3

While implementing SSLR, I ran into the problem of incorrectly displaying objects: they are infinitely projected "down" and displayed in no way at all in the mirror. I give the code and screenshot below.

Fragment SSLR shader:

#version 330 core

uniform sampler2D normalMap; // in view space
uniform sampler2D depthMap; // in view space
uniform sampler2D colorMap;
uniform sampler2D reflectionStrengthMap;
uniform mat4 projection;
uniform mat4 inv_projection;

in vec2 texCoord;

layout (location = 0) out vec4 fragColor;

vec3 calcViewPosition(in vec2 texCoord) {
    // Combine UV & depth into XY & Z (NDC)
    vec3 rawPosition = vec3(texCoord, texture(depthMap, texCoord).r);

    // Convert from (0, 1) range to (-1, 1)
    vec4 ScreenSpacePosition = vec4(rawPosition * 2 - 1, 1);

    // Undo Perspective transformation to bring into view space
    vec4 ViewPosition = inv_projection * ScreenSpacePosition;

    // Perform perspective divide and return
    return ViewPosition.xyz / ViewPosition.w;
}

vec2 rayCast(vec3 dir, inout vec3 hitCoord, out float dDepth) {
    dir *= 0.25f;  

    for (int i = 0; i < 20; i++) {
        hitCoord += dir; 

        vec4 projectedCoord = projection * vec4(hitCoord, 1.0);
        projectedCoord.xy /= projectedCoord.w;
        projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5; 

        float depth = calcViewPosition(projectedCoord.xy).z;
        dDepth = hitCoord.z - depth; 

        if(dDepth < 0.0) return projectedCoord.xy;
    }

    return vec2(-1.0);
}

void main() {
    vec3 normal = texture(normalMap, texCoord).xyz * 2.0 - 1.0;
    vec3 viewPos = calcViewPosition(texCoord);

    // Reflection vector
    vec3 reflected = normalize(reflect(normalize(viewPos), normalize(normal)));

    // Ray cast
    vec3 hitPos = viewPos;
    float dDepth; 
    float minRayStep = 0.1f;
    vec2 coords = rayCast(reflected * max(minRayStep, -viewPos.z), hitPos, dDepth);
    if (coords != vec2(-1.0)) fragColor = mix(texture(colorMap, texCoord), texture(colorMap, coords), texture(reflectionStrengthMap, texCoord).r);
    else fragColor = texture(colorMap, texCoord);
}

Screenshot: sslr

Also, the lamp is not reflected at all

I will grateful for help

UPDATE:

colorMap: cm

normalMap: nm

depthMap: dm

UPDATE: I solved the problem with the wrong reflection, but there are still problems.

I solved it as follows: ViewPosition.y *= -1

Now, as you can see in the screenshot, the lower parts of the objects are not reflected for some reason. screenshot

The question still remains open.

congard
  • 945
  • 2
  • 10
  • 28
  • This question is far from providing a [MCVE](https://stackoverflow.com/help/mcve), so one can only guess. What ius `colorMap`, what is your rendering architecture (especially, which passes are you doing). Also the `max(minRayStep, -viewPos.z)` seems a bit weird, that will result in gigantic step size if the mirror is a few units away. – derhass Nov 05 '18 at 19:16
  • @derhass I updated the question – congard Nov 05 '18 at 20:40

1 Answers1

2

I m struggling to get a fine ssr too. I found two things that could help.

  1. To get the view space normals you have to keep only the rotation of the camera and remove the translation, because if you dont, you will get the normals stretched to the opposite direction of the camera movement and will no longer have the right direction even if you normalize them again, for column major mat4 you can do it like:

    mat4 viewNoTranslation = view; viewNoTranslation[3] = vec4(0.0, 0.0, 0.0, 1.0);

  2. The depth sampling from the depth image is logarithmic and if you linearize it you will get indeed the values from 0 to 1 but they will be inaccurate as to the needed precision. I tried to get the depth value straight from the vertex shader:

    gl_Position = ubo.projection * ubo.view * ubo.model * inPos; depth = gl_Position.z;

I dont know if it is right but the depth now is more accurate.

If you make proggress, please update :)

  • Thank you for the answer, but the solution you proposed unfortunately did not help me. If you have successfully implemented SSR, could you share the code, please? – congard Nov 12 '18 at 15:24
  • yes i finally did it, it needs some more variables to handle the edges and some visual errors, but it works :D Btw calculations are for Vulkan NDC, but you can easy tranform them if needed. Here is the shader https://github.com/christoskaramou/VulkanMonkey3D/blob/master/VulkanMonkey/shaders/Reflections/reflection.frag – Christos Karamoustos Nov 12 '18 at 23:35
  • i pass 2 buffers, normal and position in world space, with the w compoment being the depth in view space from the vertex shader before the projection calculation in a gBuffer shader. vec4 viewPos = ubo.view * ubo.model * inPos; depth = viewPos.z; you have to play with the values thought to get correct results – Christos Karamoustos Nov 12 '18 at 23:38
  • Thank you so much, you gave me a great idea. Problem solved, I will post a solution later – congard Nov 17 '18 at 16:27
  • 1
    @PeGiannOS the problem was in `depthMap`. Right now I'm just using `positionMap`. Correct [shader](https://github.com/congard/algine/blob/master/src/resources/shaders/ssr/fragment.glsl) – congard Aug 28 '19 at 08:11
  • @congard Cool, thx :), 1 silly question: What do you use for texCoord? I get weird artifacts with gl_FragCoord.xy/resolution.xy , in my case i have a resolution of 1000x800 (my window size). Is it correct? or do i need the actual texture coords of the object. I tried with it but it is like they are in a different space – PeGiannOS Aug 28 '19 at 09:07
  • @PeGiannOS I pass `texCoord` as an attribute. [Here](https://github.com/congard/algine/blob/master/src/algine_renderer.cpp#L113) tex coords array. It can be also done using vertices: `texCoord = vertex * 0.5 + 0.5` – congard Aug 28 '19 at 09:33
  • Ah yes, thx, so it is from the object, i forgot to say that im trying to add reflections to other objects , sphere, cube and a mesh but i will try for the floor for now. Cheers :)! – PeGiannOS Aug 28 '19 at 09:40