Próbuję wdrożyć Microfacet BRDF, ale moje obrazy wyników są nieprawidłowe

9

Usiłuję wdrożyć model BRDF mikrofacet. Czytam slajdy Sebastiena Lagarde . Wdrożyłem formuły do ​​mojego kodu, ale myślę, że obraz wyniku jest nieprawidłowy.

Żółty to podstawowy kolor materiału. Kolor zwierciadlany jest czerwony, aby prawidłowo widzieć.

Mój kod:

// Fragment Shader
#version 330 core

in vec3 Position;
in vec2 TexCoord0;
in vec3 Normal;
in vec3 Tangent;
out vec4 FinalColor;

uniform vec3 uCameraPosition; // init value: vec3(0, 0, 5)

#define PI 3.1415926f
#define EPSILON 10e-5f
#define saturate(value) clamp(value, 0.0f, 1.0f);

float BRDF_Lambert(float NdotL)
{
    return NdotL;
}

// Got these BRDF formulas Moving Frostbite to PBR slide by Sebastien Lagarde & Charles de Rousiers 
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr_v2.pdf
float BRDF_D_GGX(float NdotH, float Roughness)
{
    float Roughness2 = Roughness * Roughness;
    float f = (NdotH * Roughness2 - NdotH) * NdotH + 1.0f;
    return Roughness2 / (f * f + EPSILON);
}


float BRDF_F_FresnelSchlick(float LdotH, float F0)
{
    float f = F0 + (1.0f - F0) * pow((1.0f - LdotH), 5);
    return f;
}

float BRDF_G_SmithGGXCorrelated(float NdotL, float NdotV, float Roughness)
{
    float Roughness2 = Roughness * Roughness;
    float GV = NdotL * sqrt((-NdotV * Roughness2 + NdotV) * NdotV + Roughness2);
    float GL = NdotV * sqrt((-NdotL * Roughness2 + NdotL) * NdotL + Roughness2);

    return 0.5f / (GV + GL + EPSILON);
}

float BRDF_Specular(float NdotV, float NdotL, float NdotH, float LdotH, float Roughness, float F0)
{
    float D = BRDF_D_GGX(NdotH, Roughness);
    float F = BRDF_F_FresnelSchlick(LdotH, F0);
    float G = BRDF_G_SmithGGXCorrelated(NdotL, NdotV, Roughness);
    return (D * F * G) / PI;
}

void main()
{
    FinalColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
    vec4 BaseColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);
    vec4 SpecularColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
    vec3 LightDirection = normalize(vec3(0, 4, 4));
    vec3 ViewDirection = normalize(Position - uCameraPosition);
    vec3 HalfVector = normalize(ViewDirection + LightDirection);
    float Roughness = 0.9f; // [0.04 - 0.1f] -> Dielectric, [0.7, 1.0f] -> Metallic

    float RefractiveIndex = 0.27049f; // RI for Gold materials. I got this from http://refractiveindex.info/
    float F0 = pow(((1.0f - RefractiveIndex) / (1.0f + RefractiveIndex)), 2);

    float NdotL = saturate(dot(LightDirection, Normal));
    float NdotV = abs(dot(ViewDirection, Normal)) + EPSILON; // Avoid artifact - Ref: SIGGRAPH14 - Moving Frosbite to PBR
    float LdotH = saturate(dot(LightDirection, HalfVector));
    float NdotH = saturate(dot(Normal, HalfVector));

    float DiffuseFactor = BRDF_Lambert(NdotL);
    float SpecularFactor = BRDF_Specular(NdotV, NdotL, NdotH, LdotH, Roughness, F0);

    FinalColor = BaseColor * DiffuseFactor + SpecularColor * SpecularFactor;
}

Zły wynik

EDYTOWAĆ

Chropowatość = 0,2f; wprowadź opis zdjęcia tutaj

Chropowatość = 0,04f; wprowadź opis zdjęcia tutaj

hmkum
źródło
1
Nie przyjrzałem się zbytnio szczegółom kodu, ale obraz wydaje się być w porządku. Efekt Fresnela pojawia się jako czerwony pierścień. Przy tak dużej chropowatości (0,9) sensowne jest, że reszta obrazu jest w większości żółta (tj. Głównie rozproszona). Jeśli zmniejszysz chropowatość, możesz uzyskać czerwony
odblaskowy
@RichieSams Dodałem nowe zdjęcia dla różnych wartości chropowatości, ale nie widzę jeszcze błyszczącego czerwonego połysku.
hmkum,
1
Wydaje się, że twoje 2. i 3. obrazy mają ogólnie mniej czerwieni (w żółtym rozproszonym obszarze) niż oryginalny obraz. Nie jest to zbyt widoczne, ponieważ dodanie odrobiny czerwieni do żółtego obszaru pozostawia podobny kolor (raczej pomarańczowo-żółty niż żółty). Czy widzisz więcej szczegółów rozkładu czerwonego, jeśli znacznie zmniejszysz żółty? Całkowite pominięcie żółtego może pomóc w określeniu, co się dzieje.
trichoplax
@trichoplax zmniejszyłem żółty, ale znowu nie ma sposobu, aby zobaczyć czerwony lustrzany. Właśnie widzę efekt czerwonego pierścienia (Fresnela). Bez względu na to, co ustawiłem wartość szorstkości, nie widzę efektu lustrzanego, który skupił punkt.
hmkum,
2
Najpierw normalizuj wektor normalny przed jego użyciem, a następnie viewDirection to wektor wychodzący z pozycji do kamery: uCameraPosition - Position.
xpicox,

Odpowiedzi:

3

Problem rozwiązany przez RichieSams, trichoplax i xpicox. Dziękuję wszystkim za odpowiedzi.

Obniżam chropowatość, zmieniam kolor materiału i odwracam ViewDirection, a potem w końcu zaczynam widzieć właściwe odbicie lustrzane :).

Naprawiono kod:

#version 330 core

in vec3 Position;
in vec2 TexCoord0;
in vec3 Normal;
in vec3 Tangent;
out vec4 FinalColor;

uniform vec3 uCameraPosition;

#define PI 3.1415926f
#define EPSILON 10e-5f
#define saturate(value) clamp(value, 0.0f, 1.0f);

float BRDF_Lambert(float NdotL)
{
    return NdotL;
}

// Got these BRDF formulas Moving Frostbite to PBR slide by Sebastien Lagarde & Charles de Rousiers 
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr_v2.pdf
float BRDF_D_GGX(float NdotH, float Roughness)
{
    float Roughness2 = Roughness * Roughness;
    float f = (NdotH * Roughness2 - NdotH) * NdotH + 1.0f;
    return Roughness2 / (f * f + EPSILON);
}


float BRDF_F_FresnelSchlick(float LdotH, float F0)
{
    float f = F0 + (1.0f - F0) * pow((1.0f - LdotH), 5);
    return f;
}

float BRDF_G_SmithGGXCorrelated(float NdotL, float NdotV, float Roughness)
{
    float Roughness2 = Roughness * Roughness;
    float GV = NdotL * sqrt((-NdotV * Roughness2 + NdotV) * NdotV + Roughness2);
    float GL = NdotV * sqrt((-NdotL * Roughness2 + NdotL) * NdotL + Roughness2);

    return 0.5f / (GV + GL + EPSILON);
}

float BRDF_Specular(float NdotV, float NdotL, float NdotH, float LdotH, float Roughness, float F0)
{
    float D = BRDF_D_GGX(NdotH, Roughness);
    float F = BRDF_F_FresnelSchlick(LdotH, F0);
    float G = BRDF_G_SmithGGXCorrelated(NdotL, NdotV, Roughness);
    return (D * F * G) / PI;
}

void main()
{
    vec3 normal = normalize(Normal);

    vec4 BaseColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
    vec4 SpecularColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);

    vec3 LightDirection = normalize(vec3(0, 4, 4) - Position);
    vec3 ViewDirection = normalize(uCameraPosition - Position);
    vec3 HalfVector = normalize(ViewDirection + LightDirection);
    float Roughness = 0.04f;

    float RefractiveIndex = 0.24f; // RI for Gold materials. I got this from http://refractiveindex.info/
    float F0 = pow(((1.0f - RefractiveIndex) / (1.0f + RefractiveIndex)), 2);

    float NdotL = saturate(dot(LightDirection, normal));
    float NdotV = abs(dot(ViewDirection, normal)) + EPSILON; // Avoid artifact - Ref: SIGGRAPH14 - Moving Frosbite to PBR
    float LdotH = saturate(dot(LightDirection, HalfVector));
    float NdotH = saturate(dot(normal, HalfVector));

    float DiffuseFactor = BRDF_Lambert(NdotL);
    float SpecularFactor = 0.0f;
    if(DiffuseFactor > 0.0f)
    {
        SpecularFactor = BRDF_Specular(NdotV, NdotL, NdotH, LdotH, Roughness, F0);
    }
    FinalColor = BaseColor * DiffuseFactor + SpecularColor * SpecularFactor;
}

Ostateczny obraz:

wprowadź opis zdjęcia tutaj

hmkum
źródło