我正在尝试编写一个在 OpenGL 和纯 C 的计算着色器中运行的光线追踪器。我首先只想渲染球体。这些球体旨在提供给 SSBO 中的计算着色器。问题是,计算着色器只能访问球体数组的第一个元素。第二个元素仅由零组成。
我编写了一个简单的调试计算着色器,它仅将半径显示为输出纹理中交替垂直条纹中的颜色。当更改第一个球体的半径时,它会更改一半条纹的颜色,但这不适用于第二个球体。
C代码:
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include "shader.c"
#include "plane.c"
#include "texture.c"
#define TEXTURE_WIDTH 512
#define TEXTURE_HEIGHT 512
struct Sphere {
float center[3];
float radius;
float color[4];
int source;
};
int main(int argc, char** argv)
{
if (!glfwInit()) {
printf("Failed to initialize GLFW\n");
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
GLFWwindow* window = glfwCreateWindow(512, 512, "rays", NULL, NULL);
if (window == NULL) {
printf("Failed to create GLFW window\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
GLenum err = glewInit();
if (err != GLEW_OK) {
printf("Failed to initialize GLEW\n");
return -1;
}
if (!GLEW_VERSION_2_1) {
printf("GLEW version does not match 2.1\n");
return -1;
}
GLuint vertex_shader = loadShader("shaders/vertex.glsl", GL_VERTEX_SHADER);
GLuint fragment_shader = loadShader("shaders/fragment.glsl", GL_FRAGMENT_SHADER);
GLuint program = createProgram(2, vertex_shader, fragment_shader);
GLuint compute_shader = loadShader("shaders/compute.glsl", GL_COMPUTE_SHADER);
GLuint compute_program = createProgram(1, compute_shader);
GLuint plane = createPlane();
GLuint texture = createTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT);
struct Sphere spheres[] = {
{
{1, 1, 2},
0.25,
{0, 1, 0, 1},
1
},
{
{-1, 1, 2},
0.75,
{0, 0, 1, 1},
1,
}
};
GLuint ssbo;
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(struct Sphere) * 2, spheres, GL_STATIC_DRAW);
while(!glfwWindowShouldClose(window)) {
glfwSwapBuffers(window);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, ssbo);
glUseProgram(compute_program);
glUniform1i(glGetUniformLocation(compute_program, "sphere_count"), 2);
glDispatchCompute((unsigned int)TEXTURE_WIDTH / 32, (unsigned int)TEXTURE_HEIGHT / 32, 1);
glMemoryBarrier(GL_ALL_BARRIER_BITS);
glUseProgram(program);
glUniform1i(glGetUniformLocation(program, "tex"), 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(plane);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwPollEvents();
}
glfwDestroyWindow(window);
return 0;
}
计算着色器:
#version 460 core
layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
layout(rgba32f, binding = 0) uniform image2D imgOutput;
struct Sphere {
vec3 center;
float radius;
vec4 color;
int source;
};
layout(std430, binding = 2) buffer SphereBlock {
Sphere spheres[];
};
uniform int sphere_count;
void main() {
ivec2 texelCoord = ivec2(gl_GlobalInvocationID.xy);
vec4 value = vec4(spheres[0].radius);
if (texelCoord.x % 20 > 10) {
value = vec4(spheres[1].radius);
}
imageStore(imgOutput, texelCoord, value);
}
刚刚弄清楚:您必须向结构添加填充。 显然,SSBO 中数组条目的大小必须是 vec4(16 字节)的倍数。在此示例中,您只需在 c 代码中向结构体添加 3 个浮点即可:
struct Sphere {
float center[3];
float radius;
float color[4];
int source; float __padding[3];
}