Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

mesh.cpp

Go to the documentation of this file.
00001 /*
00002     toxic - A Global Illumination Renderer
00003     Copyright (C) 2003-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of toxic.
00007 
00008     toxic is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     toxic is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with toxic; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "mesh.h"   // include first
00024 #include "context.h"
00025 #include "framebuffer.h"
00026 #include "icamera.h"
00027 #include "intersecttriangle.h"
00028 #include "ray.h"
00029 #include "statistics.h"
00030 #include "triboxoverlap.h"
00031 
00032 #include <cassert>
00033 #include <limits>
00034 
00035 using namespace sheep;
00036 using namespace std;
00037 using namespace toxic;
00038 
00039 Mesh::Mesh(const Matrix4 &m,
00040            const ISurfaceShader *surface_shader,
00041            IntersectionMask intersection_mask /*= INTERSECT_ALL_RAYS*/) :
00042     IAreaLight(m, surface_shader, intersection_mask),
00043     m_octree(0)
00044 {
00045 }
00046 
00047 Mesh::~Mesh() {
00048     delete m_octree;
00049 }
00050 
00051 Mesh::FeatureId Mesh::AppendVertex(const Point3 &v) {
00052     m_vertices.push_back(v);
00053 
00054     return static_cast<FeatureId>(m_vertices.size() - 1);
00055 }
00056 
00057 Mesh::FeatureId Mesh::AppendNormal(const Vector3 &n) {
00058     assert(n.IsUnitLength());
00059 
00060     m_normals.push_back(n);
00061 
00062     return static_cast<FeatureId>(m_normals.size() - 1);
00063 }
00064 
00065 Mesh::FeatureId Mesh::AppendTexCoord(const Vector2 &vt) {
00066     m_texcoords.push_back(vt);
00067 
00068     return static_cast<FeatureId>(m_texcoords.size() - 1);
00069 }
00070 
00071 Mesh::FeatureId Mesh::AppendTriangle(FeatureId v0, FeatureId v1, FeatureId v2) {
00072     triangle tri;
00073 
00074     tri.m_v0 = v0;
00075     tri.m_v1 = v1;
00076     tri.m_v2 = v2;
00077 
00078     tri.m_n0 = tri.m_n1 = tri.m_n2 = -1;    // no normals yet
00079     tri.m_t0 = tri.m_t1 = tri.m_t2 = -1;    // no texture coordinates yet
00080 
00081     m_triangles.push_back(tri);
00082 
00083     return static_cast<FeatureId>(m_triangles.size() - 1);
00084 }
00085 
00086 void Mesh::SetTriangleNormals(FeatureId tri, FeatureId n0, FeatureId n1, FeatureId n2) {
00087     assert(tri >= 0 && tri < static_cast<FeatureId>(m_triangles.size()));
00088 
00089     m_triangles[tri].m_n0 = n0;
00090     m_triangles[tri].m_n1 = n1;
00091     m_triangles[tri].m_n2 = n2;
00092 }
00093 
00094 void Mesh::SetTriangleTexCoords(FeatureId tri, FeatureId t0, FeatureId t1, FeatureId t2) {
00095     assert(tri >= 0 && tri < static_cast<FeatureId>(m_triangles.size()));
00096 
00097     m_triangles[tri].m_t0 = t0;
00098     m_triangles[tri].m_t1 = t1;
00099     m_triangles[tri].m_t2 = t2;
00100 }
00101 
00102 void Mesh::Finalize(const Context &context) {
00103     finalize_geometry();
00104 
00105     IAreaLight::Finalize(context);
00106 
00107     // Transform all vertices to world space. Normals are kept in object space.
00108     for(vertex_vector_it i = m_vertices.begin(), e = m_vertices.end(); i != e; ++i) {
00109         *i = TransformToWorld(*i);
00110     }
00111 
00112     // Minimum number of triangles to use an octree.
00113     const int TRIANGLES_THRESHOLD = 8;
00114 
00115     if(m_triangles.size() >= TRIANGLES_THRESHOLD) {
00116         m_octree = new octree();
00117 
00118         for(triangle_vector_const_it i = m_triangles.begin(), e = m_triangles.end(); i != e; ++i) {
00119             AABB3 aabb;
00120 
00121             aabb.Include(m_vertices[i->m_v0]);
00122             aabb.Include(m_vertices[i->m_v1]);
00123             aabb.Include(m_vertices[i->m_v2]);
00124 
00125             aabb.Extend(OBJECT_AABB_EXTENSION);
00126 
00127             m_octree->Insert(&(*i), aabb);
00128         }
00129 
00130         // Maximum number of subdivisions.
00131         const int MAX_SUBDIV = 6;   // at most 8^6 = 262,144 cells
00132 
00133         triangle_voxel_intersector tvi(m_vertices);
00134         m_octree->Subdivide(TRIANGLES_THRESHOLD, MAX_SUBDIV, tvi);
00135 
00136         //!\todo This is probably incorrect...
00137         m_aabb = m_octree->GetAABB();
00138     } else {
00139         assert(m_octree == 0);
00140 
00141         m_aabb.Invalidate();
00142 
00143         // Compute AABB from vertices.
00144         for(vertex_vector_const_it i = m_vertices.begin(), e = m_vertices.end(); i != e; ++i) {
00145             m_aabb.Include(*i);
00146         }
00147 
00148         // Enlarge the object bounding box to avoid numerical instabilities.
00149         m_aabb.Extend(OBJECT_AABB_EXTENSION);
00150     }
00151 }
00152 
00153 Real Mesh::ComputeSurfaceArea() const {
00154     //!\todo Implement.
00155 //  assert(!"Not implemented yet.");
00156     return 0.0;
00157 }
00158 
00159 void Mesh::EvaluateSurface(const Point2 &input,
00160                            Point3 *point,
00161                            Vector3 *geometric_normal) const
00162 {
00163     assert(point);
00164     assert(geometric_normal);
00165 
00166     //!\todo Implement.
00167     assert(!"Not implemented yet.");
00168 }
00169 
00170 bool Mesh::Intersect(const Context &context,
00171                      const Ray &ray,    //!< 'ray' is expressed in world space.
00172                      Hit *hit /*= 0*/) const
00173 {
00174     // Test whether this object intersects with this type of ray.
00175     if(!(m_intersection_mask & ray.GetType()))
00176         return false;
00177 
00178     ++context.m_statistics->m_tested_intersections;
00179 
00180     if(m_octree) {
00181         if(hit) {
00182             octree_full_visitor visitor(m_vertices, context, ray);
00183             m_octree->Trace(ray.m_origin, ray.m_direction, visitor);
00184 
00185             if(visitor.m_t < std::numeric_limits<Real>::max()) {
00186                 ++context.m_statistics->m_intersections_found;
00187 
00188                 const Real k = 1.0 - visitor.m_u - visitor.m_v;
00189 
00190                 hit->m_object = this;
00191                 hit->m_abscissa = visitor.m_t;  // world space
00192                 hit->m_geometric_normal = visitor.m_triangle->m_geometric_normal;   // object space
00193 
00194                 const Vector3 &n0 = m_normals[visitor.m_triangle->m_n0];
00195                 const Vector3 &n1 = m_normals[visitor.m_triangle->m_n1];
00196                 const Vector3 &n2 = m_normals[visitor.m_triangle->m_n2];
00197 
00198                 const Vector2 &t0 = m_texcoords[visitor.m_triangle->m_t0];
00199                 const Vector2 &t1 = m_texcoords[visitor.m_triangle->m_t1];
00200                 const Vector2 &t2 = m_texcoords[visitor.m_triangle->m_t2];
00201 
00202                 // Compute shading normal.
00203                 //!\todo Interpolate vertex normals using spherical interpolation.
00204                 hit->m_shading_normal = k * n0 + visitor.m_u * n1 + visitor.m_v * n2;
00205 
00206                 // Compute texture coordinates.
00207                 hit->m_u = k * t0.m_x + visitor.m_u * t1.m_x + visitor.m_v * t2.m_x;
00208                 hit->m_v = k * t0.m_y + visitor.m_u * t1.m_y + visitor.m_v * t2.m_y;
00209 
00210 //!\todo Hack...
00211 hit->m_u = fmod(hit->m_u, 1.0);
00212 if(hit->m_u < 0.0)
00213     hit->m_u += 1.0;
00214 
00215 hit->m_v = fmod(hit->m_v, 1.0);
00216 if(hit->m_v < 0.0)
00217     hit->m_v += 1.0;
00218 
00219                 // Normals will be made unit-length later, when absolutely necessary.
00220 
00221                 return true;
00222             } else return false;
00223         } else {
00224             octree_test_visitor visitor(m_vertices, context, ray);
00225             m_octree->Trace(ray.m_origin, ray.m_direction, visitor);
00226 
00227             if(visitor.m_found) {
00228                 ++context.m_statistics->m_intersections_found;
00229                 return true;
00230             } else return false;
00231         }
00232     } else {
00233         if(hit) {
00234             Real nearest_t = std::numeric_limits<Real>::max();
00235             Real nearest_u, nearest_v;
00236             const triangle *nearest_triangle;
00237 
00238             for(triangle_vector_const_it i = m_triangles.begin(), e = m_triangles.end(); i != e; ++i) {
00239                 const Point3 &v0 = m_vertices[i->m_v0];
00240                 const Point3 &v1 = m_vertices[i->m_v1];
00241                 const Point3 &v2 = m_vertices[i->m_v2];
00242 
00243                 Real t, u, v;
00244 
00245                 if(intersect_triangle(ray, v0, v1, v2, &t, &u, &v))
00246                     if(t > 0.0 && t < nearest_t) {
00247                         nearest_t = t;
00248                         nearest_u = u;
00249                         nearest_v = v;
00250                         nearest_triangle = &(*i);
00251                     }
00252             }
00253 
00254             if(nearest_t < std::numeric_limits<Real>::max()) {
00255                 ++context.m_statistics->m_intersections_found;
00256 
00257                 const Real k = 1.0 - nearest_u - nearest_v;
00258 
00259                 hit->m_object = this;
00260                 hit->m_abscissa = nearest_t;    // world space
00261                 hit->m_geometric_normal = nearest_triangle->m_geometric_normal; // object space
00262 
00263                 const Vector3 &n0 = m_normals[nearest_triangle->m_n0];
00264                 const Vector3 &n1 = m_normals[nearest_triangle->m_n1];
00265                 const Vector3 &n2 = m_normals[nearest_triangle->m_n2];
00266 
00267                 const Vector2 &t0 = m_texcoords[nearest_triangle->m_t0];
00268                 const Vector2 &t1 = m_texcoords[nearest_triangle->m_t1];
00269                 const Vector2 &t2 = m_texcoords[nearest_triangle->m_t2];
00270 
00271                 // Compute shading normal.
00272                 //!\todo Interpolate normals with a spherical interpolation.
00273                 hit->m_shading_normal = k * n0 + nearest_u * n1 + nearest_v * n2;
00274 
00275                 // Compute texture coordinates.
00276                 hit->m_u = k * t0.m_x + nearest_u * t1.m_x + nearest_v * t2.m_x;
00277                 hit->m_v = k * t0.m_y + nearest_u * t1.m_y + nearest_v * t2.m_y;
00278 
00279 //!\todo Hack...
00280 hit->m_u = fmod(hit->m_u, 1.0);
00281 if(hit->m_u < 0.0)
00282     hit->m_u += 1.0;
00283 
00284 hit->m_v = fmod(hit->m_v, 1.0);
00285 if(hit->m_v < 0.0)
00286     hit->m_v += 1.0;
00287 
00288                 // Normals will be made unit-length later, when absolutely necessary.
00289 
00290                 return true;
00291             } else return false;
00292         } else {
00293             for(triangle_vector_const_it i = m_triangles.begin(), e = m_triangles.end(); i != e; ++i) {
00294                 const Point3 &v0 = m_vertices[i->m_v0];
00295                 const Point3 &v1 = m_vertices[i->m_v1];
00296                 const Point3 &v2 = m_vertices[i->m_v2];
00297 
00298                 Real t, u, v;   // not used
00299 
00300                 if(intersect_triangle(ray, v0, v1, v2, &t, &u, &v))
00301                     if(t > 0.0) {
00302                         ++context.m_statistics->m_intersections_found;
00303                         return true;
00304                     }
00305             }
00306 
00307             return false;
00308         }
00309     }
00310 }
00311 
00312 namespace {
00313     void line(const ICamera *camera,
00314               Framebuffer *framebuffer,
00315               const Point3 &p0,
00316               const Point3 &p1,
00317               const Color3 &color)
00318     {
00319         int x0, y0, x1, y1;
00320 
00321         framebuffer->ConvertFromNDC(camera->Project(p0), &x0, &y0);
00322         framebuffer->ConvertFromNDC(camera->Project(p1), &x1, &y1);
00323 
00324         framebuffer->PlotLine(x0, y0, x1, y1, color);
00325     }
00326 }
00327 
00328 void Mesh::Annotate(const Context &context,
00329                     const ICamera *camera,
00330                     Framebuffer *framebuffer) const
00331 {
00332     int n = 0;
00333 
00334     for(triangle_vector_const_it i = m_triangles.begin(), e = m_triangles.end(); i != e; ++i) {
00335 //      if(n++ % 50 != 0)
00336 //          continue;
00337 
00338         const Point3 &v0 = m_vertices[i->m_v0];
00339         const Point3 &v1 = m_vertices[i->m_v1];
00340         const Point3 &v2 = m_vertices[i->m_v2];
00341 
00342         const Vector3 n0 = TransformNormalToWorld(m_normals[i->m_n0]);
00343         const Vector3 n1 = TransformNormalToWorld(m_normals[i->m_n1]);
00344         const Vector3 n2 = TransformNormalToWorld(m_normals[i->m_n2]);
00345 
00346         assert(n0.IsUnitLength());
00347         assert(n1.IsUnitLength());
00348         assert(n2.IsUnitLength());
00349 
00350         const Real SCALE = 1.0e-2;
00351         const Color3 COLOR(1.0, 0.0, 0.0);
00352 
00353 //      line(camera, framebuffer, v0, v0 + SCALE * n0, COLOR);
00354 //      line(camera, framebuffer, v1, v1 + SCALE * n1, COLOR);
00355 //      line(camera, framebuffer, v2, v2 + SCALE * n2, COLOR);
00356 
00357         const Point3 p = (v0 + v1 + v2) / 3;
00358         const Vector3 n = SCALE * (n0 + n1 + n2).Normalized();
00359 
00360         line(camera, framebuffer, p, p + 0.9 * n, COLOR);
00361         line(camera, framebuffer, p + 0.9 * n, p + n, Color3(1.0, 1.0, 0.0));
00362     }
00363 }
00364 
00365 inline
00366 Mesh::triangle::triangle()
00367 #ifdef USE_MAILBOXES
00368     : m_mailbox_ray_id(Ray::GetInvalidId())
00369 #endif  // USE_MAILBOXES
00370 {
00371 }
00372 
00373 inline
00374 bool Mesh::triangle_voxel_intersector::Intersect(const triangle *tri,
00375                                                  const AABB3 &voxel) const
00376 {
00377     assert(tri);
00378 
00379     const Point3 boxcenter = voxel.GetCenter();
00380     const Vector3 boxhalfsize = voxel.m_max - boxcenter;
00381     const Point3 &v0 = m_vertices[tri->m_v0];
00382     const Point3 &v1 = m_vertices[tri->m_v1];
00383     const Point3 &v2 = m_vertices[tri->m_v2];
00384 
00385     return tri_box_overlap(boxcenter, boxhalfsize, v0, v1, v2);
00386 }
00387 
00388 inline
00389 Mesh::octree_test_visitor::octree_test_visitor(const vertex_vector &vertices,
00390                                                const Context &context,
00391                                                const Ray &ray) :
00392     m_vertices(vertices),   
00393     m_context(context),
00394     m_ray(ray),
00395     m_found(false)
00396 {
00397 }
00398 
00399 bool Mesh::octree_test_visitor::Trace(const octree_node *node,
00400                                       Real /*t0*/, Real /*t1*/)
00401 {
00402     assert(node);
00403 
00404     for(octree_node::ItemVectorConstIt i = node->m_items.begin(), e = node->m_items.end(); i != e; ++i) {
00405         //!\todo Optimize: use a simplified routine that does not compute
00406         //! and report t, u and v, because we really don't care here.
00407 
00408         const triangle *tri = *i;
00409 
00410         const Point3 &v0 = m_vertices[tri->m_v0];
00411         const Point3 &v1 = m_vertices[tri->m_v1];
00412         const Point3 &v2 = m_vertices[tri->m_v2];
00413 
00414         Real t, u, v;   // not used
00415 
00416         if(intersect_triangle(m_ray, v0, v1, v2, &t, &u, &v))
00417             if(t > 0.0) {
00418                 m_found = true;
00419                 return true;    // terminate octree traversal
00420             }
00421     }
00422 
00423     return false;   // continue octree traversal
00424 }
00425 
00426 inline
00427 Mesh::octree_full_visitor::octree_full_visitor(const vertex_vector &vertices,
00428                                                const Context &context,
00429                                                const Ray &ray) :
00430     m_vertices(vertices),
00431     m_context(context),
00432     m_ray(ray),
00433     m_t(std::numeric_limits<Real>::max())
00434 {
00435 }
00436 
00437 bool Mesh::octree_full_visitor::Trace(const octree_node *node,
00438                                       Real t0, Real t1)
00439 {
00440     assert(node);
00441 
00442     for(octree_node::ItemVectorConstIt i = node->m_items.begin(), e = node->m_items.end(); i != e; ++i) {
00443         const triangle *tri = *i;
00444 
00445 #ifdef USE_MAILBOXES
00446         if(tri->m_mailbox_ray_id != m_ray.GetId()) {
00447 #endif  // USE_MAILBOXES
00448             const Point3 &v0 = m_vertices[tri->m_v0];
00449             const Point3 &v1 = m_vertices[tri->m_v1];
00450             const Point3 &v2 = m_vertices[tri->m_v2];
00451 
00452             Real t, u, v;
00453 
00454             if(intersect_triangle(m_ray, v0, v1, v2, &t, &u, &v)) {
00455                 if(t > 0.0 && t < m_t) {
00456                     m_t = t;
00457                     m_u = u;
00458                     m_v = v;
00459                     m_triangle = tri;
00460                 }
00461             }
00462 
00463 #ifdef USE_MAILBOXES
00464             tri->m_mailbox_ray_id = m_ray.GetId();
00465         }
00466 #endif  // USE_MAILBOXES
00467     }
00468 
00469     //!\todo Make sure the <= and >= are correct.
00470     if(m_t >= t0 && m_t <= t1)
00471         return true;    // terminate octree traversal
00472     else return false;  // continue octree traversal
00473 }
00474 
00475 void Mesh::finalize_geometry() {
00476     int dummy_tid = -1;
00477 
00478     for(triangle_vector_it i = m_triangles.begin(), e = m_triangles.end(); i != e; ++i) {
00479         triangle &tri = *i;
00480 
00481         const Point3 &v0 = m_vertices[tri.m_v0];
00482         const Point3 &v1 = m_vertices[tri.m_v1];
00483         const Point3 &v2 = m_vertices[tri.m_v2];
00484 
00485         // Compute geometric normal to the triangle surface.
00486         const Vector3 e0 = v1 - v0; // object space
00487         const Vector3 e1 = v2 - v0; // object space
00488         tri.m_geometric_normal = (e0 ^ e1).Normalized();    // object space
00489 
00490         // Set missing vertex normals.
00491         if(tri.m_n0 == -1 || tri.m_n1 == -1 || tri.m_n2 == -1) {
00492             m_normals.push_back(tri.m_geometric_normal);
00493             tri.m_n0 = tri.m_n1 = tri.m_n2 = static_cast<FeatureId>(m_normals.size() - 1);
00494         }
00495 
00496         // Set missing texture coordinates.
00497         if(tri.m_t0 == -1 || tri.m_t1 == -1 || tri.m_t2 == -1) {
00498             if(dummy_tid == -1) {
00499                 m_texcoords.push_back(Vector2(0.0));
00500                 dummy_tid = m_texcoords.size() - 1;
00501             }
00502 
00503             tri.m_t0 = tri.m_t1 = tri.m_t2 = dummy_tid;
00504         }
00505     }
00506 }

Generated on Tue May 11 01:31:51 2004 for toxic by doxygen 1.3.6