LWJGL 3中Phong着色的镜面光照失效问题
自研引擎光照异常:物体无法正常发光、镜面光照完全失效
我在自研引擎中实现了光照效果,但物体无法正常发光,镜面光照完全失效。将float diffuseFactor = max(dot(normal, to_light_dir ), 0.0);和float specularFactor = max(dot(camera_direction, reflected_light), 0.0);中的0.0改为0.1等大于0的值后,效果有所变化,但镜面光照仍完全失效。
顶点着色器代码
#version 330 layout (location = 0) in vec3 position; layout (location = 1) in vec2 tex_coords; layout (location = 2) in vec3 normals; uniform mat4 projectionMatrix; uniform mat4 worldMatrix; uniform mat4 viewMatrix; out vec2 coords; out vec3 vertexNormals; out vec3 vertexPos; void main() { vec4 mVerPos = worldMatrix * vec4(position, 1.0); gl_Position = projectionMatrix * viewMatrix * worldMatrix * vec4(position, 1.0); coords = tex_coords; vertexNormals = normalize(worldMatrix * vec4(normals, 0.0)).xyz; vertexPos = mVerPos.xyz; }
片段着色器代码
#version 330 struct Material { vec4 ambient; vec4 diffuse; vec4 specular; int hasTexture; float reflectance; }; struct PointLight { vec3 color; vec3 position; float intensity; float constant; float linear; float exponent; }; struct DirLight { vec3 position; vec3 color; float intensity; }; out vec4 fragColor; in vec2 coords; in vec3 vertexNormals; in vec3 vertexPos; uniform sampler2D sampler; uniform vec3 ambientColor; uniform Material material; uniform PointLight pointLight; uniform float specularPower; uniform DirLight dirLight; vec4 ambientC; vec4 diffuseC; vec4 specularC; void setUpColor(Material material, vec2 coords) { if (material.hasTexture == 1) { ambientC = texture(sampler, coords); diffuseC = ambientC; specularC = ambientC; } else { ambientC = material.ambient; diffuseC = material.diffuse; specularC = material.specular; } } vec4 calcLightColor(vec3 lightColor, float lightIntensity, vec3 position, vec3 to_light_dir, vec3 normal) { vec4 diffuseColour = vec4(0, 0, 0, 0); vec4 specColour = vec4(0, 0, 0, 0); // Diffuse Light float diffuseFactor = max(dot(normal, to_light_dir ), 0.0); diffuseColour = diffuseC * vec4(lightColor, 1.0) * lightIntensity * diffuseFactor; // Specular Light vec3 camera_direction = normalize(-position); vec3 from_light_dir = -to_light_dir; vec3 reflected_light = normalize(reflect(from_light_dir, normal)); float specularFactor = max(dot(camera_direction, reflected_light), 0.0); specularFactor = pow(specularFactor, specularPower); specColour = specularC * lightIntensity * specularFactor * material.reflectance * vec4(lightColor, 1.0); return (diffuseColour + specColour); }; vec4 calcPointLight(PointLight light, vec3 position, vec3 normal) { vec3 light_direction = light.position - position; vec3 to_light_source = normalize(light_direction); vec4 lightColor = calcLightColor(light.color, light.intensity, position, to_light_source, normal); // Attenuation float distance = length(light_direction); float attenuationInv = light.constant + light.linear * distance + light.exponent * distance * distance; return lightColor / attenuationInv; } vec4 calcDirLight(DirLight light, vec3 position, vec3 normal) { return calcLightColor(light.color, light.intensity, position, normalize(light.position), normal); } void main() { setUpColor(material, coords); vec4 diffuseSpecularComp = calcDirLight(dirLight, vertexPos, vertexNormals); diffuseSpecularComp += calcPointLight(pointLight, vertexPos, vertexNormals); fragColor = ambientC * vec4(ambientColor, 1) + diffuseSpecularComp; }
问题排查与修复方案
- 修正法线变换逻辑:
直接用worldMatrix变换法线会在非均匀缩放时出错,必须使用法线矩阵(世界矩阵的逆转置):// 顶点着色器中替换法线变换代码 vertexNormals = normalize(mat3(inverse(transpose(worldMatrix))) * normals); - 修复相机方向计算:
当前相机方向计算错误,需要传入相机的世界空间位置,计算从顶点指向相机的方向:// 片段着色器中添加相机位置uniform uniform vec3 cameraWorldPos; // 在calcLightColor函数中修改相机方向计算 vec3 camera_direction = normalize(cameraWorldPos - position); - 检查镜面光参数配置:
- 确认
material.specular不是黑色(比如设置为vec4(1.0,1.0,1.0,1.0)) material.reflectance值应大于0(比如0.5~1.0)specularPower建议设置为32、64或更高,过小会导致高光过于分散
- 确认
- 修正方向光方向:
DirLight的position字段被误用为方向,正确的方向光方向应该是从顶点指向光源的反方向,修改calcDirLight函数:vec4 calcDirLight(DirLight light, vec3 position, vec3 normal) { // 假设light.position是光源方向,取反得到指向光源的方向 vec3 to_light_dir = normalize(-light.position); return calcLightColor(light.color, light.intensity, position, to_light_dir, normal); } - 优化纹理镜面光处理:
使用纹理时,不要直接用漫反射纹理作为镜面纹理,建议单独设置镜面纹理或使用材质的镜面颜色:// 修改setUpColor函数中的镜面颜色赋值 if (material.hasTexture == 1) { ambientC = texture(sampler, coords); diffuseC = ambientC; specularC = material.specular; // 使用材质镜面颜色而非纹理 }
内容的提问来源于stack exchange,提问作者Ajinkya Sanas
相关产品推荐
相关产品推荐

