Original Post
Hi,
i'm trying to implement shadow volumes, and i've been stuck for a few days now. It works perfectly fine with simple models like cube, but if I use a complex model, it shows artifacts:

My first thought was that the volume wasn't properly generated, but after carefully inspecting the code, I can't find the error... Anyway, if someone could help, it would be great. Here is the code:
Thanks !
i'm trying to implement shadow volumes, and i've been stuck for a few days now. It works perfectly fine with simple models like cube, but if I use a complex model, it shows artifacts:

My first thought was that the volume wasn't properly generated, but after carefully inspecting the code, I can't find the error... Anyway, if someone could help, it would be great. Here is the code:
void findSilhouetteEdge( SubMesh* sm, Vector3d* lightPos, std::vector< Vertex* >& silhouette, std::vector< Face* >& facesInLight ){ int* faceInShadow = new int[ sm->getNumberOfFaces() ];; for( int j=0; j<sm->getNumberOfFaces(); j++ ) faceInShadow[ j ] = -1; for( int j=0; j<sm->getNumberOfFaces(); j++ ) { Face* f = sm->getFace( j ); if( faceInShadow[ j ] == -1 ) faceInShadow[ j ] = ( GeometryUtil::dot( *lightPos, *f->normal ) <= 0 )?true:false; if( !faceInShadow[ j ] ) { facesInLight.push_back( sm->getFace( j ) ); for( std::map< std::pair<int,int>,Face* >::const_iterator faceIt = f->neighboors.begin(); faceIt != f->neighboors.end(); ++faceIt ) { Face* neighboor = faceIt->second; if( faceInShadow[ neighboor->indexInList ] == -1 ) faceInShadow[ neighboor->indexInList ] = ( GeometryUtil::dot( *lightPos, *(neighboor->normal) ) <= 0 )?true:false; if( faceInShadow[ j ] != faceInShadow[ neighboor->indexInList ] ) { // the common edge is part of the silhouette for( int k=0; k<neighboor->getNbVertices(); k++ ) { for( int l=0; l<f->getNbVertices(); l++ ) { if( neighboor->getVertexInd(k) == f->getVertexInd(l) ) silhouette.push_back( sm->getVertex( neighboor->getVertexInd(k) ) ); } } } } } if( f->neighboors.size() < f->getNbVertices() ) { for( int l=0; l<f->getNbVertices(); l++ ) { std::pair<int,int> edge1; std::pair<int,int> edge2; if( l != f->getNbVertices()-1 ) { edge1 = std::pair<int,int>( f->getVertexInd(l), f->getVertexInd(l+1) ); edge2 = std::pair<int,int>( f->getVertexInd(l+1), f->getVertexInd(l) ); } else { edge1 = std::pair<int,int>( f->getVertexInd(l), f->getVertexInd(0) ); edge2 = std::pair<int,int>( f->getVertexInd(0), f->getVertexInd(l) ); } if( f->neighboors.find( edge1 ) == f->neighboors.end() && f->neighboors.find( edge2 ) == f->neighboors.end() ) { silhouette.push_back( sm->getVertex( edge2.first ) ); silhouette.push_back( sm->getVertex( edge2.second ) ); } } } } delete faceInShadow;}void drawSilhouetteShadowVolume( Vector3d* lightPos, std::vector< Vertex* > silhouette ){ for( int j=0; j<silhouette.size()-1; j+=2 ) { Vertex* v1 = silhouette.at( j ); Vertex* v2 = silhouette.at( j+1 ); Vector3d v1proj( ( (v1->getCoordinates().x - lightPos->x) * M_INFINITY ) + lightPos->x, ( (v1->getCoordinates().y - lightPos->y) * M_INFINITY ) + lightPos->y, ( (v1->getCoordinates().z - lightPos->z) * M_INFINITY ) + lightPos->z ); Vector3d v2proj( ( (v2->getCoordinates().x - lightPos->x) * M_INFINITY ) + lightPos->x, ( (v2->getCoordinates().y - lightPos->y) * M_INFINITY ) + lightPos->y, ( (v2->getCoordinates().z - lightPos->z) * M_INFINITY ) + lightPos->z ); glBegin(GL_QUADS); glVertex3f( v1->getCoordinates().x,v1->getCoordinates().y,v1->getCoordinates().z ); glVertex3f( v2->getCoordinates().x,v2->getCoordinates().y,v2->getCoordinates().z ); glVertex3f( v2proj.x,v2proj.y,v2proj.z ); glVertex3f( v1proj.x,v1proj.y,v1proj.z ); glEnd(); }}void drawShadowVolume( Mesh* m, Vector3d* lightPos ){ for( int i=0; i < m->getNumSubMeshes(); i++ ) { SubMesh* sm = m->getSubMesh( i ); std::vector< Vertex* > silhouette; std::vector< Face* > facesInLight; findSilhouetteEdge( sm, lightPos, silhouette, facesInLight ); if( silhouette.size() == 0 ) continue; //depth-pass glCullFace(GL_BACK); glStencilFunc(GL_ALWAYS, 0x0, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); drawSilhouetteShadowVolume( lightPos, silhouette ); glCullFace(GL_FRONT); glStencilFunc(GL_ALWAYS, 0x0, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); drawSilhouetteShadowVolume( lightPos, silhouette ); } }void Graphics::render(){ // render scene with only ambient light glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glDisable(GL_BLEND); glDepthFunc(GL_LESS); glDepthMask(GL_TRUE); glEnable(GL_COLOR_MATERIAL); glDisable(GL_LIGHT0); drawScene(); glDisable(GL_LIGHTING); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glEnable(GL_CULL_FACE); glDepthMask(GL_FALSE); glEnable(GL_STENCIL_TEST); glClear(GL_STENCIL_BUFFER_BIT); glStencilFunc(GL_ALWAYS, 0, 0); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(0.0f, 100.0f); // here we draw the shadow volumes if( shadowEnabled ) { //for each light draw shadow volumes std::map< int, Entity* > entities = sceneMgr->getEntities(); for( std::map< int, Entity* >::const_iterator it = entities.begin(); it != entities.end(); ++it ) { if( it->second->castsShadow() ) { glPushMatrix(); Mesh* m = it->second->getMesh(); drawShadowVolume( m, lightPos ); glPopMatrix(); } } } // draw lit scene glCullFace(GL_BACK); glDepthFunc(GL_LEQUAL); glEnable(GL_BLEND); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glEnable(GL_LIGHT0); glStencilFunc(GL_EQUAL, 0, 0xff); drawScene(); glDisable(GL_COLOR_MATERIAL); glDepthMask(GL_TRUE); }Thanks !