Mesh.cpp

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   Mesh.cpp
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @author Nong Li (nongli@gmail.com)
00005    @date   Spring 2008
00006    
00007    @brief
00008       Representation of a triangular mesh stored in the obj format.
00009    It consists of a list of vertices's and a list of faces that contain
00010    indices in the vertex list.
00011    <!-------------------------------------------------------------------->**/
00012 
00013 #include "Mesh.h"
00014 #include <SurfacePoint.h>
00015 #include <kdTreeAccel.h>
00016 #include <NaiveSpatialAccel.h>
00017 #include <ResourceManager.h>
00018 #include <Random.h>
00019 #include <QtCore>
00020 
00021 #include <strings.h>
00022 #include <values.h>
00023 #include <float.h>
00024 
00025 // converts a random real inbetween 0 and 1 into a valid triangle index
00026 #define MESH_GET_INDEX(u)  (MIN((unsigned)floor((u) * m_nTriangles), m_nTriangles - 1))
00027 
00028 /* Constructs a mesh out of the specified MeshData */
00029 Mesh::Mesh(const MeshData &data) {
00030    m_nVertices    = data.vertices.size();
00031    m_nNormals     = data.normals.size();
00032    m_nUVs         = data.uvs.size();
00033    m_nTriangles   = data.triangles.size();
00034    
00035    ASSERT(m_nVertices > 0);
00036    ASSERT(m_nTriangles > 0);
00037    ASSERT(m_nUVs >= 0);
00038    
00039    m_vertices     = new Vertex[m_nVertices];
00040    m_normals      = new Normal[m_nNormals];
00041    m_uvs          = new UV[m_nUVs];
00042    m_triangles    = new MeshTriangle[m_nTriangles];
00043    
00044    // TODO: heuristic for choosing MeshTriangle or MeshTriangleFast
00045    //if (m_nTriangles > (1 << 15)) {
00046    //   m_triangles = new MeshTriangle[m_nTriangles];
00047    //} else {
00048    //   m_triangles = new MeshTriangleFast[m_nTriangles];
00049    //}
00050    
00051    /* Copy data over from other mesh */
00052    if (m_nVertices > 0)
00053       memcpy(m_vertices,  &data.vertices[0],  sizeof(Vertex)       * m_nVertices);
00054    if (m_nNormals > 0)
00055       memcpy(m_normals,   &data.normals[0],   sizeof(Normal)       * m_nNormals);
00056    if (m_nUVs > 0)
00057       memcpy(m_uvs,       &data.uvs[0],       sizeof(UV)           * m_nUVs);
00058    if (m_nTriangles > 0)
00059       memcpy(m_triangles, &data.triangles[0], sizeof(MeshTriangle) * m_nTriangles);
00060    
00061    /*for(unsigned i = m_nVertices; i--;)
00062       m_vertices[i] = data.vertices[i];
00063    for(unsigned i = m_nNormals; i--;)
00064       m_normals[i] = data.normals[i];
00065    for(unsigned i = m_nUVs; i--;)
00066       m_uvs[i] = data.uvs[i];*/
00067    
00068    for(unsigned i = m_nTriangles; i--;) {
00069       //m_triangles[i] = data.triangles[i];
00070       m_triangles[i].mesh = this;
00071       
00072       /*if (m_triangles[i].A >= m_nVertices)
00073          cerr << i << ", A, " << m_triangles[i].A << endl;
00074       if (m_triangles[i].B >= m_nVertices)
00075          cerr << i << ", B, " << m_triangles[i].B << endl;
00076       if (m_triangles[i].C >= m_nVertices)
00077          cerr << i << ", C, " << m_triangles[i].C << endl;*/
00078       
00079       ASSERT(m_triangles[i].A < m_nVertices);
00080       ASSERT(m_triangles[i].B < m_nVertices);
00081       ASSERT(m_triangles[i].C < m_nVertices);
00082       
00083       if (m_nNormals > 0) {
00084          ASSERT(m_triangles[i].nA < m_nNormals);
00085          ASSERT(m_triangles[i].nB < m_nNormals);
00086          ASSERT(m_triangles[i].nC < m_nNormals);
00087       }
00088       if (m_nUVs > 0) {
00089          ASSERT(m_triangles[i].tA < m_nUVs);
00090          ASSERT(m_triangles[i].tB < m_nUVs);
00091          ASSERT(m_triangles[i].tC < m_nUVs);
00092       }
00093    }
00094    
00095    if (0 == m_nNormals)
00096       computeNormals();
00097    
00098    m_batch        = 0;
00099    m_spatialAccel = NULL;
00100 }
00101 
00102 Mesh::Mesh(unsigned nVertices, unsigned nNormals, unsigned nUVs, 
00103            unsigned nTriangles)
00104 {
00105    ASSERT(nVertices > 0);
00106    ASSERT(nTriangles > 0);
00107    ASSERT(nUVs >= 0);  
00108    
00109    m_nVertices    = nVertices;
00110    m_nNormals     = nNormals;
00111    m_nUVs         = nUVs;
00112    m_nTriangles   = nTriangles;
00113    
00114    m_vertices     = new Vertex[m_nVertices];
00115    m_normals      = new Normal[m_nNormals];
00116    m_uvs          = new UV[m_nUVs];
00117    m_triangles    = new MeshTriangle[m_nTriangles];
00118    
00119    for(unsigned i = m_nTriangles; i--;) {
00120       m_triangles[i].mesh = this;
00121       
00122       ASSERT(m_triangles[i].A < m_nVertices);
00123       ASSERT(m_triangles[i].B < m_nVertices);
00124       ASSERT(m_triangles[i].C < m_nVertices);
00125       
00126       if (m_nNormals > 0) {
00127          ASSERT(m_triangles[i].nA < m_nNormals);
00128          ASSERT(m_triangles[i].nB < m_nNormals);
00129          ASSERT(m_triangles[i].nC < m_nNormals);
00130       }
00131       if (m_nUVs > 0) {
00132          ASSERT(m_triangles[i].tA < m_nUVs);
00133          ASSERT(m_triangles[i].tB < m_nUVs);
00134          ASSERT(m_triangles[i].tC < m_nUVs);
00135       }
00136    }
00137    
00138    if (0 == m_nNormals)
00139       computeNormals();
00140    
00141    m_batch        = 0;
00142    m_spatialAccel = NULL;
00143 }
00144 
00145 /* Copy constructor; does not copy kd-Trees or texture */
00146 Mesh::Mesh(const Mesh &mesh) {
00147    m_nVertices    = mesh.m_nVertices;
00148    m_nNormals     = mesh.m_nNormals;
00149    m_nUVs         = mesh.m_nUVs;
00150    m_nTriangles   = mesh.m_nTriangles;      
00151    
00152    m_vertices     = new Vertex[m_nVertices];
00153    m_normals      = new Normal[m_nNormals];
00154    m_uvs          = new UV[m_nUVs];
00155    m_triangles    = new MeshTriangle[m_nTriangles];
00156    
00157    /* Copy data over from other mesh */
00158    memcpy(m_vertices,  mesh.m_vertices,  sizeof(Vertex)       * m_nVertices);
00159    memcpy(m_normals,   mesh.m_normals,   sizeof(Normal)       * m_nNormals);
00160    memcpy(m_uvs,       mesh.m_uvs,       sizeof(UV)           * m_nUVs);
00161    memcpy(m_triangles, mesh.m_triangles, sizeof(MeshTriangle) * m_nTriangles);
00162    
00163    for(unsigned i = m_nTriangles; i--;) {
00164       m_triangles[i].mesh = this;
00165       
00166       ASSERT(m_triangles[i].A < m_nVertices);
00167       ASSERT(m_triangles[i].B < m_nVertices);
00168       ASSERT(m_triangles[i].C < m_nVertices);
00169       
00170       if (m_nNormals > 0) {
00171          ASSERT(m_triangles[i].nA < m_nNormals);
00172          ASSERT(m_triangles[i].nB < m_nNormals);
00173          ASSERT(m_triangles[i].nC < m_nNormals);
00174       }
00175       if (m_nUVs > 0) {
00176          ASSERT(m_triangles[i].tA < m_nUVs);
00177          ASSERT(m_triangles[i].tB < m_nUVs);
00178          ASSERT(m_triangles[i].tC < m_nUVs);
00179       }
00180    }
00181    
00182    m_batch        = 0;
00183    m_spatialAccel = NULL;
00184    
00185    inherit(mesh);
00186 }
00187 
00188 Mesh::~Mesh() {
00189    safeDeleteArray(m_vertices);
00190    safeDeleteArray(m_normals);
00191    safeDeleteArray(m_uvs);
00192    safeDeleteArray(m_triangles);
00193    
00194    safeDelete(m_spatialAccel);
00195    
00196    if (m_batch != 0)
00197       glDeleteLists(m_batch, 1);
00198 }
00199 
00200 void Mesh::init(bool forceUpdate) {
00201    if (forceUpdate) {
00202       setPreviewDirty();
00203       safeDelete(m_spatialAccel);
00204    }
00205    
00206    init();
00207 }
00208 
00209 void Mesh::init() {
00210    ASSERT(m_material);
00211    
00212    if (NULL == m_spatialAccel) {
00213       for(unsigned i = 0; i < m_nTriangles; ++i) {
00214          m_triangles[i].init();
00215          
00216          ASSERT(m_triangles[i].getAABB().isValid());
00217       }
00218       
00219       const std::string &accelType = getValue<std::string>("spatialAccel", 
00220                                                            "kdTree");
00221       
00222       IntersectableList *primitives = new IntersectableList(m_nTriangles);
00223       for(unsigned i = m_nTriangles; i--;)
00224          (*primitives)[i] = static_cast<Intersectable*>(&m_triangles[i]);
00225       
00226       if (accelType == "kdTree") {
00227          m_spatialAccel = new kdTreeAccel();
00228       } else {
00229          ASSERT(accelType == "naive");
00230          
00231          m_spatialAccel = new NaiveSpatialAccel();
00232       }
00233       
00234       m_spatialAccel->setGeometry(primitives);
00235       m_spatialAccel->inherit(*this);
00236       m_spatialAccel->init();
00237       
00238       m_objSpaceAABB = m_spatialAccel->getAABB();
00239       
00240       // transform AABB into parent coordinate system
00241       Transformable::init();
00242       
00243       //ResourceManager::log.info << "Mesh: " << m_aabb << endl;
00244    }
00245 }
00246 
00247 void Mesh::preview() {
00248    /*GLreal_t data[16];
00249    glGetDoublev(GL_MODELVIEW_MATRIX, data);
00250    Matrix4x4 m = Matrix4x4(data).getTranspose();
00251    cerr << m << endl;*/
00252    
00253    //glDisable(GL_CULL_FACE);
00254    //glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
00255    
00256    bool enableAccelPreview = 
00257       ResourceManager::getValue<bool>("enableAccelPreview", true);
00258    bool flush = ((enableAccelPreview != m_enableAccelPreview) || 
00259                  ResourceManager::getValue<bool>("flushPreview", false));
00260    
00261    Transformable::preview();
00262       
00263    if (m_batch == 0 || flush) {
00264       if (m_batch != 0)
00265          glDeleteLists(m_batch, 1);
00266       
00267       m_batch = glGenLists(1);
00268       m_enableAccelPreview = enableAccelPreview;
00269       
00270       glNewList(m_batch, GL_COMPILE_AND_EXECUTE);
00271       
00272       if (m_enableAccelPreview && m_spatialAccel) {
00273          m_spatialAccel->preview();
00274       } else {
00275 #ifdef DEBUG
00276          m_objSpaceAABB.preview();
00277 #endif
00278       }
00279       
00280       glBegin(GL_TRIANGLES);
00281       
00282       for(unsigned i = m_nTriangles; i--;) {
00283          const MeshTriangle &tri = m_triangles[i];
00284          
00285          glNormal3real_tv(m_normals[tri.nA].data);
00286          glTexCoord2real_tv(m_uvs[tri.tA].data);
00287          glVertex3real_tv(m_vertices[tri.A].data);
00288          
00289          glNormal3real_tv(m_normals[tri.nB].data);
00290          glTexCoord2real_tv(m_uvs[tri.tB].data);
00291          glVertex3real_tv(m_vertices[tri.B].data);
00292          
00293          glNormal3real_tv(m_normals[tri.nC].data);
00294          glTexCoord2real_tv(m_uvs[tri.tC].data);
00295          glVertex3real_tv(m_vertices[tri.C].data);
00296       }
00297       
00298       /*glEnable(GL_VERTEX_ARRAY);
00299       glVertexPointer(3, GL_DOUBLE, 0, m_vertices);
00300       
00301       if (m_nNormals > 0) {
00302          glEnable(GL_NORMAL_ARRAY);
00303          glNormalPointer(GL_DOUBLE, 0, m_normals);
00304       }
00305       
00306       if (m_nUVs > 0) {
00307          glEnable(GL_TEXTURE_COORD_ARRAY);
00308          glTexCoordPointer(2, GL_DOUBLE, 0, m_uvs);
00309       }
00310       
00311       // won't work because triangle indices aren't consecutive in memory
00312       // (MeshTrianles)
00313       glDrawElements(GL_TRIANGLES, m_nTriangles, GL_UNSIGNED_INT, m_triangles);*/
00314       
00315       glEnd();
00316       glEndList();
00317    } else {
00318       glCallList(m_batch);
00319    }
00320 }
00321 
00322 /* Computes the normals.  The vertex positions should be set.  The normals
00323  * will be averaged (Gouraud Shading) */
00324 void Mesh::computeNormals() {
00325    /*bool *normalFlip = new bool[m_nTriangles * 3];
00326    
00327    for (unsigned i = 0; i < m_nTriangles; i++) {
00328       const Vector3 &normal = m_triangles[i].getNormal(pt);
00329       const Vector3 &nA = m_normals[m_triangles[i].nA];
00330       const Vector3 &nB = m_normals[m_triangles[i].nB];
00331       const Vector3 &nC = m_normals[m_triangles[i].nC];
00332       normalFlip[i*3 + 0] = normal.dot(nA) < 0;
00333       normalFlip[i*3 + 1] = normal.dot(nB) < 0;
00334       normalFlip[i*3 + 2] = normal.dot(nC) < 0;
00335    }*/
00336    
00337    Normal *normals = new Normal[m_nVertices];
00338    m_nNormals = m_nVertices;
00339    
00340    for(unsigned i = 0; i < m_nTriangles; i++) {
00341       unsigned v1 = m_triangles[i].A;
00342       unsigned v2 = m_triangles[i].B;
00343       unsigned v3 = m_triangles[i].C;
00344       
00345       m_triangles[i].nA = v1;
00346       m_triangles[i].nB = v2;
00347       m_triangles[i].nC = v3;
00348       
00349       const Vector3 &normal = m_triangles[i].getNormal();
00350       
00351       normals[v1] += normal;
00352       normals[v2] += normal;
00353       normals[v3] += normal;
00354    }
00355    
00356    for(unsigned i = 0; i < m_nNormals; i++)
00357       normals[i].normalize();
00358    
00359    Normal *oldNormals = m_normals;
00360    m_normals = normals;
00361    safeDeleteArray(oldNormals);
00362    
00363    //safeDeleteArray(normalFlip);
00364 }
00365 
00366 real_t Mesh::getIntersection(const Ray &ray, SurfacePoint &pt) {
00367    ASSERT(m_spatialAccel);
00368    
00369    // TODO: creating a new Ray here is rather inefficient...
00370    Point3  P;
00371    Vector3 D;
00372    _transformRayWorldToObj(ray, P, D);
00373    
00374    real_t retVal = m_spatialAccel->getIntersection(Ray(P, D), pt);
00375    
00376    if (Ray::isValid(retVal)) {
00377       ASSERT(pt.index < m_nTriangles);
00378       pt.shape = this;
00379    }
00380    
00381    return retVal;
00382 }
00383 
00384 bool Mesh::intersects(const Ray &ray, real_t tMax) {
00385    ASSERT(m_spatialAccel);
00386    
00387    // TODO: creating a new Ray here is rather inefficient...
00388    Point3  P;
00389    Vector3 D;
00390    _transformRayWorldToObj(ray, P, D);
00391    
00392    return m_spatialAccel->intersects(Ray(P, D), tMax);
00393 }
00394 
00395 void Mesh::_getUV(SurfacePoint &pt) const {
00396    ASSERT(pt.index < m_nTriangles);
00397    
00398    if (m_nUVs > 0) {
00399       const UV &uv = m_uvs[m_triangles[pt.index].tA];
00400       // TODO: not fully implemented!
00401       
00402       pt.uv = uv;
00403    }
00404 }
00405 
00406 void Mesh::_getGeometricNormal(SurfacePoint &pt) const {
00407    ASSERT(pt.index < m_nTriangles);
00408    
00409    Point3 P;
00410    _transformPoint3WorldToObj(pt.position, P);
00411    
00412    const MeshTriangle &tri = m_triangles[pt.index];
00413    const Vector3 &coords   = tri.getBaryocentricCoords(P);
00414    const Normal &n = (coords[0] * m_normals[tri.nA] + 
00415                       coords[1] * m_normals[tri.nB] + 
00416                       coords[2] * m_normals[tri.nC]);
00417    
00418    _transformVector3ObjToWorld(n, pt.normalG);
00419    //_transformVector3ObjToWorld(m_triangles[pt.index].getNormal(), pt.normalG);
00420 }
00421 
00422 void Mesh::getPoint(SurfacePoint &pt, const UV &uv) {
00423    pt.index = MESH_GET_INDEX(uv.u);
00424    ASSERT(pt.index < m_nTriangles);
00425    
00426    Transformable::getPoint(pt, uv);
00427 }
00428 
00429 Point3 Mesh::getPosition(const UV &uv) {
00430    // uv.u determines which triangle
00431    const unsigned index = MESH_GET_INDEX(uv.u);
00432    
00433    return m_transToWorld * 
00434       m_triangles[index].getPosition(UV(Random::sample(0, 1), uv.v));
00435 }
00436 
00437 real_t Mesh::_getSurfaceArea() {
00438    real_t area = 0;
00439    
00440    // TODO: calculate this in world-space
00441    for(unsigned i = m_nTriangles; i--;) {
00442       const MeshTriangle &t = m_triangles[i];
00443       
00444       const Vertex &v1 = m_transToWorld * m_vertices[t.A];
00445       const Vertex &v2 = m_transToWorld * m_vertices[t.B];
00446       const Vertex &v3 = m_transToWorld * m_vertices[t.C];
00447       
00448       area += (v2 - v1).cross(v3 - v1).getMagnitude();
00449    }
00450    
00451    return 0.5 * area;
00452 }
00453 
00454 void Mesh::setPreviewDirty() {
00455    GLuint batch = m_batch;
00456    m_batch = 0;
00457    
00458    if (batch != 0)
00459       glDeleteLists(batch, 1);
00460 }
00461 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6