LoginSignup
2
0

More than 5 years have passed since last update.

glut,sdlを使わずにpyOpenGL

Last updated at Posted at 2017-08-24

glut,sdlを使わない

glut,sdlとかを使わないのがシンプルでいいのでdemosceneで使われているスキルをctypeを使ってのpythonに移植です。
慣れてくると、ctypeを使っているせいでソースが似ているので、pythonでもC言語でも、どっちでもよくなります。まあ、いくぶんC言語の方がFPSが速いけどコンパイル時間が長いかな。pythonは初回起動に限り長いけど、以降は快適です。


from OpenGL.GL import *
from OpenGL.WGL import *
from ctypes import *
from ctypes.wintypes import *
import numpy
import sys

kernel32 = windll.kernel32
user32 = windll.user32
winmm = windll.winmm 

XRES = 640
YRES = 480

duration = 10

vsh = """
#version 430

layout(location = 0) in vec2 p;

void main(){
    gl_Position = vec4(p, 0, 1);
}
"""

fsh = """
#version 430

out vec4 fragColor;

uniform vec2 resolution;
uniform float time;

void main() {
    vec2 p = (2.0 * gl_FragCoord.xy - resolution.xy) / resolution.y;
    p += vec2(cos(time), sin(time)) * 0.5;
    float g = exp(-1.5 * dot(p,p));
    fragColor = vec4(g, g, g, 1.0);
}
"""

# window init
WS_OVERLAPPEDWINDOW = 0xcf0000
WS_VISIBLE = 0x10000000
hWnd = user32.CreateWindowExA(0,0xC018,0,WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,XRES,YRES,0,0,0,0)
hdc = user32.GetDC(hWnd)   
user32.SetForegroundWindow(hWnd)

# GL context init
PFD_SUPPORT_OPENGL = 32
PFD_DOUBLEBUFFER = 1
pfd = PIXELFORMATDESCRIPTOR(0,1,PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,32,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0)
SetPixelFormat(hdc, ChoosePixelFormat(hdc, pfd), pfd)
hGLrc = wglCreateContext(hdc)
wglMakeCurrent(hdc, hGLrc)

# GL init
glClearColor(0, 0, 0, 1)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)

program = glCreateProgram()
for s, t in zip((vsh, fsh), (GL_VERTEX_SHADER, GL_FRAGMENT_SHADER)):    
    shader = glCreateShader(t)
    glShaderSource(shader, s)
    glCompileShader(shader)
    if glGetShaderiv(shader, GL_COMPILE_STATUS) != GL_TRUE:
        raise RuntimeError(glGetShaderInfoLog(shader).decode())
    glAttachShader(program, shader)
glLinkProgram(program)
glUseProgram(program)
glUniform2f(glGetUniformLocation(program, "resolution"), XRES, YRES)
vertices = numpy.array([-1,-1,1,-1,-1,1,1,1], numpy.float32)
glBindBuffer(GL_ARRAY_BUFFER, glGenBuffers(1))
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, (c_float*len(vertices))(*vertices), GL_STATIC_DRAW)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, None)
glEnableVertexAttribArray(0)

# GL loop
PM_REMOVE = 1
WM_NCLBUTTONDOWN = 161
HTCLOSE = 20
VK_ESCAPE = 27
msg = MSG()
lpmsg = pointer(msg)
fps, cnt, s0 = 0, 0, 0
zero = winmm.timeGetTime()
done = False
while done==False:
    while user32.PeekMessageA(lpmsg, 0, 0, 0, PM_REMOVE):
        if (msg.message == WM_NCLBUTTONDOWN and msg.wParam == HTCLOSE): done = True
        user32.DispatchMessageA(lpmsg)
    if(user32.GetAsyncKeyState(VK_ESCAPE)):  done = True
    t = (winmm.timeGetTime() - zero)*0.001

    # GL update
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glUniform1f(glGetUniformLocation(program, "time"), t)
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)

    SwapBuffers(hdc)
    cnt += 1
    if (t - s0 > 1):
        fps = cnt      
        cnt = 0
        s0 = t
    sys.stdout.write("\r FPS : {0:d} TIME : {1:.2f}".format(fps,t))
    sys.stdout.flush()
    if (t > duration):  done = True


# GL context finish
wglMakeCurrent(0, 0)
wglDeleteContext(hGLrc)

# window finish
user32.ReleaseDC(hWnd, hdc)
user32.PostQuitMessage(0)
user32.DestroyWindow(hWnd)

Fragment shaderで遊べます。

このソースのfrgment shaderだけ書き換えて遊べます。仕様に振り回されて慣れるよりshaderだけで遊ぶ方が楽しいかな。

次の一手

今回、このソースを載せたのは、ffmpeg.exeを使ってmovie fileを作るための前振りです。それにpyopenglはマイナーぽいので、少しでも情報あった方がいいかな?を兼ねてです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0