Shadow Volumes

I’ve been doing a simple demo to implement shadow volumes, but I think I’m doing a mistake related to the stencil buffer part (because i end up with all the screen being shadowed)

Here is the code related to the stencil buffer:

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glEnable(GL_CULL_FACE);
glEnable(GL_STENCIL_TEST);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0.0f, 100.0f);
glCullFace(GL_FRONT);
glStencilFunc(GL_ALWAYS, 0x0, 0xff);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
RS_Render_Shadow_Volume(obj,obj->poligono[i].a,obj->poligono[i].b,obj->poligono[i].c, obj->pos, luz0.pos);
glCullFace(GL_BACK);
glStencilFunc(GL_ALWAYS, 0x0, 0xff);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
RS_Render_Shadow_Volume(obj,obj->poligono[i].a,obj->poligono[i].b,obj->poligono[i].c, obj->pos, luz0.pos);
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_CULL_FACE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);

glStencilFunc(GL_NOTEQUAL, 0x0, 0xff);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
RS_Draw_Shadow();
glDisable(GL_STENCIL_TEST); 

Here is the screenshoot where you can see that the shadow volumes are right (writing the shadows to the color buffer)

OK, I solved the stencil buffer problem, I was clearing it the wrong way.

But now, although the shadow is rendered properly, I also get the back cap of the shadow volume rendered, I don’t know if you understand me, here is a ss:

Thanks in advance

This snapshot reminds me of my first shadow volume demo with the same scene as yours.

If your algorithms is “Z-Failed”, the “ghost” shadow on the left bottom is generally caused by the far clip plane of the view frustrum.

If the shadow volume is stretched too long ( e.g. the light source is far from the cube ), the back cap of the shadow volume may be clipped by the far-side clip planes and not drawn, as a result, the stencil values in this area would not be increased or decreased through this pass and the incorrect shadow will appear.

You were right, the problem was that the back cap of the shadow was too far away that it was clipped. That problem is solved.

Now I have another problem when rotating objects, as you will see in the screenshoot, the light position seems to rotate with the object, which makes the shadow volume extrude to the wrong direction. Here are both the screenshoot and the piece of code which - I think - is wrong:


// This is what I do in order to fix the light and get the position
glPushMatrix();
glLoadIdentity();
RS_Move_Obj(obj->pos[0],obj->pos[1],obj->pos[2]);
RS_Rotate_Obj(obj);
RS_Light_Fix();
glGetLightfv(GL_LIGHT0,GL_POSITION,light_pos);
glPopMatrix();
// And then when I draw the shadow volume
glPushMatrix();
RS_Move_Obj(obj->pos[0],obj->pos[1],obj->pos[2]);
RS_Rotate_Obj(obj);
// Draw
... 

Thanks in advance

in my opinion, you’d better not use ‘glGetLightfv’ to get your light position but deal with ( i mean, caculate ) it by yourself.

as you see, the light position would be transformed by the modelview matrix, the position you get from that function may not be what you have expected ( since the ‘light’ position is also translated and rotated or even scaled by the ‘model’ matrix )

Can you help me with that? I’m a begginer not only with Opengl but also with all the 3d world, coordinates, matrix and such things which are kind of new to me.

I understood that it would be better to calculate the (transformed) light position myself.

  1. If I have a light at the position (10,10,10), and I have a point in the position (1,1,1), the transofmred light position is (9,9,9)?

  2. What about rotation? if the point (1,1,1) is rotated 180º on the X axis, which is the transformed light position?

Thanks

you can define your model’s local space simplely with these :

vec3 origin;
( define its origin in world space )

mat3 axis;
( define its ortho axis, that is, its own x’, y’, z’ axis in world space with row-major )

assume a point v in the model space,
then its final position in the world space is :


  v' = v * axis + origin; 
     = ( v.x * x' + v.y * y' + v.z * z' ) + origin;

  the world space is a particular case with
  x' = ( 1, 0, 0 );
  y' = ( 0, 1, 0 );
  z' = ( 0, 0, 1 );
  origin = ( 0, 0, 0 );

and if a point w is in the world space( e.g., the light ),
its position in the local space is :


  w'' = axis * ( w - origin )
      = axis * w'  ( w' = w- origin )
      = vec3( x' * w', y' * w', z' * w' ) 
            ( here '*' is dot production )

and that is what you need.

a little complicated,
if a matrix R is orthogonalized ( like the axis ),
R * v and v * R’ will have the same result :
where R’ is R’s transpose,
and also its reverse and column-major form

so you can convert the formulas above into another forms :


  let rot = axis', then

  v' = rot * v + origin;
  w' = ( w - origin ) * rot;

  where rot is literally meanning 'rotate'

so if you want to know the rot for 180º around the X axis,
an easy way is :


    float mat[ 16 ];

    glMatrixMode( GL_MODELVIEW );
    glPushMatrix();

    glLoadIdentity();
    glRotatef( 180.0f, 0, 0 );

    glGetFloatv( GL_MODELVIEW_MATRIX, mat );
    glPopMatrix();

however, since the matrix in OpenGL is column-major,
what you actually get is ‘axis’,
and that is what we are talking about at first :slight_smile:

I’m sorry but altough I tried to understand what you are saying, I couldn’t. My knowledge about math/matrices is not that advanced (or basic hehe). I’d be grateful if you could help me a little more.

If I have a light at pos (15,10,20) and a point at pos (5,5,5) which rotates 180º around the x axis, how could I calculate the fixed light position?

If you can please help me with C code instead of math formulas.

thanks again, hope to understand how to do it this time

hi Riskz,

first, since the light position is never changed when the point is rotated, what we actually need calcualting is the light position relative to the point, and what we should do in your case is just rotating the light -180 degree around the x axis :


// dst = mat * src
void Mat3x3MultVec3( float dst[ 3 ], float mat[ 3 ][ 3 ], float src[ 3 ] ) {
    float result[3];

    result[0] = mat[0][0] * src[0] + mat[0][1] * src[1] + mat[0][2] * src[2];
    result[1] = mat[1][0] * src[0] + mat[1][1] * src[1] + mat[1][2] * src[2];
    result[2] = mat[2][0] * src[0] + mat[2][1] * src[1] + mat[2][2] * src[2];

    dst[0] = result[0];
    dst[1] = result[1];
    dst[2] = result[2];
}


// dst = src rotated around x axis
void RotateX( float dst[ 3 ], float src[ 3 ], float degree ) {
    float mat[ 3 ][ 3 ];

    float deg_to_rad, rad;
    float c, s;

    deg_to_rad = 3.14159265f / 180.0f;
    rad = degree * deg_to_rad;

    c = cosf( rad );
    s = sinf( rad );

    mat[ 0 ][ 0 ] =  1;
    mat[ 0 ][ 1 ] =  0;
    mat[ 0 ][ 2 ] =  0;

    mat[ 1 ][ 0 ] =  0;
    mat[ 1 ][ 1 ] =  c;
    mat[ 1 ][ 2 ] = -s;

    mat[ 2 ][ 0 ] =  0;
    mat[ 2 ][ 1 ] =  s;
    mat[ 2 ][ 2 ] =  c;

    Mat3x3MultVec3( dst, mat, src );
};

call ‘RotateX’ with degree = -180.0f

I LOVE YOU (sorry for the caps but i’m actually shouting)

I understood everything now, not only the code but also how matrix are used. Thank you for helping and for being so patient with me.

Thanks again