Banding artifact in screen space reflection

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.

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.

Thank you for letting us know what the issue was.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.