OpenGL + SDL2 + Compute Shader = 黑屏
OpenGL + SDL2 + Compute Shader = black screen
我正在将 C raytracer 转换为 glsl,以便我可以在计算着色器中使用它。现在我只是想在屏幕上渲染一些模糊的图案。没有编译错误,但是没有渲染。
我正在学习这两个教程(后者相当不完整并且遗漏了一些部分,我可能在那里遗漏了一些东西)
SDL2 with OpenGL - Lee Zhi Eng
Compute Shaders - Anton's OpenGL4 Tutorials
我不是opengl专家,所以我不确定着色器是否输出到纹理?或者纹理没有绘制?还是其他地方的问题?
请 post 准确的语法,而不是像 "you need to do x by initializing y and flushing z" 这样的模糊指令,因为我可能不知道执行 xyz 的语法。
请注意:主程序仍然是 C 语言,而不是 C++。
编译:-std=gnu18 -ffast-math -O3 -lm -lGLEW -lGL -lglut -Wall -pedantic -Werror -Wshadow -Wstrict-aliasing -Wstrict-overflow
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <SDL2/SDL.h>
int main(void)
{
int tex_w = 1920;
int tex_h = 1080;
//////////////////////
//
// SDL Stuff
if (SDL_Init(SDL_INIT_VIDEO) < 0){
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
SDL_Window * window;
window = SDL_CreateWindow(
"Rendering first frame",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
tex_w*scale,
tex_h*scale,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
);
if (window == NULL){
printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
#ifdef FULLSCREEN
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
#endif
SDL_Event event;
//////////////////////
//
// GL Stuff
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GLContext glContext = SDL_GL_CreateContext(window);
if (glContext == NULL){
printf("OpenGL context could not be created! SDL Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
glewInit();
GLuint tex_output;
glGenTextures(1, &tex_output);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_output);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_w, tex_h, 0, GL_RGBA, GL_FLOAT, NULL);
glBindImageTexture(0, tex_output, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
//////////////////////
//
// init compute shader
const GLchar *the_ray_shader_string = "#ifdef GL_ES\
precision mediump float;\
#endif\
\
#extension GL_OES_standard_derivatives : enable\
\
uniform float time;\
uniform vec2 mouse;\
uniform vec2 resolution;\
layout(local_size_x = 1, local_size_y = 1) in;\
layout(rgba32f, binding = 0) uniform image2D img_output;\
\
void main( void ) {\
\
vec2 position = ( gl_FragCoord.xy / resolution.xy ) + mouse / 4.0;\
\
float color = 0.0;\
color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );\
color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );\
color += sin( position.x * sin( time / 5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );\
color *= sin( time / 10.0 ) * 0.5;\
\
gl_FragColor = vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );\
\
}[=10=]";
GLuint ray_shader = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(ray_shader, 1, &the_ray_shader_string, NULL);
glCompileShader(ray_shader);
GLuint ray_program = glCreateProgram();
glAttachShader(ray_program, ray_shader);
glLinkProgram(ray_program);
int delta, leftToWait;
int startTime, i = 0;
while (++i && demoRunning)
{
startTime = SDL_GetTicks();
SDL_PollEvent(&event);
demoHandleInput(&event);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_output);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(ray_program);
glDispatchCompute((GLuint)tex_w, (GLuint)tex_h, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
SDL_GL_SwapWindow(window);
delta = SDL_GetTicks() - startTime;
leftToWait = (16 - delta); // aim for 60 fps
if (leftToWait > 0){
SDL_Delay(leftToWait);
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCES;
}
你所说的计算着色器实际上更像是一个Fragment Shader than a Compute Shader。 gl_FragCoord
是片段着色器的内置输入,gl_FragColor
是(已弃用的)片段着色器输出变量。附加到 GL_COMPUTE_SHADER
着色器对象,此着色器将无法编译。
您必须使用 gl_GlobalInvocationID
to identify the invocation and you've to use imageStore
将纹素写入输出图像 (img_output
)。例如:
#version 460
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D img_output;
void main( void ) {
vec2 position = vec2(gl_GlobalInvocationID.xy) / resolution.xy + mouse / 4.0;
float color = 0.0;
color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );
color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );
color += sin( position.x * sin( time / 5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );
color *= sin( time / 10.0 ) * 0.5;
vec4 pixel = vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );
imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), pixel);
}
但请注意,这不会向 window(默认帧缓冲区)绘制任何内容,计算机着色器的目标是图像。计算着色器只是设置图像中的像素。
如果你想 "see" 显示器上的图像,那么你必须渲染一个带有纹理对象的四边形,或者将纹理附加到帧缓冲区并将其 "blit" (glBlitFramebuffer
) 到默认帧缓冲区。
我正在将 C raytracer 转换为 glsl,以便我可以在计算着色器中使用它。现在我只是想在屏幕上渲染一些模糊的图案。没有编译错误,但是没有渲染。
我正在学习这两个教程(后者相当不完整并且遗漏了一些部分,我可能在那里遗漏了一些东西) SDL2 with OpenGL - Lee Zhi Eng Compute Shaders - Anton's OpenGL4 Tutorials
我不是opengl专家,所以我不确定着色器是否输出到纹理?或者纹理没有绘制?还是其他地方的问题?
请 post 准确的语法,而不是像 "you need to do x by initializing y and flushing z" 这样的模糊指令,因为我可能不知道执行 xyz 的语法。
请注意:主程序仍然是 C 语言,而不是 C++。
编译:-std=gnu18 -ffast-math -O3 -lm -lGLEW -lGL -lglut -Wall -pedantic -Werror -Wshadow -Wstrict-aliasing -Wstrict-overflow
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <SDL2/SDL.h>
int main(void)
{
int tex_w = 1920;
int tex_h = 1080;
//////////////////////
//
// SDL Stuff
if (SDL_Init(SDL_INIT_VIDEO) < 0){
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
SDL_Window * window;
window = SDL_CreateWindow(
"Rendering first frame",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
tex_w*scale,
tex_h*scale,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
);
if (window == NULL){
printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
#ifdef FULLSCREEN
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
#endif
SDL_Event event;
//////////////////////
//
// GL Stuff
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GLContext glContext = SDL_GL_CreateContext(window);
if (glContext == NULL){
printf("OpenGL context could not be created! SDL Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
glewInit();
GLuint tex_output;
glGenTextures(1, &tex_output);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_output);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_w, tex_h, 0, GL_RGBA, GL_FLOAT, NULL);
glBindImageTexture(0, tex_output, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
//////////////////////
//
// init compute shader
const GLchar *the_ray_shader_string = "#ifdef GL_ES\
precision mediump float;\
#endif\
\
#extension GL_OES_standard_derivatives : enable\
\
uniform float time;\
uniform vec2 mouse;\
uniform vec2 resolution;\
layout(local_size_x = 1, local_size_y = 1) in;\
layout(rgba32f, binding = 0) uniform image2D img_output;\
\
void main( void ) {\
\
vec2 position = ( gl_FragCoord.xy / resolution.xy ) + mouse / 4.0;\
\
float color = 0.0;\
color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );\
color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );\
color += sin( position.x * sin( time / 5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );\
color *= sin( time / 10.0 ) * 0.5;\
\
gl_FragColor = vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );\
\
}[=10=]";
GLuint ray_shader = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(ray_shader, 1, &the_ray_shader_string, NULL);
glCompileShader(ray_shader);
GLuint ray_program = glCreateProgram();
glAttachShader(ray_program, ray_shader);
glLinkProgram(ray_program);
int delta, leftToWait;
int startTime, i = 0;
while (++i && demoRunning)
{
startTime = SDL_GetTicks();
SDL_PollEvent(&event);
demoHandleInput(&event);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_output);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(ray_program);
glDispatchCompute((GLuint)tex_w, (GLuint)tex_h, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
SDL_GL_SwapWindow(window);
delta = SDL_GetTicks() - startTime;
leftToWait = (16 - delta); // aim for 60 fps
if (leftToWait > 0){
SDL_Delay(leftToWait);
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCES;
}
你所说的计算着色器实际上更像是一个Fragment Shader than a Compute Shader。 gl_FragCoord
是片段着色器的内置输入,gl_FragColor
是(已弃用的)片段着色器输出变量。附加到 GL_COMPUTE_SHADER
着色器对象,此着色器将无法编译。
您必须使用 gl_GlobalInvocationID
to identify the invocation and you've to use imageStore
将纹素写入输出图像 (img_output
)。例如:
#version 460
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D img_output;
void main( void ) {
vec2 position = vec2(gl_GlobalInvocationID.xy) / resolution.xy + mouse / 4.0;
float color = 0.0;
color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );
color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );
color += sin( position.x * sin( time / 5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );
color *= sin( time / 10.0 ) * 0.5;
vec4 pixel = vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );
imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), pixel);
}
但请注意,这不会向 window(默认帧缓冲区)绘制任何内容,计算机着色器的目标是图像。计算着色器只是设置图像中的像素。
如果你想 "see" 显示器上的图像,那么你必须渲染一个带有纹理对象的四边形,或者将纹理附加到帧缓冲区并将其 "blit" (glBlitFramebuffer
) 到默认帧缓冲区。