Screen Space Reflections: Artifacts Problem

#1

Hello! I’m trying to implement a simple (so far) screen space reflections shader. Below is my code:

const int numBinarySearchSteps = 100;
const int maxSteps = 400;
const float rayStep = 0.01; // 25;
const float minRayStep = rayStep/2.5;

vec3 BinarySearch(vec3 dir, inout vec3 hitCoord, out float dDepth, out int hit)
{
    float depth;


    for(int i = 0; i < numBinarySearchSteps; i++)
    {
        vec4 projectedCoord = projectionMatrix * vec4(hitCoord, 1.0);
        projectedCoord.xyz /= projectedCoord.w;
        projectedCoord.xyz = projectedCoord.xyz * 0.5 + 0.5;

        depth = texture2D(depthMapTex, projectedCoord.xy).x;

		vec4 viewSpaceDepth = inverse(projectionMatrix) * vec4(projectedCoord.xy, depth * 2.0 - 1.0, 1.0);
		viewSpaceDepth.xyz /= viewSpaceDepth.w;
	
		dDepth = viewSpaceDepth.z - hitCoord.z; 


        if(dDepth < 0.0)
            hitCoord += dir;

        dir *= 0.5;
        hitCoord -= dir;    
    }

    vec4 projectedCoord = projectionMatrix * vec4(hitCoord, 1.0);
    projectedCoord.xyz /= projectedCoord.w;
    projectedCoord.xyz = projectedCoord.xyz * 0.5 + 0.5;

	hit = 1; 

    return vec3(projectedCoord.xy, depth);
}


vec4 RayCast(vec3 dir, inout vec3 hitCoord, out float dDepth, out int hit)
{

    dir *= rayStep;

    float depth;

	/*vec4 projectedCoord = projectionMatrix * vec4(hitCoord, 1.0);
        projectedCoord.xyz /= projectedCoord.w;
        projectedCoord.xyz = projectedCoord.xyz * 0.5 + 0.5;

        depth = texture2D(depthMapTex, projectedCoord.xy).x;

	return vec4(vec3(depth),1.0);*/

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


        vec4 projectedCoord = projectionMatrix * vec4(hitCoord, 1.0);
        projectedCoord.xyz /= projectedCoord.w;
        projectedCoord.xyz = projectedCoord.xyz * 0.5 + 0.5;

        depth = texture2D(depthMapTex, projectedCoord.xy).x;

		float zNear = 5.0;
		float zFar = 2000.0;
		float z_n = 2.0 * depth - 1.0;
		float z_e = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear));

		/*vec4 viewSpaceDepth = inverse(projectionMatrix) * vec4(projectedCoord.xy, depth * 2.0 - 1.0, 1.0);
		viewSpaceDepth.xyz /= viewSpaceDepth.w;*/
		
		dDepth = -hitCoord.z - z_e; 


        if(dDepth > 0.0){
			if (dDepth >= length(dir)) {
				// Inconclusive
				hit = 2; 
				return vec4(0.0);
			}
            return vec4(BinarySearch(dir, hitCoord, dDepth, hit), 1.0);
		}
    }
	hit = 0; 
    return vec4(0.0, 0.0, 0.0, 0.0);
}

vec3 ssr()
{
	// Reflection vector
    vec3 reflected = normalize(reflect(normalize(viewSpacePosition), normalize(viewSpaceNormal)));

    // Ray cast
    vec3 hitPos = viewSpacePosition;
    float dDepth;

	int hit;  /* 0 = no hit, 1 = good hit, 2 = nonsense hit */
    vec4 coords = RayCast(reflected /** max(minRayStep, -viewSpacePosition.z)*/, hitPos, dDepth, hit);

	vec3 color; 
	if (hit == 1) {
		color = texture2D(colorMapTex, coords.xy).rgb;
	}
	else {
		color = vec3(0.0);
	}
	return color;
}

So far, all it does is just return the color of every pixels purely specular reflection, or black if there is no reflection on the screen or if the reflection ray passes behind an object.

My issue is that I get these bizarre artifacts where the pixel gets a color (dDepth >= length(dir)), even though dDepth is supposed to be way larger than length(dir). I’ve been stuck on debugging this for ages now and I’m wondering if anyone can see the mistake?

This is the scene using just a simple shader (to the right), and the scene running only the SSR-shader (on the left)

Extremely thankful for any help!!!
Simon

#2

I’m not going to try to debug that, but one comment: it would be simpler (and also more efficient and robust) to just work in NDC throughout. I.e. transform the ray start and direction to NDC rather than converting between eye space and NDC at each step. Also add in the [-1,1]->[0,1] conversion.