OpenGL 统一的结构数组
Posted
技术标签:
【中文标题】OpenGL 统一的结构数组【英文标题】:OpenGL uniform array of structures 【发布时间】:2013-11-10 20:34:15 【问题描述】:所以我在片段着色器中有一个自定义结构和一个统一变量,它是这些结构的数组。它是这样定义的:
#version 130
#define MAX_LIGHTS 8
struct Light
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec4 position;
vec3 direction;
float cutoff;
float exponent;
;
uniform Light lights[MAX_LIGHTS];
现在,我正在尝试像这样获得统一的位置:
glGetUniformLocation(program, "lights[0].ambient");
glGetUniformLocation(program, "lights[0].diffuse");
// etc...
在我的 GTX460 上一切正常,但 glGetUniformLocation
在 Mobility Radeon HD 5650 上返回 -1,即使着色器编译/链接正常且一切正常。 (顺便说一句,这是一个 OpenGL 3.1 上下文。)
我做错了什么?
编辑:好的,here 是完整的着色器(不是我写的,我正在尝试修复朋友的程序)。此外,我还在英特尔高清集成显卡适配器上对此进行了测试,它也可以正常工作。
【问题讨论】:
着色器的其余部分在哪里?如果您从不引用lights[0].ambient
,那么您不应期望它具有活动统一位置。我建议你浏览一下现役制服的清单……(参见:GL_ACTIVE_UNIFORMS
和 glGetActiveUniform (...)
)。根据多年的经验,我可以告诉你 NV 和 AMD 在将基于数组的统一元素命名和限定为 active 时都有不同的行为。
您确定它正在正确编译和链接着色器吗?我猜你打电话给glGetProgramInfoLog
是为了得到任何可能发生的错误?
补充@AndonM.Coleman 所说的:一个活动的统一变量是一个在着色器中实际使用的变量,而不仅仅是声明的。编译器可以随意丢弃代码中未使用的变量。因此,即使在着色器中声明了一个uniform,只要不使用它,它的报告位置也可以是-1。从这里:lighthouse3d.com/tutorials/glsl-core-tutorial/…
是的,正如我所说,它可以在我的电脑上运行,而且灯光也在那里,所以一切都在使用。它在每个字段上返回 -1,但仅限于 lights
。
【参考方案1】:
由于人们经常盲目地摸索试图找出glGetUniformLocation (...)
返回 -1 的原因是什么,我想我会分享一些修改后的代码,用于枚举每个 GLSL 的所有制服程序。我实际上使用映射结构来对字符串名称进行类型枚举,但这会比必要的复杂。
用于打印人类可读类型的实用程序结构(最高 GLSL 430):
struct glsl_type_set
GLenum type;
const char* name;
type_set [] =
GL_INVALID_ENUM, "invalid",
GL_FLOAT, "float",
GL_FLOAT_VEC2, "vec2",
GL_FLOAT_VEC3, "vec3",
GL_FLOAT_VEC4, "vec4",
GL_DOUBLE, "double",
GL_DOUBLE_VEC2, "dvec2",
GL_DOUBLE_VEC3, "dvec3",
GL_DOUBLE_VEC4, "dvec4",
GL_INT, "int",
GL_INT_VEC2, "ivec2",
GL_INT_VEC3, "ivec3",
GL_INT_VEC4, "ivec4",
GL_UNSIGNED_INT, "unsigned int",
GL_UNSIGNED_INT_VEC2, "uvec2",
GL_UNSIGNED_INT_VEC3, "uvec3",
GL_UNSIGNED_INT_VEC4, "uvec4",
GL_BOOL, "bool",
GL_BOOL_VEC2, "bvec2",
GL_BOOL_VEC3, "bvec3",
GL_BOOL_VEC4, "bvec4",
GL_FLOAT_MAT2, "mat2",
GL_FLOAT_MAT3, "mat3",
GL_FLOAT_MAT4, "mat4",
GL_FLOAT_MAT2x3, "mat2x3",
GL_FLOAT_MAT2x4, "mat2x4",
GL_FLOAT_MAT3x2, "mat3x2",
GL_FLOAT_MAT3x4, "mat3x4",
GL_FLOAT_MAT4x2, "mat4x2",
GL_FLOAT_MAT4x3, "mat4x3",
GL_DOUBLE_MAT2, "dmat2",
GL_DOUBLE_MAT3, "dmat3",
GL_DOUBLE_MAT4, "dmat4",
GL_DOUBLE_MAT2x3, "dmat2x3",
GL_DOUBLE_MAT2x4, "dmat2x4",
GL_DOUBLE_MAT3x2, "dmat3x2",
GL_DOUBLE_MAT3x4, "dmat3x4",
GL_DOUBLE_MAT4x2, "dmat4x2",
GL_DOUBLE_MAT4x3, "dmat4x3",
GL_SAMPLER_1D, "sampler1D",
GL_SAMPLER_2D, "sampler2D",
GL_SAMPLER_3D, "sampler3D",
GL_SAMPLER_CUBE, "samplerCube",
GL_SAMPLER_1D_SHADOW, "sampler1DShadow",
GL_SAMPLER_2D_SHADOW, "sampler2DShadow",
GL_SAMPLER_1D_ARRAY, "sampler1DArray",
GL_SAMPLER_2D_ARRAY, "sampler2DArray",
GL_SAMPLER_1D_ARRAY_SHADOW, "sampler1DArrayShadow",
GL_SAMPLER_2D_ARRAY_SHADOW, "sampler2DArrayShadow",
GL_SAMPLER_2D_MULTISAMPLE, "sampler2DMS",
GL_SAMPLER_2D_MULTISAMPLE_ARRAY, "sampler2DMSArray",
GL_SAMPLER_CUBE_SHADOW, "samplerCubeShadow",
GL_SAMPLER_BUFFER, "samplerBuffer",
GL_SAMPLER_2D_RECT, "sampler2DRect",
GL_SAMPLER_2D_RECT_SHADOW, "sampler2DRectShadow",
GL_INT_SAMPLER_1D, "isampler1D",
GL_INT_SAMPLER_2D, "isampler2D",
GL_INT_SAMPLER_3D, "isampler3D",
GL_INT_SAMPLER_CUBE, "isamplerCube",
GL_INT_SAMPLER_1D_ARRAY, "isampler1DArray",
GL_INT_SAMPLER_2D_ARRAY, "isampler2DArray",
GL_INT_SAMPLER_2D_MULTISAMPLE, "isampler2DMS",
GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, "isampler2DMSArray",
GL_INT_SAMPLER_BUFFER, "isamplerBuffer",
GL_INT_SAMPLER_2D_RECT, "isampler2DRect",
GL_UNSIGNED_INT_SAMPLER_1D, "usampler1D",
GL_UNSIGNED_INT_SAMPLER_2D, "usampler2D",
GL_UNSIGNED_INT_SAMPLER_3D, "usampler3D",
GL_UNSIGNED_INT_SAMPLER_CUBE, "usamplerCube",
GL_UNSIGNED_INT_SAMPLER_1D_ARRAY, "usampler2DArray",
GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, "usampler2DArray",
GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, "usampler2DMS",
GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, "usampler2DMSArray",
GL_UNSIGNED_INT_SAMPLER_BUFFER, "usamplerBuffer",
GL_UNSIGNED_INT_SAMPLER_2D_RECT, "usampler2DRect",
GL_IMAGE_1D, "image1D",
GL_IMAGE_2D, "image2D",
GL_IMAGE_3D, "image3D",
GL_IMAGE_2D_RECT, "image2DRect",
GL_IMAGE_CUBE, "imageCube",
GL_IMAGE_BUFFER, "imageBuffer",
GL_IMAGE_1D_ARRAY, "image1DArray",
GL_IMAGE_2D_ARRAY, "image2DArray",
GL_IMAGE_2D_MULTISAMPLE, "image2DMS",
GL_IMAGE_2D_MULTISAMPLE_ARRAY, "image2DMSArray",
GL_INT_IMAGE_1D, "iimage1D",
GL_INT_IMAGE_2D, "iimage2D",
GL_INT_IMAGE_3D, "iimage3D",
GL_INT_IMAGE_2D_RECT, "iimage2DRect",
GL_INT_IMAGE_CUBE, "iimageCube",
GL_INT_IMAGE_BUFFER, "iimageBuffer",
GL_INT_IMAGE_1D_ARRAY, "iimage1DArray",
GL_INT_IMAGE_2D_ARRAY, "iimage2DArray",
GL_INT_IMAGE_2D_MULTISAMPLE, "iimage2DMS",
GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY, "iimage2DMSArray",
GL_UNSIGNED_INT_IMAGE_1D, "uimage1D",
GL_UNSIGNED_INT_IMAGE_2D, "uimage2D",
GL_UNSIGNED_INT_IMAGE_3D, "uimage3D",
GL_UNSIGNED_INT_IMAGE_2D_RECT, "uimage2DRect",
GL_UNSIGNED_INT_IMAGE_CUBE, "uimageCube",
GL_UNSIGNED_INT_IMAGE_BUFFER, "uimageBuffer",
GL_UNSIGNED_INT_IMAGE_1D_ARRAY, "uimage1DArray",
GL_UNSIGNED_INT_IMAGE_2D_ARRAY, "uimage2DArray",
GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE, "uimage2DMS",
GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY, "uimage2DMSArray",
GL_UNSIGNED_INT_ATOMIC_COUNTER, "atomic_uint"
;
枚举程序中所有ACTIVE制服的代码:
void
eTB_GLSL__print_uniforms (GLuint program)
GLint uniform_count;
glGetProgramiv (program, GL_ACTIVE_UNIFORMS, &uniform_count);
GLchar name [256];
for (GLint i = 0; i < uniform_count; i++)
memset (name, '\0', 256);
GLint size;
GLenum type;
glGetActiveUniform (program, i, 255, NULL, &size, &type, name);
GLint location = glGetUniformLocation (program, name);
for (int j = 0; j < sizeof (type_set) / sizeof (glsl_type_set); j++)
if (type_set [j].type != type)
continue;
const char* type_name = type_set [j].name;
if (size > 1)
printf ( "Uniform %d (loc=%d):\t%20s %-20s <Size: %d>\n",
i, location, type_name, name, size );
else
printf ( "Uniform %d (loc=%d):\t%20s %-20s\n",
i, location, type_name, name );
break;
if (i == (uniform_count - 1))
printf ("\n");
样本输出 (AMD):
Uniform 0 (loc=0): float buffer_res_x
Uniform 1 (loc=1): float buffer_res_y
Uniform 2 (loc=2): float buffer_scale
Uniform 3 (loc=3): mat4 camera_matrix
Uniform 4 (loc=4): bool fxaa
Uniform 5 (loc=5): vec3 light_colors <Size: 128>
Uniform 6 (loc=133): vec3 light_pos <Size: 128>
Uniform 7 (loc=261): mat4 modelview_mat
Uniform 8 (loc=262): int num_lights
Uniform 9 (loc=263): sampler2D depth_buffer
Uniform 10 (loc=264): sampler2D diffuse_buffer
Uniform 11 (loc=265): sampler2D normal_buffer
Uniform 12 (loc=266): samplerCube shadow_buffer <Size: 10>
样本输出(NV):
Uniform 0 (loc=0): float buffer_res_x
Uniform 1 (loc=1): float buffer_res_y
Uniform 2 (loc=2): float buffer_scale
Uniform 3 (loc=3): mat4 camera_matrix
Uniform 4 (loc=4): bool fxaa
Uniform 5 (loc=5): vec3 light_colors[0] <Size: 128>
Uniform 6 (loc=133): vec3 light_pos[0] <Size: 128>
Uniform 7 (loc=261): mat4 modelview_mat
Uniform 8 (loc=262): int num_lights
Uniform 9 (loc=263): sampler2D depth_buffer
Uniform 10 (loc=264): sampler2D diffuse_buffer
Uniform 11 (loc=265): sampler2D normal_buffer
Uniform 12 (loc=266): samplerCube shadow_buffer[0] <Size: 10>
我选择了这个特殊的着色器,因为它是我能找到的第一个展示 NV 和 AMD 在报告数组统一名称时有何不同的着色器,它没有什么特别之处。 NV 始终使用[0]
表示法,而 AMD 不使用(不过,较新的驱动程序倾向于使用)。您仍然可以查询单个统一位置,前提是它们在 name[0]
或name
,但在任一实现中查询name
或name[0]
的统一位置在技术上是有效的。
我很想看到三件事:
-
链接到 AMD 硬件后的输出
链接到 NV 硬件后的输出
您的完整着色器
有了这三样东西,应该可以得到一个实际的答案。
更新
我认为由于着色器的编写方式,GLSL 编译器很难确定使用情况,要确认这一点,请尝试替换:
vec3 computeLight(int light_index)
Light light = lights[light_index];
if(light.position == vec4(0.0)) return vec3(0.0);
if(light.position.w == 0.0 ) return directionLight(light);
if(light.cutoff == 0) return pointLight(light);
return reflectionLight(light);
[...]
vec3 lighting = vec3(0.);
for(int i = 0; i < lights_no; i++)
lighting += computeLight(i);
还有更难看的东西,比如:
vec3 lighting = vec3(0.0);
for(int i = 0; i < lights_no; i++)
Light light = lights [i];
if (light.position != vec4 (0.0))
if (light.position.w == 0.0)
lighting += directionLight(light);
else if (light.cutoff == 0.0)
lighting += pointLight(light);
else
lighting += reflectionLight (light);
【讨论】:
好吧,我试过了,浅色制服似乎因为某种原因消失了。这里是输出:pastebin.com/gm1ty36Mpastebin.com/eqpJ6rFU 另外,这里是完整的着色器代码,但我想指出它不是我写的,我想帮助一个朋友:pastebin.com/jnSqEKW5 @Detheroc:查看我更新的答案,我相信这是由于在函数中使用非常量表达式来索引统一数组。这在 OpenGL ES 中肯定是无效的,它不违反桌面 OpenGL 规则,但是如果 GLSL 编译器没有正确分析computeLight (...)
,我不会感到惊讶。如果是这种情况,我建议重写 computeLight (...)
以传递 Light
而不是从 lights []
数组中读取的索引。
感谢您的帮助,朋友告诉我已经通过更新驱动程序解决了问题,所以很遗憾我没有测试您的解决方案。重要的是它现在可以工作了。以上是关于OpenGL 统一的结构数组的主要内容,如果未能解决你的问题,请参考以下文章