views:

433

answers:

1

I'm writing a game using OpenGL and I am trying to implement shadow volumes.

I want to construct the shadow volume of a model on the GPU via a vertex shader. To that end, I represent the model with a VBO where:

  • Vertices are duplicated such that each triangle has its own unique three vertices
  • Each vertex has the normal of its triangle
    • For reasons I'm not going to get into, I was actually doing the above two points anyway, so I'm not too worried about the vertex duplication
  • Degenerate triangles are added to form quads inside the edges between each pair of "regular" triangles

Using this model format, inside the vertex shader I am able to find vertices that are part of triangles that face away from the light and move them back to form the shadow volume.

What I have left to figure out is what transformation exactly I should apply to the back-facing vertices.

I am able to detect when a vertex is facing away from the light, but I am unsure what transformation I should apply to it. This is what my vertex shader looks like so far:

uniform vec3 lightDir; // Parallel light.
                       // On the CPU this is represented in world
                       // space.  After setting the camera with
                       // gluLookAt, the light vector is multiplied by
                       // the inverse of the modelview matrix to get
                       // it into eye space (I think that's what I'm
                       // working in :P ) before getting passed to
                       // this shader.

void main()
{
    vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
    vec3 realLightDir = normalize(lightDir);

    float dotprod = dot(eyeNormal, realLightDir);

    if (dotprod <= 0.0)
    {
        // Facing away from the light
        // Need to translate the vertex along the light vector to
        // stretch the model into a shadow volume

        //---------------------------------//
        // This is where I'm getting stuck //
        //---------------------------------//
        // All I know is that I'll probably turn realLightDir into a
        // vec4

        gl_Position = ???;
    }
    else
    {
        gl_Position = ftransform();
    }
}

I've tried simply setting gl_position to ftransform() - (vec4(realLightDir, 1.0) * someConstant), but this caused some kind of depth-testing bugs (some faces seemed to be visible behind others when I rendered the volume with colour) and someConstant didn't seem to affect how far the back-faces are extended.

Update - Jan. 22

Just wanted to clear up questions about what space I'm probably in. I must say that keeping track of what space I'm in is the greatest source of my shader headaches.

When rendering the scene, I first set up the camera using gluLookAt. The camera may be fixed or it may move around; it should not matter. I then use translation functions like glTranslated to position my model(s).

In the program (i.e. on the CPU) I represent the light vector in world space (three floats). I've found during development that to get this light vector in the right space of my shader I had to multiply it by the inverse of the modelview matrix after setting the camera and before positioning the models. So, my program code is like this:

  • Position camera (gluLookAt)
  • Take light vector, which is in world space, and multiply it by the inverse of the current modelview matrix and pass it to the shader
  • Transformations to position models
  • Drawing of models

Does this make anything clearer?

+1  A: 

the ftransform result is in clip-space. So this is not the space you want to apply realLightDir in. I'm not sure which space your light is in (your comment confuses me), but what is sure is that you want to add vectors that are in the same space.

On the CPU this is represented in world space. After setting the camera with gluLookAt, the light vector is multiplied by the inverse of the modelview matrix to get it into eye space (I think that's what I'm working in :P ) before getting passed to this shader.

multiplying a vector by the inverse of the mv matrix brings the vector from view space to model space. so you're saying your light-vector (in world space), is applied a transform that does view->model. It makes little sense to me.

We have 4 spaces:

  • model space: the space where your gl_Vertex is defined in.
  • world space: a space that GL does not care about in general, that represents an arbitrary space to locate the models in. It's usually what the 3d engine works in (it maps to our general understanding of world coordinates).
  • view space: a space that corresponds to the referencial of the viewer. 0,0,0 is where the viewer is, looking down Z. Obtained by multiplying gl_Vertex by the modelview
  • clip space: the magic space that the matrix projection brings us in. result of ftransform is in this space (so is gl_ModelViewProjectionMatrix * gl_Vertex )

Can you clarify exactly which space your light direction is in ?

What you need to do, however, is make the light vector addition in either model, world or view space: Bring all the bits of your operation in the same space. E.g. for model space, just compute the light direction in model space on CPU, and do a:

vec3 vertexTemp = gl_Vertex + lightDirInModelSpace * someConst

then you can bring that new vertex position in clip space with

gl_Position = gl_ModelViewProjectionMatrix * vertexTemp

Last bit, don't try to apply vector additions in clip-space. It won't generally do what you think it should do, as at that point you are necessarily dealing with homogeneous coordinates with non-uniform w.

Bahbar
I updated my question to try to explain what space my light, shader, etc. is in. I *think* my light vector is in model space. At the very least, the dot product test is giving what I think are correct results. I tried following your advice and set the position of a back-facing vertex like this: "gl_ModelViewProjectionMatrix * (gl_Vertex - vec4(lightDir, 0.0));" However, the extrusion seems to follow the rotation of the model, and there still seems to be some glitch polygons as you can see at http://yfrog.com/b6ship1px (compare to the actual model at http://yfrog.com/3orealship1px).
Coyote
well, it does sound like you did not put the light direction in model space.
Bahbar