为何空ExecuteVertexMaterial函数会改变GLSL顶点着色器输出结果?
GLSL空函数导致颜色闪烁的问题及解决
我编写了如下GLSL顶点着色器:
layout(location = 0) in vec4 a_position; layout(location = 1) in vec4 a_color; layout(location = 0) out vec4 v_color; struct VertexMaterial { vec4 color; }; void InitMaterial(out VertexMaterial material) { material.color = a_color; } void ExecuteVertexMaterial(out VertexMaterial material) { } void main() { VertexMaterial material; InitMaterial(material); { ExecuteVertexMaterial(material); v_color = material.color; } gl_Position = a_position; }
原本以为ExecuteVertexMaterial是空函数,不会修改out类型的material参数,但实际运行时出现颜色闪烁现象。
当注释掉该函数调用后,着色器恢复正常:
void main() { VertexMaterial material; InitMaterial(material); { //ExecuteVertexMaterial(material); v_color = material.color; } gl_Position = a_position; }
或者让ExecuteVertexMaterial内部调用InitMaterial,也能正常工作:
void ExecuteVertexMaterial(out VertexMaterial material) { InitMaterial(material); }
问题原因
核心是误解了GLSL中out参数的行为规则:
out类型是纯输出参数,函数调用时传入变量的原有值会被完全忽略,进入函数后参数处于未初始化状态;- GLSL要求所有
out参数必须在函数内部被完整赋值,空函数没有对material的成员赋值,导致material变成未定义的垃圾值,最终v_color读取到不确定的颜色数据,引发闪烁。
能否保留空的ExecuteVertexMaterial函数?
可以,但要修正参数类型或遵守out参数的规范:
- 推荐方案:改用
inout参数:如果希望函数可以读取并可选修改material,将参数类型改为inout,这样空函数不会改变原有变量的值:void ExecuteVertexMaterial(inout VertexMaterial material) { } - 如果坚持用
out参数:必须在函数内给material赋值,比如设置默认值或重新初始化:void ExecuteVertexMaterial(out VertexMaterial material) { // 赋值默认颜色或重新调用初始化函数 material.color = vec4(1.0); // 或者 InitMaterial(material); }
内容的提问来源于stack exchange,提问作者Shout
相关产品推荐
相关产品推荐

