假设我有两个物种,例如人类和小马。它们具有不同的骨骼系统,因此统一的骨骼数组对于每个物种都必须不同。我是否需要实现两个分别能够正确渲染每个骨骼数组的着色器程序,还是有一种方法可以动态声明统一数组并遍历该动态数组呢?
请注意性能(这里有很多着色器在决策分支方面表现不佳)。
请注意性能(这里有很多着色器在决策分支方面表现不佳)。
在OpenGL 4.3之前,GLSL中的数组必须具有固定的编译时大小。4.3允许使用着色器存储缓冲区对象,可以使它们的长度“无限制”。基本上你可以这样做:
buffer BlockName
{
mat4 manyManyMatrices[];
};
OpenGL会根据您使用的glBindBufferRange
来在运行时确定这个数组中有多少个矩阵。因此,您仍然可以使用manyManyMatrices.length()
来获取长度,但它不会是编译时常量。
然而,这个功能(截至本次编辑)非常新,并且仅在beta版中实现。它还需要GL 4.x级别的硬件(也称为Direct3D 11级别的硬件)。最后,由于它使用着色器存储块,访问数据可能比人们期望的要慢。
因此,我建议您只使用一个包含您将使用的最大矩阵数量的uniform块。如果出现内存问题(不太可能),则可以根据数组大小拆分着色器或使用着色器存储块等方法。
你可以使用n-by-1的纹理作为数组的替代品。纹理大小可以在运行时指定。我使用这种方法将任意数量的光源传递给我的着色器。尽管有许多循环和分支,但我很惊讶它运行得如此之快。示例请参见jReality源代码中jogl3.glsl.nontransp文件夹下的polygon.f着色器文件。
uniform sampler2D sys_globalLights;
uniform int sys_numGlobalDirLights;
uniform int sys_numGlobalPointLights;
uniform int sys_numGlobalSpotLights;
...
int lightTexSize = sys_numGlobalDirLights*3+sys_numGlobalPointLights*3+sys_numGlobalSpotLights*5;
for(int i = 0; i < numDir; i++){
vec4 dir = texture(sys_globalLights, vec2((3*i+1+0.5)/lightTexSize, 0));
...