Terrain: Contour Lines using pixel shader

Started by
6 comments, last by rob35 12 years ago
I have to draw x, y, z level lines on my relief surface. 2 soluttions: 1. Using of additional geometry (lines). Major disadvantage - i need time to calculate this lines. 2. Using pixel shader.

float4 TestP1(PS_INPUT Input): COLOR0
{
        float4 Color;
	int z = ceil(Input.Position.y);
	int y = ceil(Input.Position.z);
	int x = ceil(Input.Position.x);
	Color = Input.Color;

	if(abs(fmod(z, 100))<1.0)
	{
		Color.b = 1.0f;
		Color.r = Color.g = 0.0f;
	}
	if(abs(fmod(x, 100))<1.0)
	{
		Color.b = 1.0f;
		Color.r = Color.g = 0.0f;
	}
	if(abs(fmod(y, 100))<1.0)
	{
		Color.r = 1.0f;
		Color.b = Color.g = 0.0f;
	}

	return Color;
}



But on this way i have troubles: first far and second near Any ideas, how to get "good" level lines in shader? [Edited by - mr_hell on April 2, 2009 6:31:04 AM]
Advertisement
You can accomplish this with screen-space derivatives. Instead of drawing a band of color over a range of contours, you draw a band of color over a range of pixels near the contour value. Here's an example in GLSL, but it should port easily.

This vertex shader simply passes along the position in a varying variable.

varying vec3 k;void main(){    k = gl_Vertex.xyz;    gl_Position = ftransform();}


For reference, here's a GLSL fragment shader that does something similar to your approach. It uses smoothstep to get anti-aliased contour lines.
varying vec3 k;void main(){    vec3 f  = fract (k * 100.0);    vec3 df = fwidth(k * 100.0);    vec3 g = smoothstep(0.05, 0.10, f);    float c = g.x * g.y * g.z;    gl_FragColor = vec4(c, c, c, 1.0);}

Here's what this looks like applied to the head of the famous dragon. It has the same results that you see: lines that are too narrow in some places and too wide in others.



Now here's a fragment shader that uses screen-space derivatives to accomplish the same task. It uses smoothstep to blend between distances of 1 and 2 pixels from the desired contour value.
varying vec3 k;void main(){    vec3 f  = fract (k * 100.0);    vec3 df = fwidth(k * 100.0);    vec3 g = smoothstep(df * 1.0, df * 2.0, f);    float c = g.x * g.y * g.z;    gl_FragColor = vec4(c, c, c, 1.0);}

The result is a set of contour lines of consistent width everywhere.



I just happened to stumble across this and it's a nice approach! I will try and remember it for the future.
Nice!

A little modification to get smoother result :)

uniform float gsize;uniform float gwidth;varying vec3 P;void main(){	vec3 f  = abs(fract (P * gsize)-0.5);	vec3 df = fwidth(P * gsize);	vec3 g = smoothstep(-gwidth*df,gwidth*df , f);	float c = g.x * g.y * g.z; 	gl_FragColor = vec4(c, c, c, 1.0);// * gl_Color;}


Edit:
another little modification 8^)
uniform float gsize;//size of the griduniform float gwidth;//grid lines'width in pixelsvarying vec3 P;void main(){	vec3 f  = abs(fract (P * gsize)-0.5);	vec3 df = fwidth(P * gsize);	float mi=max(0.0,gwidth-1.0), ma=max(1.0,gwidth);//should be uniforms	vec3 g=clamp((f-df*mi)/(df*(ma-mi)),max(0.0,1.0-gwidth),1.0);//max(0.0,1.0-gwidth) should also be sent as uniform	float c = g.x * g.y * g.z;	gl_FragColor = vec4(c, c, c, 1.0);	gl_FragColor = gl_FragColor * gl_Color;}


[Edited by - knighty on April 3, 2009 10:39:31 AM]
Oh yeah I totally screwed up the antialiasing on that. Not sure what I was thinking. It's still aliased on one side. We'd need two smoothsteps to make it perfect. You get the idea, at least.
Trurl
yessss, it works, thank you.
How to rewrite this shader for SM 2.0? (does not support ddx ddy operations - i have to emulate gradiants by myself).
its necessary for me!

[Edited by - mr_hell on April 3, 2009 8:28:30 AM]

How to rewrite this shader for SM 2.0? (does not support ddx ddy operations - i have to emulate gradiants by myself).
its necessary for me!

[Edited by - mr_hell on April 3, 2009 8:28:30 AM]

Yes, how do we get this to work on HLSL SM 2.0 cards? There's no ddx/ddy functions in any graphics cards but the new super-duper ones that many people don't have. It is so frustrating to think that it is impossible to have real contour lines without a SM 3.0 card! If anyone could figure out how to implement this on SM 2.0, they'd be a genius, but it seems that it is impossible unless you have the fancy ddx/ddy functions.

This topic is closed to new replies.

Advertisement