从GLSL着色器中获取常量

6

我有一个用GLSL编写的着色器,其中包含一个结构体数组来存储光照数据。我使用常量来声明数组大小,这是一个好习惯。假设变量声明如下:

const int NUM_POINT_LIGHTS = 100;

我该如何使用C++从着色器中提取这些数据,以便我的C++程序准确地知道它可用的灯光数量?我已经尝试将其声明为

const uniform int NUM_POINT_LIGHTS = 100;

正如预期的那样,这并没有起作用(尽管奇怪的是,似乎统一规范简单地覆盖了const规范,因为OpenGL抱怨我正在使用非const值初始化数组)。我还尝试过

const int NUM_POINT_LIGHTS = 100;
uniform numPointLights = NUM_POINT_LIGHTS;

这种方法是可行的,但是由于GLSL会优化掉未使用的uniform变量,所以我必须让GLSL误认为这个uniform变量被使用了,才能获取到数据。我没有找到其他查询程序以获取常量值的方法。有没有人有什么想法可以从着色器中提取常量,使我的程序能够获取编码在着色器中的信息并加以使用?


1
一般来说,以这种方式编写的常量字面值在着色器编译后会变成统一变量。在NV GLSL实现中,这可能被称为 _main_NUM_POINT_LIGHTS。我建议您枚举程序中的所有统一变量,以查看是否发生了这种情况。不过,我真的不确定您最终想要实现什么...如果您想要一个数据数组,最好使用UBO,因为它不受统一变量的相同限制(例如最大统一变量组件数)的约束。 - Andon M. Coleman
我曾经认为UBO的组件计入了最大统一组件数,但通过添加一个元素数量超过2048个统一组件的数组来确认它们并没有计入其中。我实际上正在使用UBO,但即使使用UBO,让C++程序动态确定其可用的灯光数量也是很好的。我会查看并确定创建了哪些统一变量,尽管这听起来可能不适用于其他硬件的解决方案。 - Darinth
没有这样的运气,我的常数没有制服。 - Darinth
2个回答

9

我不认为您可以直接获取常量的值。但是,我想您必须使用常量的值,最有可能作为统一数组的大小。如果是这种情况,您可以获取统一数组的大小,从而间接地获取常量的值。

假设您的着色器包含以下内容:

const int NUM_POINT_LIGHTS = 100;
uniform vec3 LightPositions[NUM_POINT_LIGHTS];

那么,您可以先获取此统一的索引:

const GLchar* uniformName = "LightPositions";
GLuint uniformIdx = 0;
glGetUniformIndices(program, 1, &uniformName, &uniformIdx);

使用此索引,您可以检索此制服的属性:
const int nameLen = strlen("LightPositions") + 1;
const GLchar name[nameLen];
GLint uniformSize = 0;
GLenum uniformType = GL_NONE;
glGetActiveUniform(program, uniformIdx, nameLen, NULL,
                   &uniformSize, &uniformType, name);

uniformSize 应该是 NUM_POINT_LIGHTS 常量的值。请注意,我没有尝试过这个方法,但是根据文档,我希望我理解的是正确的。

另一种有点丑陋但可能非常实用的解决方案是从着色器源代码中解析出该值。由于您需要在将其传递给 glShaderSource() 之前先读取它,因此挑选常量值应该很容易。

如果您的主要目标是避免在多个位置定义常量,则另一个选项是在 C++ 代码中定义它,并在读取着色器代码后动态将常量定义添加到着色器代码中,然后将其传递给 glShaderSource()


2
将“#define NUM_POINT_LIGHTS”动态注入着色器源代码中,加1。 - jozxyqk
很遗憾,您无法在结构体数组上使用glGetUniformIndices,因为每个单独的元素都有自己的索引,而不是数组有一个索引。然而,从源代码中解析该值或动态添加到源代码中都可以作为使此函数非常好的方法。动态添加可能是我最好的选择,因为它允许使用变量编写多个着色器,并始终与程序功能保持同步。 - Darinth

0

很遗憾,UBO成员不能有初始化器。 :( - Darinth
我认为你试图让一切都变得动态化,有些过度了。你完全可以采用厂商相关的解决方案,甚至在读取着色器源代码时查看它本身,但如果直接在C++中定义一个常量,你会失去什么呢?任何解决办法都将非常复杂。 - BlamKiwi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接