Sign in to follow this  
mr_hell

Terrain: Contour Lines using pixel shader

Recommended Posts

mr_hell    126
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]

Share this post


Link to post
Share on other sites
Trurl    208
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 this post


Link to post
Share on other sites
knighty    313
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 grid
uniform float gwidth;//grid lines'width in pixels
varying 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 this post


Link to post
Share on other sites
Trurl    208
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 this post


Link to post
Share on other sites
mr_hell    126
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 this post


Link to post
Share on other sites
rob35    78
[quote name='mr_hell' timestamp='1238722086' post='4431886']
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]
[/quote]
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this