fragmentでノイズのtextureを使わずにSSBOやってみる
3D_textureノイズを作るのをSSBOやってみる事にした。作り始めて気が付いたが、1次元の大量の配列のノイズは、簡単に2次元、3次元、4次元に加工できる。
その時の用途によりけりfragment shaderで加工してもいいかな?
リアルタイムでノイズを生成するよりtextureの方がFPS的に有利だけど、textureは持ちたくないので、今回の手法もいいのかと思います。
ノイズ生成にfract(sin())
を使ったけど、変な特性が出ちゃったので、Integer Hash使いました。xorshiftより短い記述で済みます。
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 Noise{ float Hash[]; }; uniform float time; uniform vec2 resolution; uniform int data_size; out vec4 fragColor; void main() { int id = int(gl_FragCoord.x+gl_FragCoord.y*resolution.x); id += int(resolution.x*resolution.y*time*10); id %= data_size; fragColor = vec4(Hash[id]); } """ csh = """ #version 430 layout(std430, binding=7) buffer Noise{ float Hash[]; }; layout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in; float hash( uint n ) { // https://www.shadertoy.com/view/llGSzw n = (n << 13U) ^ n; n = n * (n * n * 15731U + 789221U) + 1376312589U; return float( n & uvec3(0x7fffffffU))/float(0x7fffffff); } void main(){ uint id = gl_GlobalInvocationID.x; Hash[id] = hash(id); } """ 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) data_size = 256*256*256 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) glUniform1i(glGetUniformLocation(program, "data_size"), data_size) 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) ssbo = glGenBuffers(1) glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo) glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * data_size, None, GL_STATIC_DRAW) glUseProgram(program); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, ssbo) glUseProgram(computeProg) glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, ssbo) glUseProgram(computeProg); glDispatchCompute(data_size//128, 1, 1) duration = 60 msg = MSG() lpmsg = pointer(msg) zero = winmm.timeGetTime() done = False fps, cnt, s0 = 0, 0, 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 time = (winmm.timeGetTime() - zero)*0.001 glUseProgram(program); glUniform1f(glGetUniformLocation(program, "time"), time) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) SwapBuffers(hdc) cnt += 1 if (time - s0 > 1): fps = cnt cnt = 0 s0 = time sys.stdout.write("\r FPS : %d TIME : %f" %(fps,time)) sys.stdout.flush() if (time > duration): done = True wglMakeCurrent(0, 0) wglDeleteContext(hGLrc) user32.ReleaseDC(hWnd, hdc) user32.PostQuitMessage(0) user32.DestroyWindow(hWnd)