テラByteの時代にキロByte

shader又はdemosceneに関係する事

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)