You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 12:52:52