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
1.5.6