Problem With Screen Space Reflections in OpenGL

Started by
3 comments, last by lGuy 5 years, 4 months ago

Hi, I've recently been trying to implement screen space reflections into my engine, however, it is extremely buggy. I'm using this tutorial http://imanolfotia.com/blog/update/2017/03/11/ScreenSpaceReflections.html

The reflections look decent when I am close to the ground (first image), however when I get further away from the ground (the surface that is reflecting stuff), the reflections become blocky and strange (second image).

I have a feeling that it has something to do with the fact that the further the rays travel in view space, the more scattered they get -> therefore the reflected image is less detailed hence the blockiness. However I really am not sure about this and if this is the case, I don't know how to fix it.

It would be great if anyone had any suggestions around how to debug or sort this thing out. Thanks.

Here is the code for the ray casting


vec4 ray_cast(inout vec3 direction, inout vec3 hit_coord, out float depth_difference, out bool success)
{
	vec3 original_coord = hit_coord;

	direction *= 0.2;

	vec4 projected_coord;
	float sampled_depth;

	for (int i = 0; i < 20; ++i)
	{
		hit_coord += direction;

		projected_coord = projection_matrix * vec4(hit_coord, 1.0);

		projected_coord.xy /= projected_coord.w;
		projected_coord.xy = projected_coord.xy * 0.5 + 0.5;

      	// view_positions store the view space coordinates of the objects
		sampled_depth = textureLod(view_positions, projected_coord.xy, 2).z;

		if (sampled_depth > 1000.0) continue;

		depth_difference = hit_coord.z - sampled_depth;

		if ((direction.z - depth_difference) < 1.2)
		{
			if (depth_difference <= 0)
			{
				vec4 result;
              
                // binary search for more detailed sample
				result = vec4(binary_search(direction, hit_coord, depth_difference), 1.0);

				success = true;

				return result;
			}
		}
	}

	return vec4(projected_coord.xy, sampled_depth, 0.0);
}

Here is the code just before this gets called


float ddepth;

vec3 jitt = mix(vec3(0.0), vec3(hash33(view_position)), 0.5);

vec3 ray_dir = reflect(normalize(view_position), normalize(view_normal));

ray_dir = ray_dir * max(0.2, -view_position.z);

/* ray cast */
vec4 coords = ray_cast(ray_dir, view_position, ddepth);

 

ssr4.PNG

ssr5.PNG

Advertisement

I found a fix to the problem. The problem was being caused because of this :


if ((direction.z - depth_difference) < 1.2)

(Visualize the scene with the first image)ssr.thumb.png.c4146b4761a1f80d209eec6d434e1a88.png

The reason I needed this "1.2" magic number was to check whether or not the point B was not too far away from the point A (The point A's z coordinate basically projects to infinity because the reflection gets calculated with the info from a 2D texture). However this caused the weird bar artifacts because of the ray march distances.

ssr2.thumb.png.837edd62b1905ea9929289d07495a30c.png

With the box (second image), the ray marches are of a certain distance (it varies depending on how far the point trying to reflect is from the camera). The point P1 is positioned in such a way that when the ray thinks it hits the box with B1 (because it is behind A1), the ray is within the 1.2 proximity required for the reflection to happen. However, the point P2 is just in the zone where all the rays' B position (in this case B2) arrive just too far for the 1.2 requirement. 

So how do you fix it?

Remove the 1.2 requirement!

However this causes other artifacts on the visible points on the surface that are behind the object being reflected. The rays emitted from these points will think that they reflect simply because their B point is behind the A point as there is no threshold. So if you remove the threshold there are artifacts and when you keep the threshold, there are still artifacts. 

The solution I found was to get the two vectors : P to B and A to P. B is the point that the ray thinks it is at when it is behind A and A is the actual point that is going to be reflected. Depending on the angle between these two, I can tell whether or not to reflect.

ssr3.thumb.png.e3d0377e0b1c9b5a4f793963da508d95.png

On the third image, you can see that the angle between these two vectors for incorrect reflections is much bigger than that between the two vectors for the correct reflection. So the solution is to set the threshold to be 


if (angle_between_vectors > some_value) reflect_point();

Hope this helped for anyone.

Out of curiosity, any screenshots of the correct output?

8 hours ago, orange451 said:

Out of curiosity, any screenshots of the correct output?

This is how it was before

fail.thumb.PNG.57b2195eeda1e6911f9803a83247bf10.PNG

Now it's like this

success.thumb.PNG.19b12c79bdba97e15c3af15d1ac18555.PNG

This topic is closed to new replies.

Advertisement