123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938 |
- #include "raycast_mesh.h"
- #include <math.h>
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <string.h>
- #include <vector>
- // This code snippet allows you to create an axis aligned bounding volume tree for a triangle mesh so that you can do
- // high-speed raycasting.
- //
- // There are much better implementations of this available on the internet. In particular I recommend that you use
- // OPCODE written by Pierre Terdiman.
- // @see: http://www.codercorner.com/Opcode.htm
- //
- // OPCODE does a whole lot more than just raycasting, and is a rather significant amount of source code.
- //
- // I am providing this code snippet for the use case where you *only* want to do quick and dirty optimized raycasting.
- // I have not done performance testing between this version and OPCODE; so I don't know how much slower it is. However,
- // anytime you switch to using a spatial data structure for raycasting, you increase your performance by orders and orders
- // of magnitude; so this implementation should work fine for simple tools and utilities.
- //
- // It also serves as a nice sample for people who are trying to learn the algorithm of how to implement AABB trees.
- // AABB = Axis Aligned Bounding Volume trees.
- //
- // http://www.cgal.org/Manual/3.5/doc_html/cgal_manual/AABB_tree/Chapter_main.html
- //
- //
- // This code snippet was written by John W. Ratcliff on August 18, 2011 and released under the MIT. license.
- //
- // mailto:jratcliffscarab@gmail.com
- //
- // The official source can be found at: http://code.google.com/p/raycastmesh/
- //
- //
- #pragma warning(disable:4100)
- namespace RAYCAST_MESH
- {
- typedef std::vector< RmUint32 > TriVector;
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * A method to compute a ray-AABB intersection.
- * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990
- * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)
- * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only)
- *
- * Hence this version is faster as well as more robust than the original one.
- *
- * Should work provided:
- * 1) the integer representation of 0.0f is 0x00000000
- * 2) the sign bit of the RmReal is the most significant one
- *
- * Report bugs: p.terdiman@codercorner.com
- *
- * \param aabb [in] the axis-aligned bounding box
- * \param origin [in] ray origin
- * \param dir [in] ray direction
- * \param coord [out] impact coordinates
- * \return true if ray intersects AABB
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #define RAYAABB_EPSILON 0.00001f
- //! Integer representation of a RmRealing-point value.
- #define IR(x) ((RmUint32&)x)
- bool intersectRayAABB(const RmReal MinB[3],const RmReal MaxB[3],const RmReal origin[3],const RmReal dir[3],RmReal coord[3])
- {
- bool Inside = true;
- RmReal MaxT[3];
- MaxT[0]=MaxT[1]=MaxT[2]=-1.0f;
- // Find candidate planes.
- for(RmUint32 i=0;i<3;i++)
- {
- if(origin[i] < MinB[i])
- {
- coord[i] = MinB[i];
- Inside = false;
- // Calculate T distances to candidate planes
- if(IR(dir[i])) MaxT[i] = (MinB[i] - origin[i]) / dir[i];
- }
- else if(origin[i] > MaxB[i])
- {
- coord[i] = MaxB[i];
- Inside = false;
- // Calculate T distances to candidate planes
- if(IR(dir[i])) MaxT[i] = (MaxB[i] - origin[i]) / dir[i];
- }
- }
- // Ray origin inside bounding box
- if(Inside)
- {
- coord[0] = origin[0];
- coord[1] = origin[1];
- coord[2] = origin[2];
- return true;
- }
- // Get largest of the maxT's for final choice of intersection
- RmUint32 WhichPlane = 0;
- if(MaxT[1] > MaxT[WhichPlane]) WhichPlane = 1;
- if(MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2;
- // Check final candidate actually inside box
- if(IR(MaxT[WhichPlane])&0x80000000) return false;
- for(RmUint32 i=0;i<3;i++)
- {
- if(i!=WhichPlane)
- {
- coord[i] = origin[i] + MaxT[WhichPlane] * dir[i];
- #ifdef RAYAABB_EPSILON
- if(coord[i] < MinB[i] - RAYAABB_EPSILON || coord[i] > MaxB[i] + RAYAABB_EPSILON) return false;
- #else
- if(coord[i] < MinB[i] || coord[i] > MaxB[i]) return false;
- #endif
- }
- }
- return true; // ray hits box
- }
- bool intersectLineSegmentAABB(const RmReal bmin[3],const RmReal bmax[3],const RmReal p1[3],const RmReal dir[3],RmReal &dist,RmReal intersect[3])
- {
- bool ret = false;
- if ( dist > RAYAABB_EPSILON )
- {
- ret = intersectRayAABB(bmin,bmax,p1,dir,intersect);
- if ( ret )
- {
- RmReal dx = p1[0]-intersect[0];
- RmReal dy = p1[1]-intersect[1];
- RmReal dz = p1[2]-intersect[2];
- RmReal d = dx*dx+dy*dy+dz*dz;
- if ( d < dist*dist )
- {
- dist = sqrtf(d);
- }
- else
- {
- ret = false;
- }
- }
- }
- return ret;
- }
- /* a = b - c */
- #define vector(a,b,c) \
- (a)[0] = (b)[0] - (c)[0]; \
- (a)[1] = (b)[1] - (c)[1]; \
- (a)[2] = (b)[2] - (c)[2];
- #define innerProduct(v,q) \
- ((v)[0] * (q)[0] + \
- (v)[1] * (q)[1] + \
- (v)[2] * (q)[2])
- #define crossProduct(a,b,c) \
- (a)[0] = (b)[1] * (c)[2] - (c)[1] * (b)[2]; \
- (a)[1] = (b)[2] * (c)[0] - (c)[2] * (b)[0]; \
- (a)[2] = (b)[0] * (c)[1] - (c)[0] * (b)[1];
- static inline bool rayIntersectsTriangle(const RmReal *p,const RmReal *d,const RmReal *v0,const RmReal *v1,const RmReal *v2,RmReal &t)
- {
- RmReal e1[3],e2[3],h[3],s[3],q[3];
- RmReal a,f,u,v;
- vector(e1,v1,v0);
- vector(e2,v2,v0);
- crossProduct(h,d,e2);
- a = innerProduct(e1,h);
- if (a > -0.00001 && a < 0.00001)
- return(false);
- f = 1/a;
- vector(s,p,v0);
- u = f * (innerProduct(s,h));
- if (u < 0.0 || u > 1.0)
- return(false);
- crossProduct(q,s,e1);
- v = f * innerProduct(d,q);
- if (v < 0.0 || u + v > 1.0)
- return(false);
- // at this stage we can compute t to find out where
- // the intersection point is on the line
- t = f * innerProduct(e2,q);
- if (t > 0) // ray intersection
- return(true);
- else // this means that there is a line intersection
- // but not a ray intersection
- return (false);
- }
- static RmReal computePlane(const RmReal *A,const RmReal *B,const RmReal *C,RmReal *n) // returns D
- {
- RmReal vx = (B[0] - C[0]);
- RmReal vy = (B[1] - C[1]);
- RmReal vz = (B[2] - C[2]);
- RmReal wx = (A[0] - B[0]);
- RmReal wy = (A[1] - B[1]);
- RmReal wz = (A[2] - B[2]);
- RmReal vw_x = vy * wz - vz * wy;
- RmReal vw_y = vz * wx - vx * wz;
- RmReal vw_z = vx * wy - vy * wx;
- RmReal mag = sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
- if ( mag < 0.000001f )
- {
- mag = 0;
- }
- else
- {
- mag = 1.0f/mag;
- }
- RmReal x = vw_x * mag;
- RmReal y = vw_y * mag;
- RmReal z = vw_z * mag;
- RmReal D = 0.0f - ((x*A[0])+(y*A[1])+(z*A[2]));
- n[0] = x;
- n[1] = y;
- n[2] = z;
- return D;
- }
- #define TRI_EOF 0xFFFFFFFF
- enum AxisAABB
- {
- AABB_XAXIS,
- AABB_YAXIS,
- AABB_ZAXIS
- };
- enum ClipCode
- {
- CC_MINX = (1<<0),
- CC_MAXX = (1<<1),
- CC_MINY = (1<<2),
- CC_MAXY = (1<<3),
- CC_MINZ = (1<<4),
- CC_MAXZ = (1<<5),
- };
- class BoundsAABB
- {
- public:
- void setMin(const RmReal *v)
- {
- mMin[0] = v[0];
- mMin[1] = v[1];
- mMin[2] = v[2];
- }
- void setMax(const RmReal *v)
- {
- mMax[0] = v[0];
- mMax[1] = v[1];
- mMax[2] = v[2];
- }
- void setMin(RmReal x,RmReal y,RmReal z)
- {
- mMin[0] = x;
- mMin[1] = y;
- mMin[2] = z;
- }
- void setMax(RmReal x,RmReal y,RmReal z)
- {
- mMax[0] = x;
- mMax[1] = y;
- mMax[2] = z;
- }
- void include(const RmReal *v)
- {
- if ( v[0] < mMin[0] ) mMin[0] = v[0];
- if ( v[1] < mMin[1] ) mMin[1] = v[1];
- if ( v[2] < mMin[2] ) mMin[2] = v[2];
- if ( v[0] > mMax[0] ) mMax[0] = v[0];
- if ( v[1] > mMax[1] ) mMax[1] = v[1];
- if ( v[2] > mMax[2] ) mMax[2] = v[2];
- }
- void getCenter(RmReal *center) const
- {
- center[0] = (mMin[0]+mMax[0])*0.5f;
- center[1] = (mMin[1]+mMax[1])*0.5f;
- center[2] = (mMin[2]+mMax[2])*0.5f;
- }
- bool intersects(const BoundsAABB &b) const
- {
- if ((mMin[0] > b.mMax[0]) || (b.mMin[0] > mMax[0])) return false;
- if ((mMin[1] > b.mMax[1]) || (b.mMin[1] > mMax[1])) return false;
- if ((mMin[2] > b.mMax[2]) || (b.mMin[2] > mMax[2])) return false;
- return true;
- }
- bool containsTriangle(const RmReal *p1,const RmReal *p2,const RmReal *p3) const
- {
- BoundsAABB b;
- b.setMin(p1);
- b.setMax(p1);
- b.include(p2);
- b.include(p3);
- return intersects(b);
- }
- bool containsTriangleExact(const RmReal *p1,const RmReal *p2,const RmReal *p3,RmUint32 &orCode) const
- {
- bool ret = false;
- RmUint32 andCode;
- orCode = getClipCode(p1,p2,p3,andCode);
- if ( andCode == 0 )
- {
- ret = true;
- }
- return ret;
- }
- inline RmUint32 getClipCode(const RmReal *p1,const RmReal *p2,const RmReal *p3,RmUint32 &andCode) const
- {
- andCode = 0xFFFFFFFF;
- RmUint32 c1 = getClipCode(p1);
- RmUint32 c2 = getClipCode(p2);
- RmUint32 c3 = getClipCode(p3);
- andCode&=c1;
- andCode&=c2;
- andCode&=c3;
- return c1|c2|c3;
- }
- inline RmUint32 getClipCode(const RmReal *p) const
- {
- RmUint32 ret = 0;
- if ( p[0] < mMin[0] )
- {
- ret|=CC_MINX;
- }
- else if ( p[0] > mMax[0] )
- {
- ret|=CC_MAXX;
- }
- if ( p[1] < mMin[1] )
- {
- ret|=CC_MINY;
- }
- else if ( p[1] > mMax[1] )
- {
- ret|=CC_MAXY;
- }
- if ( p[2] < mMin[2] )
- {
- ret|=CC_MINZ;
- }
- else if ( p[2] > mMax[2] )
- {
- ret|=CC_MAXZ;
- }
- return ret;
- }
- inline void clamp(const BoundsAABB &aabb)
- {
- if ( mMin[0] < aabb.mMin[0] ) mMin[0] = aabb.mMin[0];
- if ( mMin[1] < aabb.mMin[1] ) mMin[1] = aabb.mMin[1];
- if ( mMin[2] < aabb.mMin[2] ) mMin[2] = aabb.mMin[2];
- if ( mMax[0] > aabb.mMax[0] ) mMax[0] = aabb.mMax[0];
- if ( mMax[1] > aabb.mMax[1] ) mMax[1] = aabb.mMax[1];
- if ( mMax[2] > aabb.mMax[2] ) mMax[2] = aabb.mMax[2];
- }
- RmReal mMin[3];
- RmReal mMax[3];
- };
- class NodeAABB;
- class NodeInterface
- {
- public:
- virtual NodeAABB * getNode(void) = 0;
- virtual void getFaceNormal(RmUint32 tri,RmReal *faceNormal) = 0;
- };
- class NodeAABB
- {
- public:
- NodeAABB(void)
- {
- mLeft = NULL;
- mRight = NULL;
- mLeafTriangleIndex= TRI_EOF;
- }
- NodeAABB(RmUint32 vcount,const RmReal *vertices,RmUint32 tcount,RmUint32 *indices,
- RmUint32 maxDepth, // Maximum recursion depth for the triangle mesh.
- RmUint32 minLeafSize, // minimum triangles to treat as a 'leaf' node.
- RmReal minAxisSize,
- NodeInterface *callback,
- TriVector &leafTriangles) // once a particular axis is less than this size, stop sub-dividing.
- {
- mLeft = NULL;
- mRight = NULL;
- mLeafTriangleIndex = TRI_EOF;
- TriVector triangles;
- triangles.reserve(tcount);
- for (RmUint32 i=0; i<tcount; i++)
- {
- triangles.push_back(i);
- }
- mBounds.setMin( vertices );
- mBounds.setMax( vertices );
- const RmReal *vtx = vertices+3;
- for (RmUint32 i=1; i<vcount; i++)
- {
- mBounds.include( vtx );
- vtx+=3;
- }
- split(triangles,vcount,vertices,tcount,indices,0,maxDepth,minLeafSize,minAxisSize,callback,leafTriangles);
- }
- NodeAABB(const BoundsAABB &aabb)
- {
- mBounds = aabb;
- mLeft = NULL;
- mRight = NULL;
- mLeafTriangleIndex = TRI_EOF;
- }
- ~NodeAABB(void)
- {
- }
- // here is where we split the mesh..
- void split(const TriVector &triangles,
- RmUint32 vcount,
- const RmReal *vertices,
- RmUint32 tcount,
- const RmUint32 *indices,
- RmUint32 depth,
- RmUint32 maxDepth, // Maximum recursion depth for the triangle mesh.
- RmUint32 minLeafSize, // minimum triangles to treat as a 'leaf' node.
- RmReal minAxisSize,
- NodeInterface *callback,
- TriVector &leafTriangles) // once a particular axis is less than this size, stop sub-dividing.
- {
- // Find the longest axis of the bounding volume of this node
- RmReal dx = mBounds.mMax[0] - mBounds.mMin[0];
- RmReal dy = mBounds.mMax[1] - mBounds.mMin[1];
- RmReal dz = mBounds.mMax[2] - mBounds.mMin[2];
- AxisAABB axis = AABB_XAXIS;
- RmReal laxis = dx;
- if ( dy > dx )
- {
- axis = AABB_YAXIS;
- laxis = dy;
- }
- if ( dz > dx && dz > dy )
- {
- axis = AABB_ZAXIS;
- laxis = dz;
- }
- RmUint32 count = triangles.size();
- // if the number of triangles is less than the minimum allowed for a leaf node or...
- // we have reached the maximum recursion depth or..
- // the width of the longest axis is less than the minimum axis size then...
- // we create the leaf node and copy the triangles into the leaf node triangle array.
- if ( count < minLeafSize || depth >= maxDepth || laxis < minAxisSize )
- {
- // Copy the triangle indices into the leaf triangles array
- mLeafTriangleIndex = leafTriangles.size(); // assign the array start location for these leaf triangles.
- leafTriangles.push_back(count);
- for (auto i = triangles.begin(); i != triangles.end(); ++i) {
- RmUint32 tri = *i;
- leafTriangles.push_back(tri);
- }
- }
- else
- {
- RmReal center[3];
- mBounds.getCenter(center);
- BoundsAABB b1,b2;
- splitRect(axis,mBounds,b1,b2,center);
- // Compute two bounding boxes based upon the split of the longest axis
- BoundsAABB leftBounds,rightBounds;
- TriVector leftTriangles;
- TriVector rightTriangles;
- // Create two arrays; one of all triangles which intersect the 'left' half of the bounding volume node
- // and another array that includes all triangles which intersect the 'right' half of the bounding volume node.
- for (auto i = triangles.begin(); i != triangles.end(); ++i) {
- RmUint32 tri = (*i);
- {
- RmUint32 i1 = indices[tri*3+0];
- RmUint32 i2 = indices[tri*3+1];
- RmUint32 i3 = indices[tri*3+2];
- const RmReal *p1 = &vertices[i1*3];
- const RmReal *p2 = &vertices[i2*3];
- const RmReal *p3 = &vertices[i3*3];
- RmUint32 addCount = 0;
- RmUint32 orCode=0xFFFFFFFF;
- if ( b1.containsTriangleExact(p1,p2,p3,orCode))
- {
- addCount++;
- if ( leftTriangles.empty() )
- {
- leftBounds.setMin(p1);
- leftBounds.setMax(p1);
- }
- leftBounds.include(p1);
- leftBounds.include(p2);
- leftBounds.include(p3);
- leftTriangles.push_back(tri); // Add this triangle to the 'left triangles' array and revise the left triangles bounding volume
- }
- // if the orCode is zero; meaning the triangle was fully self-contiained int he left bounding box; then we don't need to test against the right
- if ( orCode && b2.containsTriangleExact(p1,p2,p3,orCode))
- {
- addCount++;
- if ( rightTriangles.empty() )
- {
- rightBounds.setMin(p1);
- rightBounds.setMax(p1);
- }
- rightBounds.include(p1);
- rightBounds.include(p2);
- rightBounds.include(p3);
- rightTriangles.push_back(tri); // Add this triangle to the 'right triangles' array and revise the right triangles bounding volume.
- }
- assert( addCount );
- }
- }
- if ( !leftTriangles.empty() ) // If there are triangles in the left half then...
- {
- leftBounds.clamp(b1); // we have to clamp the bounding volume so it stays inside the parent volume.
- mLeft = callback->getNode(); // get a new AABB node
- new ( mLeft ) NodeAABB(leftBounds); // initialize it to default constructor values.
- // Then recursively split this node.
- mLeft->split(leftTriangles,vcount,vertices,tcount,indices,depth+1,maxDepth,minLeafSize,minAxisSize,callback,leafTriangles);
- }
- if ( !rightTriangles.empty() ) // If there are triangles in the right half then..
- {
- rightBounds.clamp(b2); // clamps the bounding volume so it stays restricted to the size of the parent volume.
- mRight = callback->getNode(); // allocate and default initialize a new node
- new ( mRight ) NodeAABB(rightBounds);
- // Recursively split this node.
- mRight->split(rightTriangles,vcount,vertices,tcount,indices,depth+1,maxDepth,minLeafSize,minAxisSize,callback,leafTriangles);
- }
- }
- }
- void splitRect(AxisAABB axis,const BoundsAABB &source,BoundsAABB &b1,BoundsAABB &b2,const RmReal *midpoint)
- {
- switch ( axis )
- {
- case AABB_XAXIS:
- {
- b1.setMin( source.mMin );
- b1.setMax( midpoint[0], source.mMax[1], source.mMax[2] );
- b2.setMin( midpoint[0], source.mMin[1], source.mMin[2] );
- b2.setMax(source.mMax);
- }
- break;
- case AABB_YAXIS:
- {
- b1.setMin(source.mMin);
- b1.setMax(source.mMax[0], midpoint[1], source.mMax[2]);
- b2.setMin(source.mMin[0], midpoint[1], source.mMin[2]);
- b2.setMax(source.mMax);
- }
- break;
- case AABB_ZAXIS:
- {
- b1.setMin(source.mMin);
- b1.setMax(source.mMax[0], source.mMax[1], midpoint[2]);
- b2.setMin(source.mMin[0], source.mMin[1], midpoint[2]);
- b2.setMax(source.mMax);
- }
- break;
- }
- }
- virtual void raycast(bool &hit,
- const RmReal *from,
- const RmReal *to,
- const RmReal *dir,
- RmReal *hitLocation,
- RmReal *hitNormal,
- RmReal *hitDistance,
- const RmReal *vertices,
- const RmUint32 *indices,
- RmReal &nearestDistance,
- NodeInterface *callback,
- RmUint32 *raycastTriangles,
- RmUint32 raycastFrame,
- const TriVector &leafTriangles,
- RmUint32 &nearestTriIndex)
- {
- RmReal sect[3];
- RmReal nd = nearestDistance;
- if ( !intersectLineSegmentAABB(mBounds.mMin,mBounds.mMax,from,dir,nd,sect) )
- {
- return;
- }
- if ( mLeafTriangleIndex != TRI_EOF )
- {
- const RmUint32 *scan = &leafTriangles[mLeafTriangleIndex];
- RmUint32 count = *scan++;
- for (RmUint32 i=0; i<count; i++)
- {
- RmUint32 tri = *scan++;
- if ( raycastTriangles[tri] != raycastFrame )
- {
- raycastTriangles[tri] = raycastFrame;
- RmUint32 i1 = indices[tri*3+0];
- RmUint32 i2 = indices[tri*3+1];
- RmUint32 i3 = indices[tri*3+2];
- const RmReal *p1 = &vertices[i1*3];
- const RmReal *p2 = &vertices[i2*3];
- const RmReal *p3 = &vertices[i3*3];
- RmReal t;
- if ( rayIntersectsTriangle(from,dir,p1,p2,p3,t))
- {
- bool accept = false;
- if ( t == nearestDistance && tri < nearestTriIndex )
- {
- accept = true;
- }
- if ( t < nearestDistance || accept )
- {
- nearestDistance = t;
- if ( hitLocation )
- {
- hitLocation[0] = from[0]+dir[0]*t;
- hitLocation[1] = from[1]+dir[1]*t;
- hitLocation[2] = from[2]+dir[2]*t;
- }
- if ( hitNormal )
- {
- callback->getFaceNormal(tri,hitNormal);
- }
- if ( hitDistance )
- {
- *hitDistance = t;
- }
- nearestTriIndex = tri;
- hit = true;
- }
- }
- }
- }
- }
- else
- {
- if ( mLeft )
- {
- mLeft->raycast(hit,from,to,dir,hitLocation,hitNormal,hitDistance,vertices,indices,nearestDistance,callback,raycastTriangles,raycastFrame,leafTriangles,nearestTriIndex);
- }
- if ( mRight )
- {
- mRight->raycast(hit,from,to,dir,hitLocation,hitNormal,hitDistance,vertices,indices,nearestDistance,callback,raycastTriangles,raycastFrame,leafTriangles,nearestTriIndex);
- }
- }
- }
- NodeAABB *mLeft; // left node
- NodeAABB *mRight; // right node
- BoundsAABB mBounds; // bounding volume of node
- RmUint32 mLeafTriangleIndex; // if it is a leaf node; then these are the triangle indices.
- };
- class MyRaycastMesh : public RaycastMesh, public NodeInterface
- {
- public:
- MyRaycastMesh(RmUint32 vcount,const RmReal *vertices,RmUint32 tcount,const RmUint32 *indices,RmUint32 maxDepth,RmUint32 minLeafSize,RmReal minAxisSize)
- {
- mRaycastFrame = 0;
- if ( maxDepth < 2 )
- {
- maxDepth = 2;
- }
- if ( maxDepth > 15 )
- {
- maxDepth = 15;
- }
- RmUint32 pow2Table[16] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 65536 };
- mMaxNodeCount = 0;
- for (RmUint32 i=0; i<=maxDepth; i++)
- {
- mMaxNodeCount+=pow2Table[i];
- }
- mNodes = new NodeAABB[mMaxNodeCount];
- mNodeCount = 0;
- mVcount = vcount;
- mVertices = (RmReal *)::malloc(sizeof(RmReal)*3*vcount);
- memcpy(mVertices,vertices,sizeof(RmReal)*3*vcount);
- mTcount = tcount;
- mIndices = (RmUint32 *)::malloc(sizeof(RmUint32)*tcount*3);
- memcpy(mIndices,indices,sizeof(RmUint32)*tcount*3);
- mRaycastTriangles = (RmUint32 *)::malloc(tcount*sizeof(RmUint32));
- memset(mRaycastTriangles,0,tcount*sizeof(RmUint32));
- mRoot = getNode();
- mFaceNormals = NULL;
- new ( mRoot ) NodeAABB(mVcount,mVertices,mTcount,mIndices,maxDepth,minLeafSize,minAxisSize,this,mLeafTriangles);
- }
- ~MyRaycastMesh(void)
- {
- delete []mNodes;
- ::free(mVertices);
- ::free(mIndices);
- ::free(mFaceNormals);
- ::free(mRaycastTriangles);
- }
- virtual bool raycast(const RmReal *from,const RmReal *to,RmReal *hitLocation,RmReal *hitNormal,RmReal *hitDistance)
- {
- bool ret = false;
- RmReal dir[3];
- dir[0] = to[0] - from[0];
- dir[1] = to[1] - from[1];
- dir[2] = to[2] - from[2];
- RmReal distance = sqrtf( dir[0]*dir[0] + dir[1]*dir[1]+dir[2]*dir[2] );
- if ( distance < 0.0000000001f ) return false;
- RmReal recipDistance = 1.0f / distance;
- dir[0]*=recipDistance;
- dir[1]*=recipDistance;
- dir[2]*=recipDistance;
- mRaycastFrame++;
- RmUint32 nearestTriIndex=TRI_EOF;
- mRoot->raycast(ret,from,to,dir,hitLocation,hitNormal,hitDistance,mVertices,mIndices,distance,this,mRaycastTriangles,mRaycastFrame,mLeafTriangles,nearestTriIndex);
- return ret;
- }
- virtual void release(void)
- {
- delete this;
- }
- virtual const RmReal * getBoundMin(void) const // return the minimum bounding box
- {
- return mRoot->mBounds.mMin;
- }
- virtual const RmReal * getBoundMax(void) const // return the maximum bounding box.
- {
- return mRoot->mBounds.mMax;
- }
- virtual NodeAABB * getNode(void)
- {
- assert( mNodeCount < mMaxNodeCount );
- NodeAABB *ret = &mNodes[mNodeCount];
- mNodeCount++;
- return ret;
- }
- virtual void getFaceNormal(RmUint32 tri,RmReal *faceNormal)
- {
- if ( mFaceNormals == NULL )
- {
- mFaceNormals = (RmReal *)::malloc(sizeof(RmReal)*3*mTcount);
- for (RmUint32 i=0; i<mTcount; i++)
- {
- RmUint32 i1 = mIndices[i*3+0];
- RmUint32 i2 = mIndices[i*3+1];
- RmUint32 i3 = mIndices[i*3+2];
- const RmReal*p1 = &mVertices[i1*3];
- const RmReal*p2 = &mVertices[i2*3];
- const RmReal*p3 = &mVertices[i3*3];
- RmReal *dest = &mFaceNormals[i*3];
- computePlane(p3,p2,p1,dest);
- }
- }
- const RmReal *src = &mFaceNormals[tri*3];
- faceNormal[0] = src[0];
- faceNormal[1] = src[1];
- faceNormal[2] = src[2];
- }
- virtual bool bruteForceRaycast(const RmReal *from,const RmReal *to,RmReal *hitLocation,RmReal *hitNormal,RmReal *hitDistance)
- {
- bool ret = false;
- RmReal dir[3];
- dir[0] = to[0] - from[0];
- dir[1] = to[1] - from[1];
- dir[2] = to[2] - from[2];
- RmReal distance = sqrtf( dir[0]*dir[0] + dir[1]*dir[1]+dir[2]*dir[2] );
- if ( distance < 0.0000000001f ) return false;
- RmReal recipDistance = 1.0f / distance;
- dir[0]*=recipDistance;
- dir[1]*=recipDistance;
- dir[2]*=recipDistance;
- const RmUint32 *indices = mIndices;
- const RmReal *vertices = mVertices;
- RmReal nearestDistance = distance;
- for (RmUint32 tri=0; tri<mTcount; tri++)
- {
- RmUint32 i1 = indices[tri*3+0];
- RmUint32 i2 = indices[tri*3+1];
- RmUint32 i3 = indices[tri*3+2];
- const RmReal *p1 = &vertices[i1*3];
- const RmReal *p2 = &vertices[i2*3];
- const RmReal *p3 = &vertices[i3*3];
- RmReal t;
- if ( rayIntersectsTriangle(from,dir,p1,p2,p3,t))
- {
- if ( t < nearestDistance )
- {
- nearestDistance = t;
- if ( hitLocation )
- {
- hitLocation[0] = from[0]+dir[0]*t;
- hitLocation[1] = from[1]+dir[1]*t;
- hitLocation[2] = from[2]+dir[2]*t;
- }
- if ( hitNormal )
- {
- getFaceNormal(tri,hitNormal);
- }
- if ( hitDistance )
- {
- *hitDistance = t;
- }
- ret = true;
- }
- }
- }
- return ret;
- }
- RmUint32 mRaycastFrame;
- RmUint32 *mRaycastTriangles;
- RmUint32 mVcount;
- RmReal *mVertices;
- RmReal *mFaceNormals;
- RmUint32 mTcount;
- RmUint32 *mIndices;
- NodeAABB *mRoot;
- RmUint32 mNodeCount;
- RmUint32 mMaxNodeCount;
- NodeAABB *mNodes;
- TriVector mLeafTriangles;
- };
- };
- using namespace RAYCAST_MESH;
- RaycastMesh * createRaycastMesh(RmUint32 vcount, // The number of vertices in the source triangle mesh
- const RmReal *vertices, // The array of vertex positions in the format x1,y1,z1..x2,y2,z2.. etc.
- RmUint32 tcount, // The number of triangles in the source triangle mesh
- const RmUint32 *indices, // The triangle indices in the format of i1,i2,i3 ... i4,i5,i6, ...
- RmUint32 maxDepth, // Maximum recursion depth for the triangle mesh.
- RmUint32 minLeafSize, // minimum triangles to treat as a 'leaf' node.
- RmReal minAxisSize // once a particular axis is less than this size, stop sub-dividing.
- )
- {
- auto m = new MyRaycastMesh(vcount, vertices, tcount, indices, maxDepth, minLeafSize, minAxisSize);
- return static_cast< RaycastMesh * >(m);
- }
|