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
1.5.6