非力なGPUで重いshaderは、ちょっと厳しい。そんな時は、movie fileを作るが良いかな。
twitterとかにも投稿できるし良いかな。
とりあえずffmpeg.exeを手に入れてパスを通してください。
変数の説明
画面サイズ(幅) : XRES = 640
画面サイズ(高さ) : YRES = 480
連番jpg fileの保存フォルダ : tempDirName = "hogehoge"
製作movie fileの名前 : movieFileName = "video.mp4"
映像描写時間(秒) : duration = 10
フレームレート : fps = 30
from OpenGL.GL import *
from OpenGL.WGL import *
from ctypes import *
from ctypes.wintypes import *
from PIL import Image
import numpy
import sys
import os
import subprocess
kernel32 = windll.kernel32
user32 = windll.user32
winmm = windll.winmm
XRES = 640
YRES = 480
tempDirName = "hogehoge"
movieFileName = "video.mp4"
duration = 10
fps = 30
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);
}
"""
# window init
WS_OVERLAPPEDWINDOW = 0xcf0000
hWnd = user32.CreateWindowExA(0,0xC018,0,WS_OVERLAPPEDWINDOW,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)
# make jpg files
pixels = (GLuint* (3 * XRES * YRES))()
if not os.path.exists(tempDirName): os.mkdir(tempDirName)
for i in range(duration * fps):
t= i/fps
filename = "{0}/img{1:05d}.jpg".format(tempDirName, i+1)
sys.stdout.write("\r make jpg file: {0} TIME : {1:.2f}".format(filename,t))
sys.stdout.flush()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glUniform1f(glGetUniformLocation(program, "time"), t)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
glReadPixels(0, 0, XRES, YRES, GL_RGB, GL_UNSIGNED_BYTE, pixels)
image = Image.frombytes(mode="RGB", size=(XRES, YRES), data=pixels)
image = image.transpose(Image.FLIP_TOP_BOTTOM)
image.save(filename)
# make mp4 file
subprocess.call("ffmpeg -f image2 -r {1:d} -i {0}/img%05d.jpg -r {1:d} -an -vcodec libx264 -pix_fmt yuv420p {2} -y".format(tempDirName,fps,movieFileName))
# GL context finish
wglMakeCurrent(0, 0)
wglDeleteContext(hGLrc)
# windoe finish
user32.ReleaseDC(hWnd, hdc)
user32.PostQuitMessage(0)
user32.DestroyWindow(hWnd)
終わりに
全部を説明すると大変なことになるので、ソースしかのせてません。
興味ある方は、fragment shaderを書き直してpythonで使ってみてください。
ffmpeg.exeを使って音楽とか入れてみても面白いと思います。