# Terrain: Contour Lines using pixel shader

This topic is 2758 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

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 and second Any ideas, how to get "good" level lines in shader? [Edited by - mr_hell on April 2, 2009 6:31:04 AM]

##### Share on other sites
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.

##### Share on other sites
I just happened to stumble across this and it's a nice approach! I will try and remember it for the future.

##### Share on other sites
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]

##### Share on other sites
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.

##### Share on other sites
Trurl
yessss, it works, thank you.

##### Share on other sites
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]

##### Share on other sites

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.

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 16
• 11
• 23
• 42
• 75