使用 imageStore 从计算着色器写入后使用 glGetTexImage 读取纹理数据

Reading texture data with glGetTexImage after writing from compute shader with imageStore

我在计算着色器中为 3D 纹理生成噪声,然后在 CPU 上构建网格。当我在主循环中执行此操作时它工作正常,但我注意到我在第一次渲染时只填充了 ~1% 的噪声。这是最小的例子,我试图用着色器中的纹理填充 3D 纹理,但在 return:

中得到零或噪声
#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <stdio.h>
#include <stdlib.h>

void error(const char* message) { ... }

const char* slurp_file(const char* filename) { ... }

int main() {
  glfwInit();

  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

  GLFWwindow* window = glfwCreateWindow(100, 100, "", NULL, NULL);
  glfwMakeContextCurrent(window);
  gladLoadGL();
  
  // create texture
  GLuint texture;
  glGenTextures(1, &texture);
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_3D, texture);

  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

  // allocate it
  size_t size = 4;
  glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, size, size, size, 0, GL_RED, GL_FLOAT, NULL);

  // create shader
  const char* shader_source = slurp_file("shaders/example.comp");
  GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
  glShaderSource(shader, 1, &shader_source, NULL);
  glCompileShader(shader);

  // check it
  int code;
  glGetShaderiv(shader, GL_COMPILE_STATUS, &code);
  if (!code) error("shader compilation failed");

  // create program
  int program = glCreateProgram();
  glAttachShader(program, shader);
  glLinkProgram(program);

  // check it
  glGetProgramiv(program, GL_LINK_STATUS, &code);
  if (!code) error("program linkage failed");

  // run shader
  glUseProgram(program);
  // i don't think it's needed, as 0 would be a default value
  int uniform_loc = glGetUniformLocation(program, "img_output");
  glUniform1i(uniform_loc, 0);

  // dispatch and sync
  glDispatchCompute(size, size, size);
  // originally i had GL_TEXTURE_FETCH_BARRIER_BIT here
  glMemoryBarrier(GL_ALL_BARRIER_BITS);

  // read texture data
  float* data = malloc(size * size * size * sizeof(float));
  glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
  glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, data);

  // prints 0s or noise, but i expect all 1s
  for (int i = 0; i < size * size * size; i++)
    printf("%f ", data[i]);
}

这是着色器:

#version 430

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, r32f) writeonly uniform image3D img_output;

void main() {
  ivec3 texture_coords = ivec3(gl_GlobalInvocationID.xyz);

  vec4  pixel = vec4(1, 0, 0, 0);

  imageStore(img_output, texture_coords, pixel);
}

只是在 glDispatchCompute 之后添加 sleep 没有任何作用,所以我想我缺少一些锁定?或者纹理应该以其他方式配置?

在执行计算着色器之前,您需要将纹理绑定到图像单元。纹理对象和着色器之间的绑定是通过纹理图像单元建立的。着色器知道单位,因为你设置了单位变量或用布局限定符指定绑定点,但你还需要将对象绑定到单位:

glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
glDispatchCompute(size, size, size);