pyOpenGL

glut,sdlを使わずにpyOpenGL

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はマイナーぽいので、少しでも情報あった方がいいかな?を兼ねてです。