ShadowVolumeGen.cpp

Go to the documentation of this file.
00001 // Copyright (C) 2005 Dave Griffiths
00002 //
00003 // This program is free software; you can redistribute it and/or modify
00004 // it under the terms of the GNU General Public License as published by
00005 // the Free Software Foundation; either version 2 of the License, or
00006 // (at your option) any later version.
00007 //
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00016 
00017 #include <algorithm>
00018 #include "ShadowVolumeGen.h"
00019 
00020 using namespace Fluxus;
00021 
00022 ShadowVolumeGen::ShadowVolumeGen() :
00023 m_ShadowVolume(PolyPrimitive::QUADS),
00024 m_LightPosition(5,5,0),
00025 m_Length(10),
00026 m_Debug(false)
00027 {
00028 }
00029 
00030 ShadowVolumeGen::~ShadowVolumeGen() 
00031 {
00032 }
00033 
00034 void ShadowVolumeGen::Generate(Primitive *prim)
00035 {   
00036     PolyPrimitive *poly = dynamic_cast<PolyPrimitive*>(prim);
00037     if (poly)
00038     {
00039         PolyGen(poly);
00040     }
00041     else
00042     {       
00043         NURBSPrimitive *nurbs = dynamic_cast<NURBSPrimitive*>(prim);
00044         if (nurbs)
00045         {
00046             NURBSGen(nurbs);
00047         }
00048     }
00049 }
00050 
00051 void ShadowVolumeGen::Clear()
00052 { 
00053     m_ShadowVolume.Resize(0);
00054 }
00055 
00056 PolyPrimitive *ShadowVolumeGen::GetVolume() 
00057 { 
00058     return &m_ShadowVolume; 
00059 }
00060 
00061 void ShadowVolumeGen::PolyGen(PolyPrimitive *src)
00062 {   
00063     TypedPData<dVector> *points = dynamic_cast<TypedPData<dVector>* >(src->GetDataRaw("p"));
00064     
00069     const vector<dVector> &normals = src->GetGeometricNormals();
00070     const vector<vector<int> > &connected=src->GetConnectedVerts();
00071     
00072     dMatrix &transform = src->GetState()->Transform;
00073     
00074     int stride=0;
00075     if (src->GetType()==PolyPrimitive::TRISTRIP) stride=2;
00076     if (src->GetType()==PolyPrimitive::QUADS) stride=4;
00077     if (src->GetType()==PolyPrimitive::TRILIST) stride=3;
00078     if (stride>0)
00079     {
00080         SharedEdgeContainer edges = src->GetUniqueEdges();
00081         vector<pair<dVector,dVector> > silhouette;
00082             
00083         if (src->IsIndexed())
00084         {
00085             vector<unsigned int> index = src->GetIndex();
00086             // loop over all the edges
00087             for (SharedEdgeContainer::iterator i=edges.begin(); i!=edges.end(); ++i)
00088             {
00089                 EdgeContainer sharededges = *i;
00090 
00091                 dVector lightdir = transform.transform(points->m_Data[index[sharededges.begin()->first]])-m_LightPosition;
00092                 lightdir.normalise();
00093 
00094                 if (sharededges.size()==2)
00095                 {
00096                     bool backface=false;
00097                     bool frontface=false;
00098 
00099                     EdgeContainer::iterator frontedge;
00100 
00101                     // loop over the edges shared by this one
00102                     for (EdgeContainer::iterator edge=sharededges.begin(); edge!=sharededges.end(); ++edge)
00103                     {           
00104                         // only check the first vert, as they should have 
00105                         // the same geometric normal if the poly is planar..
00106                         if (lightdir.dot(transform.transform_no_trans(normals[edge->first]))>0) 
00107                         {
00108                             frontedge=edge;
00109                             frontface=true;
00110                         }
00111                         else backface=true;
00112                     }
00113 
00114                     // if we contain both front and back facing normals (from the light's pov) 
00115                     if (backface && frontface) 
00116                     {           
00117                         silhouette.push_back(pair<dVector,dVector>(transform.transform(points->m_Data[index[frontedge->first]]),
00118                                                                    transform.transform(points->m_Data[index[frontedge->second]])));
00119                     }
00120                 }
00121             }
00122         }
00123         else
00124         {
00125             // loop over all the edges
00126             for (SharedEdgeContainer::iterator i=edges.begin(); i!=edges.end(); ++i)
00127             {
00128                 EdgeContainer sharededges = *i;
00129 
00130                 dVector lightdir = transform.transform(points->m_Data[sharededges.begin()->first])-m_LightPosition;
00131                 lightdir.normalise();
00132 
00133 
00134                 if (sharededges.size()==2)
00135                 {
00136                     bool backface=false;
00137                     bool frontface=false;
00138 
00139                     EdgeContainer::iterator frontedge;
00140 
00141                     // loop over the edges shared by this one
00142                     for (EdgeContainer::iterator edge=sharededges.begin(); edge!=sharededges.end(); ++edge)
00143                     {           
00144                         // only check the first vert, as they should have 
00145                         // the same geometric normal if the poly is planar..
00146                         if (lightdir.dot(transform.transform_no_trans(normals[edge->first]))>0) 
00147                         {
00148                             frontedge=edge;
00149                             frontface=true;
00150                         }
00151                         else backface=true;
00152                     }
00153 
00154                     // if we contain both front and back facing normals (from the light's pov) 
00155                     if (backface && frontface) 
00156                     {           
00157                         silhouette.push_back(pair<dVector,dVector>(transform.transform(points->m_Data[frontedge->first]),
00158                                                                    transform.transform(points->m_Data[frontedge->second])));
00159                     }
00160                 }
00161             }
00162         }
00163         
00164         for (vector<pair<dVector,dVector> >::iterator i=silhouette.begin();
00165              i!=silhouette.end(); i++)
00166         {
00167             AddEdge(i->first,i->second);
00168         }
00169     }
00170 }
00171 
00172 void ShadowVolumeGen::AddEdge(dVector start, dVector end)
00173 {
00174     if (m_Debug)
00175     {
00176         glDisable(GL_LIGHTING);
00177         glLineWidth(3);
00178         glBegin(GL_LINES);                  
00179             glColor3f(1,0,0);
00180             glVertex3fv(start.arr());
00181             glColor3f(0,0,1);
00182             glVertex3fv(end.arr());
00183         glEnd();
00184         glEnable(GL_LIGHTING);
00185     }
00186 
00187     m_ShadowVolume.AddVertex(dVertex(start,dVector(0,0,0),0,0));
00188     m_ShadowVolume.AddVertex(dVertex(end,dVector(0,0,0),0,0));
00189 
00190     dVector proj = end-m_LightPosition;
00191     m_ShadowVolume.AddVertex(dVertex(end+proj*m_Length,dVector(0,0,0),0,0));
00192 
00193     proj = start-m_LightPosition;
00194     m_ShadowVolume.AddVertex(dVertex(start+proj*m_Length,dVector(0,0,0),0,0));
00195 }
00196 
00198 void ShadowVolumeGen::NURBSGen(NURBSPrimitive *src)
00199 {   
00200     TypedPData<dVector> *points = dynamic_cast<TypedPData<dVector>* >(src->GetDataRaw("p"));
00201     TypedPData<dVector> *normals = dynamic_cast<TypedPData<dVector>* >(src->GetDataRaw("n"));
00202     
00203     dMatrix &transform = src->GetState()->Transform;
00204     
00205     int stride=4;
00206     
00207     // loop over all the faces
00208     for (unsigned int vert=0; vert<points->Size(); vert+=stride)
00209     {
00210         // find out if we are on an edge or not
00211         vector<int> edgeverts;
00212 
00213         for (int facevert=0; facevert<stride; facevert++)
00214         {
00215             dVector lightdir = transform.transform(points->m_Data[vert+facevert])-m_LightPosition;
00216             lightdir.normalise();
00217 
00218             bool backface=false;
00219             bool frontface=false;
00220 
00222             
00223             // loop over the verts connected to this one
00224             /*for (vector<int>::const_iterator cv=connected[vert+facevert].begin(); 
00225                 cv!=connected[vert+facevert].end(); cv++)
00226             {           
00227                 if (lightdir.dot(transform.transform_no_trans(normals->m_Data[*cv]))>0) frontface=true;
00228                 else backface=true;
00229             }*/
00230             
00231             // if we contain both front and back facing normals (from the light's pov) 
00232             if (backface && frontface) 
00233             {
00234                 edgeverts.push_back(vert+facevert);
00235             }
00236         }
00237 
00238         if (edgeverts.size()>=2)
00239         {
00240             for (unsigned int i=0; i<edgeverts.size()-1; i++)
00241             {   
00242                 dVector worldpoint1 = transform.transform(points->m_Data[edgeverts[i]]);
00243                 dVector worldpoint2 = transform.transform(points->m_Data[edgeverts[i+1]]);
00244 
00245                 glPushMatrix();
00246                 glDisable(GL_LIGHTING);
00247                 glBegin(GL_LINES);                  
00248                     glColor3f(1,0,0);
00249                     glVertex3fv(worldpoint1.arr());
00250                     glColor3f(0,0,1);
00251                     glVertex3fv(worldpoint2.arr());
00252                 glEnd();
00253                 glEnable(GL_LIGHTING);
00254                 glPopMatrix();
00255 
00256                 m_ShadowVolume.AddVertex(dVertex(worldpoint1,dVector(0,0,0),0,0));
00257                 m_ShadowVolume.AddVertex(dVertex(worldpoint2,dVector(0,0,0),0,0));
00258 
00259                 dVector proj = worldpoint2-m_LightPosition;
00260                 m_ShadowVolume.AddVertex(dVertex(worldpoint1+proj*100,dVector(0,0,0),0,0));
00261 
00262                 proj = worldpoint1-m_LightPosition;
00263                 m_ShadowVolume.AddVertex(dVertex(worldpoint2+proj*100,dVector(0,0,0),0,0));
00264             }
00265         }
00266     }
00267 }
00268 
00269 

Generated on Tue Sep 4 23:22:18 2007 for The Fluxus Renderer (libfluxus) by  doxygen 1.5.1