Banding artifact in screen space reflection

#1

In the recent days, I’m learning to implement a simple screen space reflection effect. But there is a problem in the reflection.

It seems the reflection is not continuous, and is split by some horizontal lines.

I applied a traditional ray marching method to implement my program. And I tried to integrate the binary search to make the hit position more accurate. But this has no effect on the banding artifact.

However, I found if I reduce the step size of ray marching, the banding effect would appear less obvious, the height of each horizontal band becomes smaller. But I don’t thinks this is a ideal method.

Here, I paste my shader code for the ray marching, binary search, and a utility function which converts view space coordinate to the texture coordinate (range [0, 1]).

This is not the original code, I modified the some variable name and added some comments. Hope it would be more readable.

vec2 convertViewSpaceToTextureSpace(vec3 v) {
	vec4 positionTextureSpace = projectionMatrix * vec4(v, 1);
	positionTextureSpace.xy /= positionTextureSpace.w;
	return positionTextureSpace.xy / 2 + 0.5;
}

// `direction` may not be an unit vector
vec3 binarySearch(vec3 origin, vec3 direction, int iterationLimit) {
	float deltaDepth = 1;
	while (iterationLimit-- != 0 && deltaDepth > 0.001) {
		deltaDepth = origin.z - texture(positionInGBuffer, convertViewSpaceToTextureSpace(origin)).z;
		origin += (deltaDepth > 0) ? direction : -direction;
		direction /= 2;
	}
	return origin;
}

// `direction` should be an unit vector
bool castRay(vec3 origin, vec3 direction, out vec3 hitPositionViewSpace, out vec2 hitPositionTextureSpace) {
	direction *= 0.1; // stepSize = 0.1
	for (int i = 0; i < 1000; i++) { // numberOfSteps = 1000
		origin += direction;
		float depthFromGBuffer = texture(positionInGBuffer, convertViewSpaceToTextureSpace(origin)).z;
		if (origin.z > 0 || depthFromGBuffer > 0) { // Point is behind camera.
			return false;
		}
		if (abs(origin.z - depthFromGBuffer) < 0.1 && origin.z < depthFromGBuffer) { // stepSize = 0.1, avoid marching behind object problem
			hitPositionViewSpace = binarySearch(origin, direction, 10);
			hitPositionTextureSpace = convertViewSpaceToTextureSpace(origin);// Can be optimized with BST
			return clamp(hitPositionTextureSpace, 0, 1) == hitPositionTextureSpace; // Hit something out of screen
		}
	}
	return false; // Doesn't hit any thing
}

Thanks for spending some time reading through this question. Any suggestion is appreciated.

#2

I think I found the problem. After the binary search, I didn’t use its result but use the unrefined one. That’s why my binary search has no any effect.

After correcting my code, the banding artifact is totally gone.

#3

Thank you for letting us know what the issue was.