#include "Triangle3.h" #include "Ray.h" #include "AxisAlignedBox3.h" #include "Containers.h" #include "Polygon3.h" namespace GtpVisibilityPreprocessor { Triangle3::Triangle3(const Vector3 &a, const Vector3 &b, const Vector3 &c) { Init(a, b, c); } void Triangle3::Init(const Vector3 &a, const Vector3 &b, const Vector3 &c) { mVertices[0] = a; mVertices[1] = b; mVertices[2] = c; } float Triangle3::GetSpatialAngle(const Vector3 &point) const { return 0.0f; } int Triangle3::CastRay(const Ray &ray, float &t, const float nearestT, Vector3 &normal) const { #if 0 VertexContainer vertices; vertices.push_back(mVertices[0]); vertices.push_back(mVertices[1]); vertices.push_back(mVertices[2]); Polygon3 poly(vertices); int dummy = poly.CastRay(ray, t, nearestT); normal = poly.GetNormal(); // cout << "polyversion code: " << dummy << " t: " << t << " nearestT: " << nearestT << endl; return dummy; #endif ////////////// // specialised triangle ray casting version // using ray-plane intersection // get triangle edge vectors and plane normal const Vector3 u = mVertices[0] - mVertices[1]; const Vector3 v = mVertices[2] - mVertices[1]; // cross product normal = Normalize(CrossProd(v, u)); // ray direction vector const Vector3 dir = ray.GetDir(); const Vector3 w0 = ray.GetLoc() - mVertices[1]; // params to calc ray-plane intersect const float a = -DotProd(normal, w0); const float b = DotProd(normal, dir); // check for division by zero if (fabs(b) < Limits::Small) { // ray is parallel to triangle plane if (a == 0) { // ray lies in triangle plane return Ray::INTERSECTION_OUT_OF_LIMITS; } else { // ray disjoint from plane return Ray::NO_INTERSECTION; } } // distance from origin of ray to plane t = a / b; if (t <= Limits::Small) // ray goes away from triangle { return Ray::INTERSECTION_OUT_OF_LIMITS; } // already found nearer intersection else if ((ray.GetType() == Ray::LOCAL_RAY) && (t >= nearestT)) { return Ray::NO_INTERSECTION; } ///////////////// //-- found intersection point //-- check if it is inside triangle const Vector3 pt = ray.GetLoc() + t * dir; #if GTP_DEBUG if (!pt.CheckValidity()) { cout << "tr: " << *this << endl; cout << "v: " << pt << " t: " << t << " a: " << a << " b: " << b << " n: " << normal << endl; } #endif const Vector3 w = pt - mVertices[1]; const float uu = DotProd(u, u); const float uv = DotProd(u, v); const float vv = DotProd(v, v); const float wu = DotProd(w, u); const float wv = DotProd(w, v); const float D = uv * uv - uu * vv; // get and test parametric coords const float s = (uv * wv - vv * wu) / D; if ((s < -Limits::Small) || (s > 1.0f + Limits::Small)) // pt is outside triangle { return Ray::NO_INTERSECTION; } const float s2 = (uv * wu - uu * wv) / D; if ((s2 < -Limits::Small) || ((s + s2) > 1.0f + Limits::Small)) // pt is outside triangle { return Ray::NO_INTERSECTION; } return Ray::INTERSECTION; // I is in T } AxisAlignedBox3 Triangle3::GetBoundingBox() const { AxisAlignedBox3 box; box.Initialize(); box.Include(mVertices[0]); box.Include(mVertices[1]); box.Include(mVertices[2]); return box; } Vector3 Triangle3::GetNormal() const { const Vector3 v1 = mVertices[0] - mVertices[1]; const Vector3 v2 = mVertices[2] - mVertices[1]; return Normalize(CrossProd(v2, v1)); } Vector3 Triangle3::GetCenter() const { return (mVertices[0] + mVertices[1] + mVertices[2]) / 3.0f; } float Triangle3::GetArea() const { Vector3 v1 = mVertices[0] - mVertices[1], v2=mVertices[2] - mVertices[1]; return 0.5f * Magnitude(CrossProd(v2, v1)); } bool Triangle3::CheckValidity() const { return !( EpsilonEqualV3(mVertices[0], mVertices[1]) || EpsilonEqualV3(mVertices[0], mVertices[2]) || EpsilonEqualV3(mVertices[1], mVertices[2]) ); } }