depth banding.

Hello.

I am trying to implement a few fragment algorithms using GLSL and FBO, i am using two textures for sampling normal and positions, Using GL_RGBA/GL_RGBA16F_ARB/GL_NEAREST/GL_CLAMP_TO_EDGE (tried a few other combinations GL_RGBA32F_ARB… no go) parameters when creating these two textures, everything is ok, but banding on Z axis is giving me nightmares, which all algorithms i use depend on sampling depth value.

Depth range is 0.1 - 20.0, also tried playing with depth values, which didn’t help.


// vertex shader for position texture
varying vec3 position;
void main()
{
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
	position = (gl_ModelViewMatrix * gl_Vertex).xyz;
}

// fragment shader for position texture
varying vec3 position;
void main()
{
	gl_FragColor = vec4(position, 0.0);
}

// fragment shader, sampling position
uniform float inv_z; // 1.0/(far-near)
uniform sampler2D position;

varying vec2 texcoord;

void main()
{
	vec4 O = texture2D(position, texcoord);
	gl_FragColor = vec4(1.0 - O.z * inv_z);
}

Sadly my current developement card is an ATI (1950Pro), as you may know ATI have some problems implementing GLSL + FBO-MRT, which costed a week of mine to find out what is actually going on, i started to think this is another GLSL + FBO issue of ATI cards.

Anyone has any ideas, if it is an issue or i am doing something wrong?

Thank you.

This one is better i think.

// fragment shader, sampling position
uniform float inv_z; // 1.0/(far-near)
uniform sampler2D position;

varying vec2 texcoord;

void main()
{
	vec4 O = texture2D(position, texcoord);
	gl_FragColor = vec4(O.z * inv_z);
}

That screenshot is about as smooth as a 8bits/channel picture can possibly look. Yes, the banding is visible, but that’s common for grayscale gradients. If you drag the dropper tool in Paint Shop Pro over the image you can see that there’s no banding other than that of only having 8 bits / channel. Each band differ only by 1 in value.

Do you use an LCD ? Quite a lot of models are still not real 8bit/color and only use 6bits, sometimes masked by temporal dithering that fail hardly for fine stripes. :stuck_out_tongue:

Nope, not LCD.

Why 8bit/channel, am i losing precision somewhere? since i have tried rendering to both 16 and 32bit/channels and still same results, also screenshots just demonstration, when i sample textures, i get exactly these banding effects and can’t get rid of them if i don’t use a really large epsilon values.

Thank you.

In the final step you take the value from your buffer and write it to gl_FragColor. Since you are going to display this you are writing to a surface with 8bit per color component here. Since you only draw this in grayscale you will get the banding. The original 16bit per component texture might not exhibit this banding but there is no way to display this directly.

[ www.trenki.net | vector_math (3d math library) | software renderer ]

16-bit floats are not particularly precise. As you are only storing numbers from 0.1 to 20.0 you’re effectively using just 3 bits of exponent range, or 13 bits altogether. And these are not linearly distributed, e.g. between 8.0 and 16.0 you only have 1024 distinct values.

If you really can’t use fp32, you at least want to use the full potential of fp16. But to do this you need to decide in which part of the range you need precision the most.
Of course you could also try to encode Z using two channels of the texture.

And a little performance hint by the way:
If your projection matrix is a typical symmetrical frustum, it looks something like this:

(A 0  0 0)
(0 B  0 0)
(0 0  C D)
(0 0 -1 0)

As you can see most of the elements are zero. If you already have to calculate the view space position in the shader you don’t have to do a second full matrix-vector multiply:

// vertex shader for position texture
varying vec3 position;
uniform vec4 projection; // (A B C D) as described above
void main()
{
	position = (gl_ModelViewMatrix * gl_Vertex).xyz;
	gl_Position.xyz = position * projection.xyz;
	gl_Position.w = -position.z;
	gl_Position.z += projection.w;
}

I finally got the point, i think.
Whatever texture format i use, (32bpp, 64bpp, 128bpp ++) since i render this to 32bpp screen, i get exact same results, which is very logical, and because i render in just grayscale, as a nature of grayscale, i get this effect, while actually there is no banding.

Here is the origin of this trouble.

normal texture GL_RGBA16F_ARB,
position texture GL_RGBA16F_ARB,
combine texture GL_RGBA16F_ARB,
copy result to framebuffer 0.
As you can see, banding is in z axis, hence where my trouble lies. Why just in this axis?
http://www.uploadgeek.com/uploads456/1/capture_a16.jpg

normal texture GL_RGBA32F_ARB,
position texture GL_RGBA32F_ARB,
combine texture GL_RGBA32F_ARB,
copy result to framebuffer 0, no banding.
http://www.uploadgeek.com/uploads456/1/capture_a32.jpg


float solve(vec4 sample, vec4 position, vec3 normal)
{
	vec3 delta = sample.xyz - position.xyz;

	float d = dot(delta, normal);
	return (d > 0.0) ? 1.0 : 0.0;
//	return (d > eps) ? 1.0 : 0.0;
}

void main()
{
	vec3 normal = texture2D(tex_normal, texcoord).xyz;
	vec4 position = texture2D(tex_position, texcoord);
	
	float f;
	f += solve(texture2D(tex_position, texcoord + sdist * vec2(-1.0, -1.0)), position, normal);
	f += solve(texture2D(tex_position, texcoord + sdist * vec2( 1.0, -1.0)), position, normal);
	f += solve(texture2D(tex_position, texcoord + sdist * vec2( 1.0,  1.0)), position, normal);
	f += solve(texture2D(tex_position, texcoord + sdist * vec2(-1.0,  1.0)), position, normal);
	f += solve(texture2D(tex_position, texcoord + sdist * vec2( 1.0,  0.0)), position, normal);
	f += solve(texture2D(tex_position, texcoord + sdist * vec2(-1.0,  0.0)), position, normal);
	f += solve(texture2D(tex_position, texcoord + sdist * vec2( 0.0,  1.0)), position, normal);
	f += solve(texture2D(tex_position, texcoord + sdist * vec2( 0.0, -1.0)), position, normal);
	f /= 8.0;

	f = max(1.0 - f, 0.0);
	gl_FragColor = vec4(f);

}

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