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

编写PBR着色器时高光区域出现黑斑问题求助

PBR着色器问题:高光区域出现黑斑,粗糙度参数完全失效

模型本该最亮的区域出现了黑斑,熬夜调试毫无进展。

预期效果的模型

我参考了LearnOpenGL的PBR光照教程,同时对照了Nadrin的PBR HLSL代码示例。

我确认自己使用的数学运算和参考内容一致,但就是得不到预期结果。除了黑斑问题,粗糙度参数完全不影响最终效果——尽管我在多个关键位置都用到了这个参数。

以下是我使用的代码,所有输入均为世界空间坐标:

vec3 gammaCorrect(vec3 color)
{
    color = color / (color + vec3(1.0));
    return pow(color, vec3(1.0/2.2));
}

vec3 shadeDiffuse(vec3 color, vec3 position, vec3 normal)
{
    vec3 lightHue = vec3(0,0,0);
    for(uint i = 0; i < plb.numLights; ++i)
    {
        float sqrdist = distance(plb.lights[i].position, position);
        sqrdist *= sqrdist;
        float b = max(0, dot(normalize(plb.lights[i].position - position), normal) * max(0, plb.lights[i].color.a * (1 / sqrdist)));
        lightHue += plb.lights[i].color.xyz * b;
    }
    color *= lightHue;

    return gammaCorrect(color);
}

#ifndef PI
const float PI = 3.14159265359;
#endif

float DistributionGGX(vec3 normal, vec3 viewVec, float roughness)
{
    float a2   = pow(roughness, 4);
    float NdotH  = max(dot(normal, viewVec), 0.0);

    float denom = (NdotH*NdotH * (a2 - 1.0) + 1.0);
    return a2 / (PI * denom * denom);
}

float GeometrySchlickGGX(float dotp, float roughness)
{

    return dotp / (dotp * (1.0 - roughness) + roughness);
}
float GeometrySmith(vec3 normal, vec3 viewVec, vec3 lightVec, float roughness)
{
    float r = (roughness + 1.0);
    float k = (r * r) / 8.0;
    return GeometrySchlickGGX(max(dot(normal, viewVec), 0.0), k) * GeometrySchlickGGX(max(dot(normal, lightVec), 0.0), k);
}

vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}

vec3 shadePBR(vec3 albedo, vec3 position, vec3 cameraPos, vec3 normal, float roughness, float metallic)
{
    vec3 viewVec = normalize(cameraPos - position);
    const vec3 F0 = mix(vec3(0.03), albedo, metallic);

    vec3 lightHue = vec3(0);
    for(uint i = 0; i < plb.numLights; ++i)
    {
        // radiance
        vec3  lightVec    = normalize(plb.lights[i].position - position);
        vec3  halfVec     = normalize(viewVec + lightVec);
        float distance    = length(plb.lights[i].position - position);
        float attenuation = 1.0 / (distance * distance);
        vec3  radiance    = plb.lights[i].color.xyz * attenuation * max(plb.lights[i].color.a, 0);

        // brdf
        float NDF = DistributionGGX(halfVec, normal, roughness);
        float G   = GeometrySmith(normal, viewVec, lightVec, roughness);
        vec3  F   = fresnelSchlick(max(dot(halfVec, viewVec), 0.0), F0);
        vec3 kD = mix(vec3(1)-F, vec3(0), metallic);

        float viewDot  = max(dot(normal, viewVec), 0.0);
        float lightDot = max(dot(normal, lightVec), 0.0);

        vec3 specular = (NDF * G * F) / (4.0 * max(viewDot * lightDot, 0.000001));

        // add to hue
        lightHue += (kD * albedo / PI + specular) * radiance * lightDot;
    }

    //Add in ambient here later
    vec3 color = lightHue;

    return gammaCorrect(color);
}

我现在要去睡觉了,提前感谢各位的帮助。

内容的提问来源于stack exchange,提问作者WireWhiz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 23:40:36