首页 > 解决方案 > GLSL 错误:计算着色器中未定义的布局缓冲区变量,尽管它已定义

问题描述

我正在尝试使用着色器存储缓冲区(SSBO)制作一个简单的计算着色器,以将数据传递给着色器。我正在用 GLFW3 和 GLEW 用 C++ 编写代码。我将整数数组传递给 SSBO,将其绑定到索引 0,并期望从layout buffer变量中检索着色器中的数据(如各个网站上所述)。但是,我在着色器编译时遇到了关于此布局缓冲区变量的意外“未定义变量”错误,尽管它已明确声明。这是计算着色器的 GLSL 代码(这个脚本只是在它的开头):

#version 430

layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

layout (std430, binding = 0) buffer params
{
    ivec3 dims;
};


int index(ivec3 coords){
    ivec3 dims = params.dims;
    return coords.x + dims.y * coords.y + dims.x * dims.y * coords.z;
}

void main() {
    ivec3 coords = ivec3(gl_GlobalInvocationID);

    int i = index(coords);
}

我得到错误:0(12) : error C1503: undefined variable "params"

这是设置和运行计算着色器的 C++ 脚本:

int dimensions[] {width, height, depth};

GLuint paramSSBO;
glGenBuffers(1, &paramSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, paramSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(dimensions), &dimensions, GL_STREAM_READ);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, paramSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

GLuint computeShaderID;
GLuint csProgramID;

char* computeSource;

loadShaderSource(computeSource, "compute.glsl");
computeShaderID = glCreateShader(GL_COMPUTE_SHADER);
compileShader(computeShaderID, computeSource);

delete[] computeSource;

csProgramID = glCreateProgram();
glAttachShader(csProgramID, computeShaderID);
glLinkProgram(csProgramID);
glDeleteShader(computeShaderID);

glUseProgram(csProgramID);
glDispatchCompute(width, height, depth);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
glUseProgram(0);

glDeleteBuffers(1, &paramSSBO);

width,height并且depthint在程序前面定义的变量。我将dimensions数组绑定到索引 0,我希望ivec3 params.dims在着色器的变量中检索它。然而,当在函数params中使用时,该变量被称为未定义。index()

这个脚本只是开始,我想添加第二个缓冲区,着色器将实际写入其结果,但我被困在这里。澄清一下:在完整的脚本中,我不希望写入任何纹理(如所有在线示例所示),而是将结果写入第二个缓冲区,我将从该缓冲区中将数据返回到 C++ 数组中以供进一步使用。

标签: c++glslglfwcompute-shader

解决方案


params不是变量。它也不是结构或类。它是接口块的名称。接口块的名称实际上并不是 GLSL 本身的一部分。它是OpenGL的一部分。它是 OpenGL API 用来表示特定块的名称。

除了定义它之外,您永远不会在着色器文本本身中使用接口块的名称。

除非你给你的接口块一个实例名称,否则该块中所有变量的名称本质上都是全局命名空间的一部分。确实,确定这些名称的范围是为块提供实例名称的全部意义。

所以访问dimsinterfae块中的字段的正确方法是“ dims”。


推荐阅读