Dane Larsen
Dane Larsen

Reputation: 1594

GLSL - Computing screen coordinates from world coordinates not working properly

I just implemented the "god-ray" shader from nVidia's lovely GPU Gems 3 book: Volumetric Light Scattering as a Post-Process.

Anyway, it's almost perfect, except for one flaw. Somehow the position of the light is not being moved with the rest of the scene.

Picture examples:

This looks exactly as it should.

enter image description here

This does not. The light should be radiating outward from the white sphere, but it looks like the position hasn't changed from the first picture.

enter image description here

I'm doing the transformations in the vertex shader:

uniform vec4 light_coords;
varying vec2 light_pos;

void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;
    light_pos = vec2(gl_ModelViewProjectionMatrix * light_coords) * 0.5 + 0.5;
}

Is this correct?

The position of the light in world coordinates is (0, 0, -2) It's entirely possible that the error is somewhere else in the code, but I wanted to make sure my calculations in the vertex shader were correct before diving into the rest of it.

EDIT: I made some changes based on what Nicol Bolas suggested below, and it's better, but still not right.

It still looks fine when the camera is at its original position, but when I rotate the scene, it looks as though the calculated light position is now too far to the left.

enter image description here

Here's the GLSL code I'm using:

uniform vec4 light_coords;
uniform mat4 light_modelview;
varying vec2 light_pos;

void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;
    light_pos = vec2(gl_ProjectionMatrix * light_modelview * light_coords) * 0.5 + 0.5;
}

light_modelview is obtained here:

glPushMatrix()
glTranslatef(self.position[0], self.position[1], self.position[2])
glScalef(2, 2, 2)       
self.modelview = glGetFloatv(GL_MODELVIEW_MATRIX)
glCallList(self.sphere) 
glLightfv(self.light_id, GL_POSITION, self.position)
glPopMatrix()

position is [0, 0, -2]. It's passed into the shader as light_coords

Ideally, I'd like light_pos to be anywhere in (0, 0) to (1, 1) if it's on the screen, and greater or less than that if it's off the screen.

Any clue what I'm doing wrong? I'm still kinda new to OpenGL, so I'm a little unsure what does what.

Upvotes: 3

Views: 2158

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 473407

If light_coords is in world space, then multiplying it by the gl_ModelViewProjectionMatrix only makes sense if gl_Vertex is also in world space. Somehow, I doubt that it is.

In general, you don't pass light directions or whatever light_coords is supposed to be in world space. You pass it in view space. You transform from world space to view space on the CPU, and you put the view space coordinates in the shader.

Upvotes: 4

Related Questions