OpenGL 添加specular lighting后Mesh变黑问题的修复方案求助
问题原因
从你提供的着色器代码里能找到多个导致镜面光失效、模型变黑的错误:
- 顶点着色器未给
toLightVector和normal两个输出变量赋值,导致片元着色器拿到的是未定义的垃圾值,所有基于光照方向、法向量的计算结果全部错误 - 片元着色器直接使用了未定义的
unitToLightVector、unitNormal、diffuse变量,计算逻辑完全不成立 - 镜面因子截断行逻辑错误:你写的
specular_factor = max(specular, 0.0)错误使用了uniform高光系数specular作为参数,而非点积得到的specular_factor,如果你的高光系数默认值为0或者数值较大,会直接导致镜面项结果为0或者超出颜色取值范围,出现纯黑 - 最终颜色计算时alpha通道叠加为2,如果开启了alpha混合会出现显示异常
修复方案
修正顶点着色器
#version 330 core layout (location = 0) in vec3 pos; layout (location = 1) in vec2 coords; layout (location = 2) in vec3 normals; out vec2 Texture_Coords; out vec3 normal; out vec3 toLightVector; out vec3 toCameraVector; uniform mat4 p; uniform mat4 m; uniform mat4 v; uniform vec3 light_position; void main(){ vec4 world_position = m * vec4(pos,1.0); gl_Position = p * v * world_position; Texture_Coords = coords; // 补充法向量、光照方向向量的传递,逆转置矩阵避免非均匀缩放导致法向量偏移 normal = mat3(transpose(inverse(m))) * normals; toLightVector = light_position - world_position.xyz; toCameraVector = (inverse(v) * vec4(0,0,0,1)).xyz - world_position.xyz; }
修正片元着色器
#version 330 core out vec4 Pixel; in vec2 Texture_Coords; in vec3 normal; in vec3 toLightVector; in vec3 toCameraVector; uniform vec4 color; uniform sampler2D Texture; uniform float ambient; uniform vec3 light_color; uniform float reflective; uniform float specular; // 建议改名为shininess避免变量名歧义 void main(){ // 补齐所有单位向量定义 vec3 unitNormal = normalize(normal); vec3 unitToLightVector = normalize(toLightVector); vec3 unitToCameraVector = normalize(toCameraVector); // 补齐漫反射计算逻辑 float diffuse_factor = max(dot(unitNormal, unitToLightVector), 0.0); vec3 diffuse = ambient * light_color + diffuse_factor * light_color; vec3 light_direction = -unitToLightVector; vec3 reflection = reflect(light_direction, unitNormal); float specular_factor = dot(reflection, unitToCameraVector); // 修正max函数参数为计算得到的镜面因子 specular_factor = max(specular_factor, 0.0); float damped_specular = pow(specular_factor, specular); vec3 final_specular = damped_specular * light_color * reflective; // 修正alpha通道计算,避免叠加后超出取值范围 vec4 tex_color = texture(Texture, Texture_Coords); Pixel = vec4(diffuse * tex_color.rgb + final_specular, tex_color.a); }
额外校验点
- CPU端传值时确认
specular(高光幂次)取值在2~256的合理区间,不要传0或者过大的数值 - 确认
reflective(高光强度)数值大于0,常规取值在0~1之间 - 如果模型没有非均匀缩放,可简化法向量计算逻辑提升性能,直接用
mat3(m) * normals传递法向量即可
内容的提问来源于stack exchange,提问作者Extorc Productions
相关产品推荐
相关产品推荐

