Sign in to follow this  
all_names_taken

Projective space in GLSL shader

Recommended Posts

I'm rendering a landscape, and was hoping the shader code given below would output a smooth gradient from RGB 0,0,0 to RGB 1,1,1 for the landscape, with white to the right of the screen and black to the left of the screen. When I rotate the camera, the gradient should follow the rotation. However what I get is a sharp line somewhere in the middle of the screen, with black to the left and white to the right. When I tried to scale the float x by dividing it by arbitrary values such as 1,000 or 10,000, I get a gradient, but the gradient seems to be different for the far away parts of the landscape (so for instance RGB 10,10,10 is closer to the middle of the screen in the upper part, than in the lower part, where it is further to the left), unless I divide it by projPos.w. I have no idea why the initial code doesn't work. Vertex shader:
varying vec4 projPos;

main() {
	gl_Position = ftransform();
	projPos = ftransform();
}




Fragment shader:
varying vec4 projPos;

main() {
	float x = (projPos.x + 1.0f) / 2.0f;
	gl_FragColor = vec4(x, x, x, 1.0f);
}




Here's how I thought when writing this: in projective space, all coordinates should be in the interval [-1..1]. So if I multiply my position by the modelviewproj matrix, I should get coordinates which should be in this interval. More specifically, the x coordinate in projPos should be exactly the same coordinate the vertex gets on the screen, but in the interval [-1..1]. For my gradient, I need the coordinates to be in the interval [0..1]. So I take the initial coordinates [-1..1] and add 1, to get [0..2], then I divide by 2, to get [0..1]. Is this correct? [Edited by - all_names_taken on May 6, 2007 3:54:21 AM]

Share this post


Link to post
Share on other sites
You definitely need to perform the homogeneous divide projPos.x / projPos.w first in you fragment shader. The reason it doesn't work initially is because projPos.x is relative to that fragment's depth. Recall that the standard OpenGL perspective matrix puts the inverted Z-value of a vertex in the W coordinate. Let's say that a vertex is really far away, at a distance of 1000 units from the camera, and it's at the far left of the view frustum but still inside it. In order for x/w to come out to about -1, x has to be about -1000! If this vertex were on the far right of the frustum, x would have to be about 1000. If the vertex happened to be at a distance of 10, then those numbers would be about -10 and 10. However what's important to note is that 0 is in the middle of the screen, so everything to the left is negative and everything to the right is positive. In terms of color, negative values are clamped to 0, which is why it's all black on the left side of the screen. Positive values are clamped to 1, but since the values of x are so large you can't see any of the values between 0 and 1. However when you divide by 1000 or 10000, you lower the scale of the values artificially, which allows you to see a gradient. It's slanted because the x values are still based on distance.

So yeah, try x/w. Also, you don't have to do ftransform() twice in the vertex shader. Just do it once and copy the result to a second value.

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