GLSL着色器中是否可以有动态数组?例如,如果我的GLSL Shader中有这样的内容:

uniform int size;
uniform SceneLights lights[size];

void main()
{
    for(int i = 0; i < size; i++) {
        /* Do Some Calculation */
    }
}


这将是我的C ++文件:

for (GLuint i = 0; i < pointLights.size(); i++) {
    glUniform3f(glGetUniformLocation(shader, ("pointLights[" + std::to_string(i) + "].position").c_str()), lights[i].someValue);
}


我想这样做是因为我有一个文件,其中包含场景中所有光源的位置(每个场景可能有所不同),所以我想有一个动态数组,该数组可以让我将不同数量的灯光发送到我的着色器。

评论

还有一些着色器存储缓冲区对象,您可以在这里阅读:khronos.org/opengl/wiki/Shader_Storage_Buffer_Object在vulkan中,像这样在GLSL中声明了“无界数组”:layout(binding = 10)Uniform sampler2D TextureUBA [ ];”(sampler2D只是一个示例),我不确定在OpenGL中如何设置。最后一个版本有很大的限制,但两者的性能都会因访问内存的方式而有所不同。 br />

#1 楼

我认为统一数组不能动态调整大小。在您的情况下,应将数组定义为将要处理的最大灯光数量,然后使用统一的控件来控制对该数组进行的迭代次数。在CPU端,您可以根据'size'变量设置lights []数组的子集。

例如

#define MAX_LIGHTS 128

uniform int size;
uniform SceneLights lights[MAX_LIGHTS];

void main()
{
    for(int i = 0; i < size; i++) {
        /* Do Some Calculation */
    }
}


I认为(推测)可能的原因是,如果您的制服列表中有可变大小的数组(取决于另一个制服的值),则无法确定制服的位置。.例如

uniform int arraySize;               // offset 0
uniform int myArray[arraySize];      // offset 4
uniform int anotherVar;              // offset ???? 


GLSL不知道要放置anotherVar,因为在计算“ anotherVar”的偏移量之前,需要将arraySize设置为一个值。我想编译器可能很聪明,可以重新排列制服的顺序来解决此问题,但是如果您有2个或更多可变大小的数组,这将再次失败。.

#2 楼

您可以在上载着色器代码时将变量添加为代码。
char header[64];
sprintf (header, "const int size = %u;\n", pointLights.size());

然后添加标头(假设您的代码在char code[]中):
GLchar  *source[2] = {(GLchar  *)header, (GLchar  *)code};
glShaderSource(shader, 2, (const GLchar **)source, NULL);
..

这样,您可以改变大小并快速将其添加到着色器。
有点麻烦,但这是我做到的方式。