SSBO経由でfragment shader
SSBOをバックバッファとして使いcompute shaderでグラフィックを作り、fragment shaderに渡して描写。
fragment shaderでSSBOからグラフィックを引っ張るのに必要なIDなのだが、
int(gl_FragCoord.x+(gl_FragCoord.y+0.5)*resolution.x)
と、謎の0.5
が登場する、意味わからんけど、これをしないと繋がらない。
とりあえず、絵がでるので使ってます。
from OpenGL.GL import * from OpenGL.WGL import * from ctypes import * from ctypes.wintypes import * import sys vsh = """ #version 430 void main() { gl_Position = vec4(ivec2(gl_VertexID & 1, gl_VertexID >> 1 & 1)*2-1, 1, 1); } """ fsh = """ #version 430 layout(std430, binding=7) buffer pic{ vec4 Col[]; }; uniform vec2 resolution; out vec4 fragColor; void main() { fragColor =Col[int(gl_FragCoord.x+(gl_FragCoord.y+0.5)*resolution.x)]; } """ csh = """ #version 430 layout(std430, binding=7) buffer pic{ vec4 Col[]; }; uniform vec2 resolution; uniform float time; uniform int frame; layout(local_size_x=64, local_size_y=1, local_size_z=1) in; void main() { vec2 fragCoord = vec2(mod(gl_GlobalInvocationID.x,resolution.x),floor(gl_GlobalInvocationID.x/resolution.x)); vec2 p = (fragCoord * 2.0 - resolution) / resolution.y; vec3 col= Col[gl_GlobalInvocationID.x].xyz*0.9; p.x += sin(time); float de = abs(length(p) - 0.3); col = vec3(mix(vec3(1,0.8,0.1),col,smoothstep(0.0,0.01,de))); Col[gl_GlobalInvocationID.x] = vec4(col,1); } """ winmm = windll.winmm kernel32 = windll.kernel32 user32 = windll.user32 XRES = 1920 // 4 YRES = 1080 // 4 WS_POPUP = 0x80000000 WS_OVERLAPPEDWINDOW = 0xcf0000 WS_VISIBLE = 0x10000000 PM_REMOVE = 1 WM_NCLBUTTONDOWN = 161 HTCLOSE = 20 VK_ESCAPE = 27 PFD_SUPPORT_OPENGL = 32 PFD_DOUBLEBUFFER = 1 #hWnd = user32.CreateWindowExA(0,0xC018,0,WS_OVERLAPPEDWINDOW|WS_VISIBLE,30,30,XRES,YRES,0,0,0,0) hWnd = user32.CreateWindowExA(0,0xC018,0,WS_POPUP|WS_VISIBLE,100,100,XRES,YRES,0,0,0,0) hdc = user32.GetDC(hWnd) user32.SetForegroundWindow(hWnd) 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) glClearColor(0, 0, 0, 1) glEnable(GL_CULL_FACE) glCullFace(GL_BACK) glEnable(GL_DEPTH_TEST) glDepthFunc(GL_LEQUAL) global program 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) computeProg = glCreateProgram() shader = glCreateShader(GL_COMPUTE_SHADER) glShaderSource(shader, csh) glCompileShader(shader) if glGetShaderiv(shader, GL_COMPILE_STATUS) != GL_TRUE: raise RuntimeError(glGetShaderInfoLog(shader).decode()) glAttachShader(computeProg, shader) glLinkProgram(computeProg) glUseProgram(computeProg) glUniform2f(glGetUniformLocation(computeProg, "resolution"), XRES , YRES) ssbo = glGenBuffers(1) glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo) glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * 4 * XRES * YRES, None, GL_STATIC_DRAW) glUseProgram(program); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, ssbo) glUseProgram(computeProg) glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, ssbo) duration = 60 msg = MSG() lpmsg = pointer(msg) zero = winmm.timeGetTime() done = False fps, cnt, s0 = 0, 0, 0 frame = 0 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 glUseProgram(computeProg); glUniform1f(glGetUniformLocation(computeProg, "time"), t) glUniform1i(glGetUniformLocation(computeProg, "frame"), frame) glDispatchCompute(XRES*YRES//64, 1, 1) glUseProgram(program); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) SwapBuffers(hdc) frame += 1 cnt += 1 if (t - s0 > 1): fps = cnt cnt = 0 s0 = t sys.stdout.write("\r FPS : %d TIME : %f" %(fps,t)) sys.stdout.flush() if (t > duration): done = True wglMakeCurrent(0, 0) wglDeleteContext(hGLrc) user32.ReleaseDC(hWnd, hdc) user32.PostQuitMessage(0) user32.DestroyWindow(hWnd)