为何无法给GLSL着色器中的in变量赋值?
问题解析
首先看你提供的片段着色器代码:
const char* fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "in vec2 TexCoord;\n" "in vec3 Normal;\n" // <------这里是你想要赋值的变量 "in vec3 Tangent;\n" "in vec3 biTangent;\n" "uniform sampler2D ourTexture;\n" "uniform sampler2D norTexture;\n" "uniform vec3 lightDir;\n" "uniform vec3 viewDir;\n" "void main()\n" "{\n" " mat3 accNormalTrans = mat3(Tangent, biTangent, Normal);\n" " Normal = texture(norTexture, TexCoord).xyz;\n"// in 变量不可随意更改 " Normal = normalize(texNormal*2.0-1.0);\n" " Normal = normalize(accNormalTrans*texNormal);\n" " vec4 ambient = texture(ourTexture, TexCoord)*0.5;\n"//norTexture error //vec4(texNormal, 1.0f) " vec4 diffuse = ambient*max(0,-dot(lightDir,Normal));\n" " vec4 specular = ambient*pow(max(0,-dot(normalize(lightDir+viewDir),Normal)),32);\n" " FragColor = ambient+diffuse+specular;\n" "}\n\0";
异常原因解析
in变量的只读属性:GLSL规范里,in修饰的输入变量是只读的,对其赋值属于未定义行为。部分编译器不会直接报错,但GPU执行时会出现不可预测的错误——比如你遇到的模型透明、跟随相机偏移,本质是GPU执行流程被破坏后输出了异常像素值。- 未定义变量的垃圾数据:代码里赋值
Normal后,后续用到了未声明的texNormal变量,这会导致GPU读取到内存中的垃圾数据,进一步加剧渲染异常。 - 逻辑混乱的空间转换:你先用原始
Normal构建了accNormalTrans矩阵,之后又覆盖Normal的值,这会让光照计算的空间转换逻辑完全错误,最终计算出的颜色分量可能被错误置0,导致模型透明。
正确的处理方式
声明局部变量存储计算后的法线,严格遵守GLSL变量修饰规则:
void main() { mat3 accNormalTrans = mat3(Tangent, biTangent, Normal); // 用局部变量存储法线贴图采样结果 vec3 texNormal = texture(norTexture, TexCoord).xyz; texNormal = normalize(texNormal * 2.0 - 1.0); vec3 finalNormal = normalize(accNormalTrans * texNormal); vec4 ambient = texture(ourTexture, TexCoord) * 0.5; vec4 diffuse = ambient * max(0.0, -dot(lightDir, finalNormal)); vec4 specular = ambient * pow(max(0.0, -dot(normalize(lightDir + viewDir), finalNormal)), 32.0); FragColor = ambient + diffuse + specular; }
内容的提问来源于stack exchange,提问作者minisparks
相关产品推荐
相关产品推荐

