テラByteの時代にキロByte

shader又はdemosceneに関係する事

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)