00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "mesh.h"
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 ) :
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;
00079 tri.m_t0 = tri.m_t1 = tri.m_t2 = -1;
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
00108 for(vertex_vector_it i = m_vertices.begin(), e = m_vertices.end(); i != e; ++i) {
00109 *i = TransformToWorld(*i);
00110 }
00111
00112
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
00131 const int MAX_SUBDIV = 6;
00132
00133 triangle_voxel_intersector tvi(m_vertices);
00134 m_octree->Subdivide(TRIANGLES_THRESHOLD, MAX_SUBDIV, tvi);
00135
00136
00137 m_aabb = m_octree->GetAABB();
00138 } else {
00139 assert(m_octree == 0);
00140
00141 m_aabb.Invalidate();
00142
00143
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
00149 m_aabb.Extend(OBJECT_AABB_EXTENSION);
00150 }
00151 }
00152
00153 Real Mesh::ComputeSurfaceArea() const {
00154
00155
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
00167 assert(!"Not implemented yet.");
00168 }
00169
00170 bool Mesh::Intersect(const Context &context,
00171 const Ray &ray,
00172 Hit *hit ) const
00173 {
00174
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;
00192 hit->m_geometric_normal = visitor.m_triangle->m_geometric_normal;
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
00203
00204 hit->m_shading_normal = k * n0 + visitor.m_u * n1 + visitor.m_v * n2;
00205
00206
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
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
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;
00261 hit->m_geometric_normal = nearest_triangle->m_geometric_normal;
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
00272
00273 hit->m_shading_normal = k * n0 + nearest_u * n1 + nearest_v * n2;
00274
00275
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
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
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;
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
00336
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
00354
00355
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
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 , Real )
00401 {
00402 assert(node);
00403
00404 for(octree_node::ItemVectorConstIt i = node->m_items.begin(), e = node->m_items.end(); i != e; ++i) {
00405
00406
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;
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;
00420 }
00421 }
00422
00423 return false;
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
00470 if(m_t >= t0 && m_t <= t1)
00471 return true;
00472 else return false;
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
00486 const Vector3 e0 = v1 - v0;
00487 const Vector3 e1 = v2 - v0;
00488 tri.m_geometric_normal = (e0 ^ e1).Normalized();
00489
00490
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
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 }