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.Clear();
00054     
00055 }
00056 
00057 PolyPrimitive *ShadowVolumeGen::GetVolume() 
00058 { 
00059     return &m_ShadowVolume; 
00060 }
00061 
00062 void ShadowVolumeGen::PolyGen(PolyPrimitive *src)
00063 {   
00064     TypedPData<dVector> *points = dynamic_cast<TypedPData<dVector>* >(src->GetDataRaw("p"));
00065     
00070     const vector<dVector> &normals = src->GetGeometricNormals();
00071     const vector<vector<int> > &connected=src->GetConnectedVerts();
00072     
00073     dMatrix &transform = src->GetState()->Transform;
00074     
00075     int stride=0;
00076     if (src->GetType()==PolyPrimitive::TRISTRIP) stride=2;
00077     if (src->GetType()==PolyPrimitive::QUADS) stride=4;
00078     if (src->GetType()==PolyPrimitive::TRILIST) stride=3;
00079     if (stride>0)
00080     {
00081         SharedEdgeContainer edges = src->GetUniqueEdges();
00082         vector<pair<dVector,dVector> > silhouette;
00083             
00084         if (src->IsIndexed())
00085         {
00086             vector<unsigned int> index = src->GetIndex();
00087             // loop over all the edges
00088             for (SharedEdgeContainer::iterator i=edges.begin(); i!=edges.end(); ++i)
00089             {
00090                 EdgeContainer sharededges = *i;
00091 
00092                 dVector lightdir = transform.transform(points->m_Data[index[sharededges.begin()->first]])-m_LightPosition;
00093                 lightdir.normalise();
00094 
00095                 if (sharededges.size()==2)
00096                 {
00097                     bool backface=false;
00098                     bool frontface=false;
00099 
00100                     EdgeContainer::iterator frontedge;
00101 
00102                     // loop over the edges shared by this one
00103                     for (EdgeContainer::iterator edge=sharededges.begin(); edge!=sharededges.end(); ++edge)
00104                     {           
00105                         // only check the first vert, as they should have 
00106                         // the same geometric normal if the poly is planar..
00107                         if (lightdir.dot(transform.transform_no_trans(normals[edge->first]))>0) 
00108                         {
00109                             frontedge=edge;
00110                             frontface=true;
00111                         }
00112                         else backface=true;
00113                     }
00114 
00115                     // if we contain both front and back facing normals (from the light's pov) 
00116                     if (backface && frontface) 
00117                     {           
00118                         silhouette.push_back(pair<dVector,dVector>(transform.transform(points->m_Data[index[frontedge->first]]),
00119                                                                    transform.transform(points->m_Data[index[frontedge->second]])));
00120                     }
00121                 }
00122             }
00123         }
00124         else
00125         {
00126             // loop over all the edges
00127             for (SharedEdgeContainer::iterator i=edges.begin(); i!=edges.end(); ++i)
00128             {
00129                 EdgeContainer sharededges = *i;
00130 
00131                 dVector lightdir = transform.transform(points->m_Data[sharededges.begin()->first])-m_LightPosition;
00132                 lightdir.normalise();
00133 
00134 
00135                 if (sharededges.size()==2)
00136                 {
00137                     bool backface=false;
00138                     bool frontface=false;
00139 
00140                     EdgeContainer::iterator frontedge;
00141 
00142                     // loop over the edges shared by this one
00143                     for (EdgeContainer::iterator edge=sharededges.begin(); edge!=sharededges.end(); ++edge)
00144                     {           
00145                         // only check the first vert, as they should have 
00146                         // the same geometric normal if the poly is planar..
00147                         if (lightdir.dot(transform.transform_no_trans(normals[edge->first]))>0) 
00148                         {
00149                             frontedge=edge;
00150                             frontface=true;
00151                         }
00152                         else backface=true;
00153                     }
00154 
00155                     // if we contain both front and back facing normals (from the light's pov) 
00156                     if (backface && frontface) 
00157                     {           
00158                         silhouette.push_back(pair<dVector,dVector>(transform.transform(points->m_Data[frontedge->first]),
00159                                                                    transform.transform(points->m_Data[frontedge->second])));
00160                     }
00161                 }
00162             }
00163         }
00164         
00165         for (vector<pair<dVector,dVector> >::iterator i=silhouette.begin();
00166              i!=silhouette.end(); i++)
00167         {
00168             AddEdge(i->first,i->second);
00169         }
00170     }
00171 }
00172 
00173 void ShadowVolumeGen::AddEdge(dVector start, dVector end)
00174 {
00175     if (m_Debug)
00176     {
00177         glDisable(GL_LIGHTING);
00178         glLineWidth(3);
00179         glBegin(GL_LINES);                  
00180             glColor3f(1,0,0);
00181             glVertex3fv(start.arr());
00182             glColor3f(0,0,1);
00183             glVertex3fv(end.arr());
00184         glEnd();
00185         glEnable(GL_LIGHTING);
00186     }
00187 
00188     m_ShadowVolume.AddVertex(dVertex(start,dVector(0,0,0),0,0));
00189     m_ShadowVolume.AddVertex(dVertex(end,dVector(0,0,0),0,0));
00190 
00191     dVector proj = end-m_LightPosition;
00192     m_ShadowVolume.AddVertex(dVertex(end+proj*m_Length,dVector(0,0,0),0,0));
00193 
00194     proj = start-m_LightPosition;
00195     m_ShadowVolume.AddVertex(dVertex(start+proj*m_Length,dVector(0,0,0),0,0));
00196 }
00197 
00199 void ShadowVolumeGen::NURBSGen(NURBSPrimitive *src)
00200 {   
00201     TypedPData<dVector> *points = dynamic_cast<TypedPData<dVector>* >(src->GetDataRaw("p"));
00202     TypedPData<dVector> *normals = dynamic_cast<TypedPData<dVector>* >(src->GetDataRaw("n"));
00203     
00204     dMatrix &transform = src->GetState()->Transform;
00205     
00206     int stride=4;
00207     
00208     // loop over all the faces
00209     for (unsigned int vert=0; vert<points->Size(); vert+=stride)
00210     {
00211         // find out if we are on an edge or not
00212         vector<int> edgeverts;
00213 
00214         for (int facevert=0; facevert<stride; facevert++)
00215         {
00216             dVector lightdir = transform.transform(points->m_Data[vert+facevert])-m_LightPosition;
00217             lightdir.normalise();
00218 
00219             bool backface=false;
00220             bool frontface=false;
00221 
00223             
00224             // loop over the verts connected to this one
00225             /*for (vector<int>::const_iterator cv=connected[vert+facevert].begin(); 
00226                 cv!=connected[vert+facevert].end(); cv++)
00227             {           
00228                 if (lightdir.dot(transform.transform_no_trans(normals->m_Data[*cv]))>0) frontface=true;
00229                 else backface=true;
00230             }*/
00231             
00232             // if we contain both front and back facing normals (from the light's pov) 
00233             if (backface && frontface) 
00234             {
00235                 edgeverts.push_back(vert+facevert);
00236             }
00237         }
00238 
00239         if (edgeverts.size()>=2)
00240         {
00241             for (unsigned int i=0; i<edgeverts.size()-1; i++)
00242             {   
00243                 dVector worldpoint1 = transform.transform(points->m_Data[edgeverts[i]]);
00244                 dVector worldpoint2 = transform.transform(points->m_Data[edgeverts[i+1]]);
00245 
00246                 glPushMatrix();
00247                 glDisable(GL_LIGHTING);
00248                 glBegin(GL_LINES);                  
00249                     glColor3f(1,0,0);
00250                     glVertex3fv(worldpoint1.arr());
00251                     glColor3f(0,0,1);
00252                     glVertex3fv(worldpoint2.arr());
00253                 glEnd();
00254                 glEnable(GL_LIGHTING);
00255                 glPopMatrix();
00256 
00257                 m_ShadowVolume.AddVertex(dVertex(worldpoint1,dVector(0,0,0),0,0));
00258                 m_ShadowVolume.AddVertex(dVertex(worldpoint2,dVector(0,0,0),0,0));
00259 
00260                 dVector proj = worldpoint2-m_LightPosition;
00261                 m_ShadowVolume.AddVertex(dVertex(worldpoint1+proj*100,dVector(0,0,0),0,0));
00262 
00263                 proj = worldpoint1-m_LightPosition;
00264                 m_ShadowVolume.AddVertex(dVertex(worldpoint2+proj*100,dVector(0,0,0),0,0));
00265             }
00266         }
00267     }
00268 }
00269 
00270 

Generated on Mon Feb 11 06:54:25 2008 for The Fluxus Renderer (libfluxus) by  doxygen 1.5.1