MeshTriangle.cpp

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   MeshTriangle.cpp
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @author Nong Li (nongli@gmail.com)
00005    @date   Spring 2008
00006    
00007    @brief
00008       Basic representation of a MeshTriangle with optional UV coordinates
00009    @see also Triangle.h which defines a Triangle class which derives from 
00010       Shape and differs from MeshTriangle in that it is a standalone Shape 
00011       and doesn't depend on a parent Mesh to exist
00012    <!-------------------------------------------------------------------->**/
00013 
00014 #include "MeshTriangle.h"
00015 #include "Mesh.h"
00016 
00017 #include <SurfacePoint.h>
00018 #include <Random.h>
00019 #include <Ray.h>
00020 
00021 
00022 #if (1 == MESH_TRIANGLE_INTERSECTION_TYPE)
00023 // Taken from chapter 5 of Real Time Collision Detection
00024 // TODO: optimize!!
00025 
00026 // 4 dot, 2 cross, 1 sub, 1 negation
00027 real_t MeshTriangle::getIntersection(const Ray &ray, SurfacePoint &pt) {
00028    const Vertex *vertices = mesh->getVertices();
00029    const Vertex   &a = vertices[A];
00030    const Vertex   &b = vertices[B];
00031    const Vertex   &c = vertices[C];
00032    const Vector3 &ab = b - a;
00033    const Vector3 &ac = c - a;
00034    
00035    const Point3 &origin     = ray.origin;
00036    const Vector3 &direction = -ray.direction;
00037    
00038    // Compute triangle normal. Can be precalculated or cached if
00039    // intersecting multiple segments against the same triangle
00040    const Vector3 &n = ab.cross(ac);
00041    
00042    // Compute denominator d. If d <= 0, segment is parallel to or points
00043    // away from triangle, so exit early
00044    const real_t d = direction.dot(n);
00045    if (d <= 0.0)
00046       return INFINITY;
00047    
00048    // Compute intersection t value of pq with plane of triangle. A ray
00049    // intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
00050    // dividing by d until intersection has been found to pierce triangle
00051    const Vector3 ap(origin[0] - a[0], origin[1] - a[1], origin[2] - a[2]);
00052    real_t t = ap.dot(n);
00053    if (t < 0.0)
00054       return INFINITY;
00055    
00056    // Compute barycentric coordinate components and test if within bounds
00057    const Vector3 &e = direction.cross(ap);
00058    real_t v = ac.dot(e);
00059    if (v < 0.0 || v > d)
00060       return INFINITY;
00061    
00062    real_t w = -ab.dot(e);
00063    if (w < 0.0 || v + w > d)
00064       return INFINITY;
00065    
00066    // Segment/ray intersects triangle. Perform delayed division and
00067    // compute the last barycentric coordinate component
00068    real_t ood = 1.0 / d;
00069    t *= ood;
00070    //v *= ood;
00071    //w *= ood;
00072    //real_t u = 1.0 - v - w;
00073    
00074    return t;
00075 }
00076 
00077 #else // 2 == MESH_TRIANGLE_INTERSECTION_TYPE
00078 
00079 #define CROSS(dest,v1,v2) \
00080           dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
00081           dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
00082           dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
00083 #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
00084 #define SUB(dest,v1,v2) \
00085           dest[0]=v1[0]-v2[0]; \
00086           dest[1]=v1[1]-v2[1]; \
00087           dest[2]=v1[2]-v2[2]; 
00088 
00089 // 4 DOT, 3 SUB, 2 CROSS
00090 real_t MeshTriangle::getIntersection(const Ray &ray, SurfacePoint &pt) {
00091    const real_t *const orig  = ray.origin.data;
00092    const real_t *const dir   = ray.direction.data;
00093    
00094    const Vertex *vertices    = mesh->getVertices();
00095    const real_t *const vert0 = vertices[A].data;
00096    const real_t *const vert1 = vertices[B].data;
00097    const real_t *const vert2 = vertices[C].data;
00098    
00099    real_t edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
00100    
00101    /* find vectors for two edges sharing vert0 */
00102    SUB(edge1, vert1, vert0);
00103    SUB(edge2, vert2, vert0);
00104    
00105    /* begin calculating determinant - also used to calculate U parameter 
00106 */
00107    CROSS(pvec, dir, edge2);
00108    
00109    /* if determinant is near zero, ray lies in plane of triangle */
00110    const real_t det = DOT(edge1, pvec);
00111    
00112 #if 0           /* define if culling is desired */
00113    // this branch takes forward facing triangles into account
00114    if (det < EPSILON)
00115       return INFINITY;
00116    
00117    /* calculate distance from vert0 to ray origin */
00118    SUB(tvec, orig, vert0);
00119    
00120    /* calculate U parameter and test bounds */
00121    const real_t u = DOT(tvec, pvec);
00122    if (u < 0.0 || u > det)
00123       return INFINITY;
00124    
00125    /* prepare to test V parameter */
00126    CROSS(qvec, tvec, edge1);
00127    
00128    /* calculate V parameter and test bounds */
00129    const real_t v = DOT(dir, qvec);
00130    if (v < 0.0 || u + v > det)
00131       return INFINITY;
00132    
00133    /* calculate t, scale parameters, ray intersects triangle */
00134    real_t t = DOT(edge2, qvec);
00135    const real_t inv_det = 1.0 / det;
00136    t *= inv_det;
00137    //*u *= inv_det;
00138    //*v *= inv_det;
00139    return t;
00140 #else                    /* the non-culling branch */
00141    // this branch takes forward and backward-facing triangles into account
00142    if (EQ(det, 0))
00143      return INFINITY;
00144    
00145    const real_t inv_det = 1.0 / det;
00146    
00147    /* prepare to test V parameter */
00148    /* calculate distance from vert0 to ray origin */
00149    SUB(tvec, orig, vert0);
00150    
00151    /* calculate U parameter and test bounds */
00152    const real_t u = DOT(tvec, pvec) * inv_det;
00153    if (u < 0.0 || u > 1.0)
00154      return INFINITY;
00155    
00156    CROSS(qvec, tvec, edge1);
00157    
00158    /* calculate V parameter and test bounds */
00159    const real_t v = DOT(dir, qvec) * inv_det;
00160    if (v < 0.0 || u + v > 1.0)
00161      return INFINITY;
00162    
00163    /* calculate t, ray intersects triangle */
00164    return (DOT(edge2, qvec) * inv_det);
00165 #endif // 0
00166 }
00167 
00168 #endif // MESH_TRIANGLE_INTERSECTION_TYPE
00169 
00170 
00171 /* Returns the geometric surface normal */
00172 Vector3 MeshTriangle::getNormal() const {
00173    const Vertex *vertices = mesh->getVertices();
00174    const Vertex &v1 = vertices[A];
00175    const Vertex &v2 = vertices[B];
00176    const Vertex &v3 = vertices[C];
00177    
00178    const Vertex &v21 = v2 - v1;
00179    const Vertex &v31 = v3 - v1;
00180    
00181    return v21.cross(v31).getNormalized();
00182 }
00183 
00184 AABB MeshTriangle::getAABB() const {
00185    AABB aabb;
00186    
00187    const Vertex *vertices = mesh->getVertices();
00188    const unsigned no = mesh->getNoVertices();
00189    ASSERT(A < no && B < no && C < no);
00190    
00191    aabb.add(vertices[A]);
00192    aabb.add(vertices[B]);
00193    aabb.add(vertices[C]);
00194    
00195    return aabb;
00196 }
00197 
00198 
00199 /* Fast triangle intersection with precomputed baryocentric coordinates
00200  * -------------------------------------------------------------------- */
00201 
00202 void MeshTriangleFast::init() {
00203    ASSERT(mesh);
00204    
00205    const Vertex *vertices = mesh->getVertices();
00206    ASSERT(vertices);
00207    
00208    const Vertex &vA = vertices[A];
00209    const Vertex &vB = vertices[B];
00210    const Vertex &vC = vertices[C];
00211    
00212    // compute geometric normal
00213    const Vector3 &b = vC - vA;
00214    const Vector3 &c = vB - vA;
00215    Vector3 n = c.cross(b);
00216    
00217    n_k = n.getMaxDimension();
00218    ASSERT(n[n_k] != 0);
00219    
00220    n /= n[n_k];
00221    n[n_k] = 1.0;
00222    
00223    int u = (n_k + 1) % 3;
00224    int v = (n_k + 2) % 3;
00225    
00226    const real_t bx = b[u];
00227    const real_t by = b[v];
00228    const real_t cx = c[u];
00229    const real_t cy = c[v];
00230    
00231    const real_t bot = 1.0 / (bx*cy - by*cx);
00232    
00233    n_u = n[u];
00234    n_v = n[v];
00235    n_d = vA.dot(n);
00236    
00237    b_u = -by * bot;
00238    b_v =  bx * bot;
00239    b_d = (by*vA[u] - bx*vA[v]) * bot;
00240    
00241    c_u =  cy * bot;
00242    c_v = -cx * bot;
00243    c_d = (vA[v]*cx - vA[u]*cy) * bot;
00244 }
00245 
00246 real_t MeshTriangleFast::getIntersection(const Ray &ray, SurfacePoint &pt) {
00247    static unsigned mod5[] = {0, 1, 2, 0, 1};
00248    const Point3  &origin = ray.origin;
00249    const Vector3 &dir    = ray.direction;
00250    
00251 #define ku mod5[n_k + 1]
00252 #define kv mod5[n_k + 2]
00253    
00254    const real_t nd = 1.0 / (dir[n_k] + n_u * dir[ku] + n_v * dir[kv]);
00255    const real_t t  = nd * (n_d - origin[n_k] -  n_u*origin[ku] - n_v*origin[kv]);
00256    
00257    if (t < EPSILON)
00258       return INFINITY;
00259    
00260    const real_t hu = origin[ku] + t * dir[ku];
00261    const real_t hv = origin[kv] + t * dir[kv];
00262    
00263    const real_t lambda = hu*b_u + hv*b_v + b_d;
00264    
00265    if (lambda < -EPSILON)
00266       return INFINITY;
00267    
00268    const real_t mue = hu * c_u + hv * c_v + c_d;
00269    
00270    if ((mue < -EPSILON) || (lambda + mue > EPSILON + 1.0))
00271       return INFINITY;
00272    
00273    //pt.uv.u = lambda;
00274    //pt.uv.v = mue;
00275    
00276    return t;
00277 }
00278 
00279 void MeshTriangle::getRandomPoint(SurfacePoint &pt) {
00280    Vector3 randBary(Random::sample(0, 1), 
00281                     Random::sample(0, 1), 
00282                     Random::sample(0, 1));
00283    
00284    const real_t sum = randBary.getSum();
00285    ASSERT(sum > 0);
00286    randBary /= sum;
00287    
00288    const Vertex *vertices = mesh->getVertices();
00289    const Vertex &v1 = vertices[A];
00290    const Vertex &v2 = vertices[B];
00291    const Vertex &v3 = vertices[C];
00292    
00293    pt.position = 
00294       Point3((v1 * randBary[0] + v2 * randBary[1] + v3 * randBary[2]).data);
00295 }
00296 
00297 Point3 MeshTriangle::getPosition(const UV &uv) {
00298 #if 0
00299    const UV *uvs = mesh->getUVs();
00300    const UV &uv0 = uvs[tA];
00301    const UV &uv1 = uvs[tB];
00302    const UV &uv2 = uvs[tC];
00303    
00304    const Vector2 a(uv1.u - uv0.u, uv1.v - uv0.v);
00305    const Vector2 b(uv2.u - uv0.u, uv2.v - uv0.v);
00306    
00307    const Vector2 c(uv.u - uv0.u, uv.v - uv0.v);
00308    const Vector2 d(uv.u - uv0.u, uv.v - uv0.v);
00309    
00310    const real_t A  = 1.0 / a.cross(b).getMagnitude();
00311    const real_t pB = c.cross(b).getMagnitude() * A;
00312    const real_t pC = d.cross(a).getMagnitude() * A;
00313    const real_t pA = 1 - pB - pC;
00314 #endif
00315    
00316    Vector3 randBary(uv.u, 
00317                     uv.v, 
00318                     Random::sample(0, 1));
00319    
00320    const real_t sum = randBary.getSum();
00321    ASSERT(sum > 0);
00322    randBary /= sum;
00323    
00324    const Vertex *vertices = mesh->getVertices();
00325    const Vertex &v1 = vertices[A];
00326    const Vertex &v2 = vertices[B];
00327    const Vertex &v3 = vertices[C];
00328    
00329    return 
00330       Point3((v1 * randBary[0] + v2 * randBary[1] + v3 * randBary[2]).data);
00331 }
00332 
00333 real_t MeshTriangle::getSurfaceArea() const {
00334    const Vertex *vertices = mesh->getVertices();
00335    const Vertex &v1 = vertices[A];
00336    const Vertex &v2 = vertices[B];
00337    const Vertex &v3 = vertices[C];
00338    
00339    return 0.5 * (v2 - v1).cross(v3 - v1).getMagnitude();
00340 }
00341 
00342 Vector3 MeshTriangle::getBaryocentricCoords(const Point3 &p) const {
00343    const Vertex *vertices = mesh->getVertices();
00344    const Vector3 &v1 = vertices[A];
00345    const Vector3 &v2 = vertices[B];
00346    const Vector3 &v3 = vertices[C];
00347    const Vector3 p0(p.data);
00348    
00349    // note actual inverse area is 2 / expr, but the 2's cancel out in pA and pB
00350    const real_t A = 1.0 / (v2 - v1).cross(v3 - v1).getMagnitude();
00351    
00352    // baryocentric coordinates of UV using ratios of subtriangle areas
00353    const real_t pA = (v2 - p0).cross(v3 - p0).getMagnitude() * A;
00354    const real_t pB = (p0 - v1).cross(v3 - v1).getMagnitude() * A;
00355    const real_t pC = 1 - pA - pB;
00356    ASSERT(EQ(pA + pB + pC, 1));
00357    
00358    return Vector3(pA, pB, pC);
00359 }
00360 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6