只能从计算着色器访问 SSBO 中数组的第一个元素

问题描述 投票:0回答:1

我正在尝试编写一个在 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);
}
c opengl graphics glsl compute-shader
1个回答
0
投票

刚刚弄清楚:您必须向结构添加填充。 显然,SSBO 中数组条目的大小必须是 vec4(16 字节)的倍数。在此示例中,您只需在 c 代码中向结构体添加 3 个浮点即可:

struct Sphere {
  float center[3];
  float radius;
  float color[4];
  int source; float __padding[3];
}
© www.soinside.com 2019 - 2024. All rights reserved.