假设我有2种,如人类和小马。它们具有不同的骨骼系统,因此每个物种的均匀骨骼阵列必须不同。我是否必须实现两个单独的着色器程序才能正确渲染每个骨骼数组,或者是否有办法动态声明统一数组并反复遍历该动态数组?
记住性能(所有着色器都在决策分支上徘徊)。
答案 0 :(得分:15)
在OpenGL 4.3之前,GLSL中的数组必须是固定的编译时大小。 4.3允许使用着色器存储缓冲区对象,这允许它们的最终长度“无界”。基本上,你可以这样做:
buffer BlockName
{
mat4 manyManyMatrices[];
};
OpenGL将根据您使用glBindBufferRange
的方式计算出运行时此阵列中有多少矩阵。因此,您仍然可以使用manyManyMatrices.length()
来获取长度,但它不是编译时常量。
但是,此功能(在编辑时)非常新,仅在测试版中实现。它还需要GL 4.x级硬件(又名:Direct3D 11级硬件)。最后,由于它使用着色器存储块,因此访问数据的速度可能比人们希望的要慢。
因此,我建议您只使用具有最大数量矩阵的统一块。如果这成为内存问题(不太可能),那么您可以根据数组大小拆分着色器或使用着色器存储块或其他任何内容。
答案 1 :(得分:10)
您可以使用n-by-1-Textures作为数组的替代品。可以在运行时指定纹理大小。我使用这种方法将任意数量的灯传递给我的着色器。尽管有很多循环和分支,但我很惊讶它的运行速度有多快。有关示例,请参阅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));
...