Войти
ПрограммированиеФорумГрафика

SSR (Screen Space Reflections) - проблемы, артефакты

Страницы: 1 2 3 4 Следующая »
#0
12:58, 11 окт. 2018

Всем привет!

Реализовал SSR, по вот этой статье: https://habr.com/post/244367/

Проблема в следующем - для простых объектов типа - ровные стены, куб, цилиндр - отражения
строятся вполне хорошо, без артефактов.. Но для более сложных объектов типа сферы - есть артефакты.
Подумал, что не точно находится пересечение отражённого луча и добавил уточнение по бинарному поиску,
но что-то результат совсем не стал от этого лучше.. Не хуже, но и не лучше..

Код главного пиксельного шейдера (шейдер под библиотеку BGFX, поэтому местами синтаксис немного отличается от
HLSL/GLSL):

$input v_texCoord0

#include "../../Common.sh"

uniform mat4 viewProj;
uniform mat4 invViewProj;
uniform vec4 cameraPosition;
uniform vec4 edgeFactorPower;
uniform vec4 reflectionDistanceFadeFactor;

SAMPLER2D(s_depthTexture, 0);
SAMPLER2D(s_normalTexture, 1);
SAMPLER2D(s_colorTexture, 2);

vec3 getWorldSpacePosition(vec2 UV, float depth)
{
    vec4 position;
 
    position.x = UV.x * 2.0 - 1.0;
    position.y = -(UV.y * 2.0 - 1.0);
    position.z = depth;
    position.w = 1.0;
 
    position = mul(invViewProj, position);
 
    position.xyz /= position.w;

    return position.xyz;
}

vec2 getUV(vec3 position)
{
    vec4 pVP = mul(viewProj, vec4(position, 1.0));
    pVP.xy = vec2(0.5, 0.5) + vec2(0.5, -0.5) * pVP.xy / pVP.w;
    return pVP.xy;
}

#define MAX_RM_STEPS 30
#define L_FACTOR 0.1
#define BS_STEPS 5

vec2 BinarySearch(vec3 dir, vec3 hitCoord, out vec3 finalHitCoord)
{
    vec2 UV;

    for (int i = 0; i < BS_STEPS; i++)
    {
        UV = getUV(hitCoord);
        float d = texture2D(s_depthTexture, UV).x;
        vec3 pos = getWorldSpacePosition(UV, d);

        float dDepth = hitCoord.z - pos.z;

        dir *= 0.5;
        if(dDepth > 0.0)
            hitCoord += dir;
        else
            hitCoord -= dir;
    }
 
    finalHitCoord = hitCoord;

    return UV;
}

vec2 RayMarch(vec3 position, vec3 dir, out float distance)
{
    vec3 hitCoord;
    vec2 UV;

    float L = L_FACTOR;

    float dist = 0.0;

    [loop]
    for (int i = 0; i < MAX_RM_STEPS; i++)
    {
        vec3 vDir = dir * L;
        hitCoord = position + vDir;

        UV = getUV(hitCoord);
        float d = texture2D(s_depthTexture, UV).x;
        vec3 newPosition = getWorldSpacePosition(UV, d);

        dist = length(hitCoord - newPosition);

        L = length(position - newPosition);
    }

    vec3 reflectionHitCoord;

    vec2 finalUV =  BinarySearch(dir * dist, hitCoord, reflectionHitCoord);
    distance = length(position - reflectionHitCoord);

    return finalUV;
}

void main()
{
    const float fresnel_multiplier = 2.8;
    const float fresnel_pow = 2.0;

    float depth = texture2D(s_depthTexture, v_texCoord0).x;

    vec3 position = getWorldSpacePosition(v_texCoord0, depth);

    vec3 viewDir = normalize(position - cameraPosition.xyz);

    vec3 normal = normalize(texture2D(s_normalTexture, v_texCoord0).xyz * 2.0 - 1.0);

    vec3 reflectDir = normalize(reflect(viewDir, normal));

    float fresnel = fresnel_multiplier * pow(1.0 + dot(viewDir, normal), fresnel_pow);

    float dist;
    vec2 vCoords = RayMarch(position, reflectDir, dist);

    float distFactor = 1.0 - saturate(dist * reflectionDistanceFadeFactor.x);

    vec2 vCoordsEdgeFact = vec2(1.0, 1.0) - pow(saturate(abs(vCoords.xy - vec2(0.5, 0.5)) * 2.0), edgeFactorPower.x);
    float fScreenEdgeFactor = saturate(min(vCoordsEdgeFact.x, vCoordsEdgeFact.y));

    float reflectionMultiplier = fresnel * saturate(reflectDir.z) * fScreenEdgeFactor;

    reflectionMultiplier = clamp(reflectionMultiplier, 0.0, 1.0);

    gl_FragColor = vec4(texture2D(s_colorTexture, vCoords).rgb * reflectionMultiplier, 0.0);
}

Скриншоты для наглядности:

ssr arf 1 | SSR (Screen Space Reflections) - проблемы, артефакты
SSR arf 2 | SSR (Screen Space Reflections) - проблемы, артефакты
SSR arf 3 | SSR (Screen Space Reflections) - проблемы, артефакты
SSR arf 4 | SSR (Screen Space Reflections) - проблемы, артефакты
SSR arf 5 | SSR (Screen Space Reflections) - проблемы, артефакты

Прошу помочь; уверен, что кто-то делал SSR и сталкивался с этими проблемами.

Благодарю.


#1
(Правка: 13:12) 13:11, 11 окт. 2018

DEN 3D
откуда ты вообще взял такую схему реймарчинга? в смысле с чего оно вообще должно сходиться?  бинарный поиск нужен, чтобы уточнить решение, он никак не поможет его исправить, если оно неправильно. поэтому отключай и отлаживай без него. у тебя ошибка в том, что луч просто пропускает особенности. рекомендую для начала реализовать самую простую схему, где шаг по лучу фиксирован, потом уже выделываться с непостоянным шагом.


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

#2
13:23, 11 окт. 2018

Suslik
Схему реймарчинга взял из вышеупомянутой статьи: https://habr.com/post/244367/

В статье код выглядит так:

float3 currentRay = 0;

float3 nuv = 0;
float L = LFactor;

for(int i = 0; i < 10; i++)
{
    currentRay = texelPosition + reflectDir * L;

    nuv = GetUV(currentRay); // проецирование позиции на экран
    float n = GetDepth(nuv.xy); // чтение глубины из DepthMap по UV

    float3 newPosition = GetPosition2(nuv.xy, n);
    L = length(texelPosition - newPosition);
}

И автор объясняет его следующим образом: "В моем варианте мы берем некоторое начальное приближение L и динамически меняем его исходя из расстояния между нашим текселем и позицией, которую мы “восстановили”.

Про общий свет пока не заморачиваюсь, сейчас главное SSR отладить.

#3
(Правка: 13:39) 13:35, 11 окт. 2018

DEN 3D
такая схема и будет сходиться только для простых случаев вроде вертикальных плоскостей. чем сложнее depth buffer, тем больше артефактов она будет давать. например, напрочь будет пропускать отражения тонких горизонтальных объектов в полу. по этой же причине у самого автора на фоне правого ящика хреновина отражается криво, с такими же артефактами, как у тебя:
Изображение

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

#4
13:54, 11 окт. 2018

Suslik
Спасибо, понял.. Можешь порекоммендовать ссылки
на хорошие имплементации SSR с нормальным рэймарчингом?
Только не в составе движков...

#5
14:01, 11 окт. 2018

DEN 3D
я не видел ни одной реализации, которая была бы настолько хорошей, что её можно взять себе и забыть. все делают screenspace raymarching по-разному не от хорошей жизни, а потому что идеального решения всё ещё нет. бери и сам экспериментируй, начать можно с гугла по запросу "screenspace raymarching". некоторые реализации можно посмотреть на шейдертое(например, по запросу parallax mapping), но там практически всегда используются distance field'ы вместо карты высот вроде depth buffer'а.

#6
14:32, 11 окт. 2018

На самом деле я пробовал и другие варианты.. Но они дают вообще неадекватный результат(
Этот вариант пока самый лучший..

#7
14:44, 11 окт. 2018

>Этот вариант пока самый лучший..
глянь это
https://blenderartists.org/t/ssr-screen-space-reflections-shader-v0-4/685927

#8
17:04, 11 окт. 2018

codingmonkey
Спасибо! Выглядит интересным) Буду пробовать..

#9
21:16, 11 окт. 2018

codingmonkey
Начал изучать эту реализацию, не понимаю в каком именно пространстве возвращают
координаты функции getViewPosition и getViewCoord? Мне, конечно, через матрицы
привычнее реализация, чем тащить в шейдер кучу параметров камеры - FOVY, Aspect, и.т.д..

Ну и в результате я не понимаю вообще в каком там пространстве координаты))

И ещё там GLSL, а мне надо под DX на HLSL - там могут быть различия и нюансы из-за
разницы систем координат...

#10
21:17, 11 окт. 2018

Например, точно уверен, что под DX вот эта формула будет выглядеть иначе:
-zfar * znear / (zdepth * (zfar - znear) - zfar);

#11
(Правка: 10:21) 10:20, 12 окт. 2018

DEN 3D
Попробуй шейдер от KillZone, можешь курить шейдеры CryTek(там реальней разобраться нежели в Unreal)

#12
10:22, 12 окт. 2018

DEN 3D
Взглянул по беглому и нашел уже ошибку. У тебя UV координаты в DX и GL отличаются убери минус перед 0.5

#13
11:21, 12 окт. 2018

могу ошибаться, но подход описаный в статье "в корне не верный"
использовать рей трейсинг пошаговый(который будет ошибаться и проваливаться из за величины шага) и строить "SDF" из контуров-слишком затратно и не будет работать в реальном времени

>>на хорошие имплементации SSR с нормальным рэймарчингом?
кубемапы спасут мир

если у тебя фотореалистичная сцена строй ее на рей-трейсере целиком(тебеж 1 кадр нужен)
если реал-тайм игра то кубемапы... или тратить пять лет на разработку супер оптимизированного алгоритма (используя cuda и процессор чтоб свести к минимуму потери производительности)

#14
11:27, 12 окт. 2018

Danilw
всё мимо кассы

Страницы: 1 2 3 4 Следующая »
ПрограммированиеФорумГрафика