Nieosiąganie pożądanych wyników dzięki implementacji SSAO

12

Po wdrożeniu odroczonego renderowania próbowałem szczęścia z implementacją SSAO, korzystając z tego samouczka . Niestety nie otrzymuję niczego, co wygląda jak SSAO, poniżej możesz zobaczyć mój wynik.

nieudana próba ssao

Widać, że powstaje jakiś dziwny wzór i nie ma cieniowania okluzji tam, gdzie musi być (tj. Pomiędzy obiektami i na ziemi). Zaimplementowane przez mnie shadery:


#VS
#version 330 core

uniform mat4 invProjMatrix;

layout(location = 0) in vec3 in_Position;
layout(location = 2) in vec2 in_TexCoord;

noperspective out vec2 pass_TexCoord;
smooth out vec3 viewRay;

void main(void){
    pass_TexCoord = in_TexCoord;
    viewRay = (invProjMatrix * vec4(in_Position, 1.0)).xyz;
    gl_Position = vec4(in_Position, 1.0);
}

#FS
#version 330 core

uniform sampler2D DepthMap;
uniform sampler2D NormalMap;
uniform sampler2D noise;

uniform vec2 projAB;
uniform ivec3 noiseScale_kernelSize;
uniform vec3 kernel[16];
uniform float RADIUS;
uniform mat4 projectionMatrix;

noperspective in vec2 pass_TexCoord;
smooth in vec3 viewRay;

layout(location = 0) out float out_AO;

vec3 CalcPosition(void){
    float depth = texture(DepthMap, pass_TexCoord).r;
    float linearDepth = projAB.y / (depth - projAB.x);
    vec3 ray = normalize(viewRay);
    ray = ray / ray.z;
    return linearDepth * ray;
}

mat3 CalcRMatrix(vec3 normal, vec2 texcoord){
    ivec2 noiseScale = noiseScale_kernelSize.xy;
    vec3 rvec = texture(noise, texcoord * noiseScale).xyz;
    vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
    vec3 bitangent = cross(normal, tangent);

    return mat3(tangent, bitangent, normal);
}

void main(void){

    vec2 TexCoord = pass_TexCoord;
    vec3 Position = CalcPosition();
    vec3 Normal = normalize(texture(NormalMap, TexCoord).xyz);

    mat3 RotationMatrix = CalcRMatrix(Normal, TexCoord);

    int kernelSize = noiseScale_kernelSize.z;

    float occlusion = 0.0;

    for(int i = 0; i < kernelSize; i++){
        // Get sample position
        vec3 sample = RotationMatrix * kernel[i];
        sample = sample * RADIUS + Position;
        // Project and bias sample position to get its texture coordinates
        vec4 offset = projectionMatrix * vec4(sample, 1.0);
        offset.xy /= offset.w;
        offset.xy = offset.xy * 0.5 + 0.5;
        // Get sample depth
        float sample_depth = texture(DepthMap, offset.xy).r;
        float linearDepth = projAB.y / (sample_depth - projAB.x);
        if(abs(Position.z - linearDepth ) < RADIUS){
            occlusion += (linearDepth <= sample.z) ? 1.0 : 0.0;
        }
    }
    out_AO = 1.0 - (occlusion / kernelSize);
}

Rysuję quad na pełnym ekranie i przekazuję tekstury głębokości i normalności. Normalne są w RGBA16F z kanałem alfa zarezerwowanym dla współczynnika AO w przebiegu przejścia rozmycia. Głębokość przechowuję w nieliniowym buforze głębokości (32F) i odzyskuję głębokość liniową za pomocą:


float linearDepth = projAB.y / (depth - projAB.x);

gdzie projAB.yoblicza się jako:

wprowadź opis zdjęcia tutaj

i projAB.xjako:

wprowadź opis zdjęcia tutaj

Pochodzą one z macierzy glm :: perspektywy (gluperspective). z_n i z_f są odległością bliską i daleką klipu.

Jak opisano w linku, który zamieściłem na górze, metoda tworzy próbki na półkuli o wyższym rozkładzie blisko środka. Następnie używa losowych wektorów z tekstury, aby losowo obracać półkulę wokół kierunku Z i ostatecznie orientować ją wzdłuż normalnej przy danym pikselu. Ponieważ wynik jest głośny, przejście do rozmycia następuje po przejściu SSAO.

Zresztą moja rekonstrukcja pozycji nie wydaje się błędna, ponieważ próbowałem zrobić to samo, ale z pozycją przekazaną z tekstury zamiast odtworzenia.

Próbowałem też bawić się promieniem, rozmiarem tekstury szumu i liczbą próbek oraz różnymi formatami tekstur, ale bez powodzenia. Z jakiegoś powodu przy zmianie promienia nic się nie zmienia.

Czy ktoś ma jakieś sugestie? Co może pójść nie tak?

Grieverheart
źródło
Myślę, że rozmycie musi być osobnym przejściem. Czy możesz zamieścić zrzut ekranu swojego shadera bez rozmycia?
knight666
Przepływ rozmycia jest osobny, możesz sprawdzić zrzut ekranu przed rozmyciem .
Grieverheart,

Odpowiedzi:

6

Znalazłem problem. To był naprawdę głupi błąd, nie wiedziałem, że musisz określić, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);aby uzyskać prawidłowe wartości głębokości, a zatem nie próbowałem wartości głębokości. Teraz otrzymuję ładny efekt SSAO:

wprowadź opis zdjęcia tutaj

Grieverheart
źródło
Zgłoś
Tak, niestety muszę poczekać jeden dzień, aby móc oflagować moją odpowiedź jako poprawną: S.
Grieverheart,
Mój błąd, nie sprawdziłem znaczników czasu.
SomeGuy,