Dark spot where light should be when attempting to code pbr shader

228 views Asked by At

I keep having this bug where there's a black spot right where I would assume the model is supposed to be brightest. I pulled an all-nighter trying to get this to work, but no avail. thing that should look good

I've been following this tutuorial https://learnopengl.com/PBR/Lighting, and referencing this code as well https://github.com/Nadrin/PBR/blob/master/data/shaders/hlsl/pbr.hlsl

As far as I can tell, the math operations I'm doing are identical but they don't produce the intended results. Along with the dark spots, roughness seems to not effect the end result whatsoever, even though I use it in several places that effect the end result.

Here's the code I'm using, all inputs are in world chordinates:


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);
}

I'm going to go sleep now, thanks for any help in advance.

1

There are 1 answers

0
WireWhiz On

So turns out I'm very stupid. Problem was that I was trying to grab the camera position from the render matrix, and as I have found out, you can't really grab a clean position from that without fully disassembling it, instead of just grabbing a few indexes from it. Passed camera position with a uniform instead and code immediately worked perfectly.