OpenGL отложенное пиксельное освещение - PullRequest
0 голосов
/ 20 сентября 2018

Я работаю над трехпроходной системой отсроченного освещения для воксельной игры, однако у меня возникают проблемы с пиксельным освещением и окклюзией окружающей среды.

На первом этапе отображается цвет, положение и нормаль каждого из них.пиксель на экране на отдельные текстуры.Эта часть работает правильно:

Base Rendering with no lighting

Второй шейдер вычисляет значение окклюзии для каждого пикселя на экране и отображает его в текстуре.Эта часть не работает должным образом и имеет пиксели:

Base Rendering with Occlusion Applied

Необработанные данные окклюзии:

Raw Occlusion Data

Третий шейдер использует текстуры цвета, положения, нормалей и окклюзии для отображения игровой сцены на экране.Освещение на этом этапе также является пиксельным:

Lighting

Фрагментный шейдер SSAO (2-й проход) происходит от www.LearnOpenGL.com учебник для экранного пространства Ambient Occlusion:

out float FragColor;

layout (binding = 0) uniform sampler2D gPosition; // World space position
layout (binding = 1) uniform sampler2D gNormal; // Normalised normal values
layout (binding = 2) uniform sampler2D texNoise;

uniform vec3 samples[64]; // 64 random precalculated vectors (-0.1 to 0.1 magnitude)
uniform mat4 projection;

float kernelSize = 64;
float radius = 1.5;

in vec2 TexCoords;

const vec2 noiseScale = vec2(1600.0/4.0, 900.0/4.0);

void main()
{
    vec4 n = texture(gNormal, TexCoords);

    // The alpha value of the normal is used to determine whether to apply SSAO to this pixel
    if (int(n.a) > 0)
    {
        vec3 normal = normalize(n.rgb);
        vec3 fragPos = texture(gPosition, TexCoords).xyz;
        vec3 randomVec = normalize(texture(texNoise, TexCoords * noiseScale).xyz);

        // Some maths. I don't understand this bit, it's from www.learnopengl.com
        vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
        vec3 bitangent = cross(normal, tangent);
        mat3 TBN = mat3(tangent, bitangent, normal);

        float occlusion = 0.0;

        // Test 64 points around the pixel
        for (int i = 0; i < kernelSize; i++)
        {
            vec3 sam = fragPos + TBN * samples[i] * radius;

            vec4 offset = projection * vec4(sam, 1.0);
            offset.xyz = (offset.xyz / offset.w) * 0.5 + 0.5;

            // If the normal's are different, increase the occlusion value
            float l = length(normal - texture(gNormal, offset.xy).rgb);
            occlusion += l * 0.3;
        }

        occlusion = 1 - (occlusion / kernelSize);
        FragColor = occlusion;
    }
}

Подсветка и финальный фрагментный шейдер:

out vec4 FragColor;

in vec2 texCoords;

layout (binding = 0) uniform sampler2D gColor; // Colour of each pixel
layout (binding = 1) uniform sampler2D gPosition; // World-space position of each pixel
layout (binding = 2) uniform sampler2D gNormal; // Normalised normal of each pixel
layout (binding = 3) uniform sampler2D gSSAO; // Red channel contains occlusion value of each pixel

// Each of these textures are 300 wide and 2 tall.
// The first row contains light positions. The second row contains light colours.

uniform sampler2D playerLightData; // Directional lights
uniform sampler2D mapLightData; // Spherical lights

uniform float worldBrightness;

// Amount of player and map lights
uniform float playerLights;
uniform float mapLights;

void main()
{
    vec4 n = texture(gNormal, texCoords);

    // BlockData: a = 4
    // ModelData: a = 2
    // SkyboxData: a = 0;

    // Don't do lighting calculations on the skybox
    if (int(n.a) > 0)
    {
        vec3 Normal = n.rgb;
        vec3 FragPos = texture(gPosition, texCoords).rgb;
        vec3 Albedo = texture(gColor, texCoords).rgb;

        vec3 lighting = Albedo * worldBrightness * texture(gSSAO, texCoords).r;

        for (int i = 0; i < playerLights; i++)
        {
            vec3 pos = texelFetch(playerLightData, ivec2(i, 0), 0).rgb;

            vec3 direction = pos - FragPos;
            float l = length(direction);

            if (l < 40)
            {
                // Direction of the light to the position
                vec3 spotDir = normalize(direction);

                // Angle of the cone of the light
                float angle = dot(spotDir, -normalize(texelFetch(playerLightData, ivec2(i, 1), 0).rgb));

                // Crop the cone
                if (angle >= 0.95)
                {
                    float fade = (angle - 0.95) * 40;
                    lighting += (40.0 - l) / 40.0 * max(dot(Normal, spotDir), 0.0) * Albedo * fade;
                }
            }
        }

        for (int i = 0; i < mapLights; i++)
        {
            // Compare this pixel's position with the light's position
            vec3 difference = texelFetch(mapLightData, ivec2(i, 0), 0).rgb - FragPos;
            float l = length(difference);

            if (l < 7.0)
            {
                lighting += (7.0 - l) / 7.0 * max(dot(Normal, normalize(difference)), 0.0) * Albedo * texelFetch(mapLightData, ivec2(i, 1), 0).rgb;
            } 
        }

        FragColor = vec4(lighting, 1.0);
    }
    else
    {
        FragColor = vec4(texture(gColor, texCoords).rgb, 1.0);
    }
}

Размер каждого лица блока в игре - 1x1 (размер мирового пространства),Я попытался разбить эти грани на более мелкие треугольники, как показано ниже, однако видимой разницы не было.

More Triangles per face

Как я могу увеличитьРазрешение освещения и данных SSAO, чтобы уменьшить эти пиксельные артефакты?Заранее спасибо

1 Ответ

0 голосов
/ 27 сентября 2018

Хорошие новости!Благодаря some_rand на стеке GameDev я смог исправить это, повысив разрешение буфера позиции с GL_RGBA16F до GL_RGBA32F.

Вот его ответ.

...