Octree per LLVolumeFace WIP
parent
0a54fb6b24
commit
0e7f4dc5ce
|
|
@ -72,6 +72,13 @@ public:
|
|||
virtual void visit(const LLOctreeNode<T>* branch) = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T>
|
||||
{
|
||||
public:
|
||||
virtual void traverse(const LLOctreeNode<T>* node);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class LLOctreeNode : public LLTreeNode<T>
|
||||
{
|
||||
|
|
@ -710,4 +717,15 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
|
|||
traverse(node->getChild(i));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node)
|
||||
{
|
||||
for (U32 i = 0; i < node->getChildCount(); i++)
|
||||
{
|
||||
traverse(node->getChild(i));
|
||||
}
|
||||
node->accept(this);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include "m4math.h"
|
||||
#include "m3math.h"
|
||||
#include "llmatrix4a.h"
|
||||
#include "lloctree.h"
|
||||
#include "lldarray.h"
|
||||
#include "llvolume.h"
|
||||
#include "llstl.h"
|
||||
|
|
@ -132,6 +133,51 @@ BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* cent
|
|||
return true;
|
||||
}
|
||||
|
||||
BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size)
|
||||
{
|
||||
LLVector4a fAWdU;
|
||||
LLVector4a dir;
|
||||
LLVector4a diff;
|
||||
|
||||
dir.setSub(end, start);
|
||||
dir.mul(0.5f);
|
||||
|
||||
diff.setAdd(end,start);
|
||||
diff.mul(0.5f);
|
||||
diff.sub(center);
|
||||
fAWdU.setAbs(dir);
|
||||
|
||||
LLVector4a rhs;
|
||||
rhs.setAdd(size, fAWdU);
|
||||
|
||||
LLVector4a lhs;
|
||||
lhs.setAbs(diff);
|
||||
|
||||
S32 grt = lhs.greaterThan4(rhs).getComparisonMask();
|
||||
|
||||
if (grt & 0x7)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LLVector4a f;
|
||||
f.setCross3(dir, diff);
|
||||
f.setAbs(f);
|
||||
|
||||
LLVector4a v0; v0.mQ = _mm_shuffle_ps(size.mQ, size.mQ, _MM_SHUFFLE(3,1,0,0));
|
||||
LLVector4a v1; v1.mQ = _mm_shuffle_ps(fAWdU.mQ, fAWdU.mQ, _MM_SHUFFLE(3,2,2,1));
|
||||
lhs.setMul(v0, v1);
|
||||
|
||||
v0.mQ = _mm_shuffle_ps(size.mQ, size.mQ, _MM_SHUFFLE(3,2,2,1));
|
||||
v1.mQ = _mm_shuffle_ps(fAWdU.mQ, fAWdU.mQ, _MM_SHUFFLE(3,1,0,0));
|
||||
rhs.setMul(v0, v1);
|
||||
rhs.add(lhs);
|
||||
|
||||
grt = f.greaterThan4(rhs).getComparisonMask();
|
||||
|
||||
return (grt & 0x7) ? false : true;
|
||||
}
|
||||
|
||||
|
||||
// intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
|
||||
// returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b,
|
||||
|
|
@ -139,7 +185,77 @@ BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* cent
|
|||
|
||||
// Moller-Trumbore algorithm
|
||||
BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
|
||||
F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided)
|
||||
F32& intersection_a, F32& intersection_b, F32& intersection_t)
|
||||
{
|
||||
|
||||
/* find vectors for two edges sharing vert0 */
|
||||
LLVector4a edge1;
|
||||
edge1.setSub(vert1, vert0);
|
||||
|
||||
LLVector4a edge2;
|
||||
edge2.setSub(vert2, vert0);
|
||||
|
||||
/* begin calculating determinant - also used to calculate U parameter */
|
||||
LLVector4a pvec;
|
||||
pvec.setCross3(dir, edge2);
|
||||
|
||||
/* if determinant is near zero, ray lies in plane of triangle */
|
||||
LLVector4a det;
|
||||
det.setAllDot3(edge1, pvec);
|
||||
|
||||
if (det.greaterEqual4(LLVector4a::getApproximatelyZero()).getComparisonMask())
|
||||
{
|
||||
/* calculate distance from vert0 to ray origin */
|
||||
LLVector4a tvec;
|
||||
tvec.setSub(orig, vert0);
|
||||
|
||||
/* calculate U parameter and test bounds */
|
||||
LLVector4a u;
|
||||
u.setAllDot3(tvec,pvec);
|
||||
|
||||
if (u.greaterEqual4(LLVector4a::getZero()).getComparisonMask() &&
|
||||
u.lessEqual4(det).getComparisonMask())
|
||||
{
|
||||
/* prepare to test V parameter */
|
||||
LLVector4a qvec;
|
||||
qvec.setCross3(tvec, edge1);
|
||||
|
||||
/* calculate V parameter and test bounds */
|
||||
LLVector4a v;
|
||||
v.setAllDot3(dir, qvec);
|
||||
|
||||
|
||||
//if (!(v < 0.f || u + v > det))
|
||||
|
||||
LLVector4a sum_uv;
|
||||
sum_uv.setAdd(u, v);
|
||||
|
||||
S32 v_gequal = v.greaterEqual4(LLVector4a::getZero()).getComparisonMask();
|
||||
S32 sum_lequal = sum_uv.lessEqual4(det).getComparisonMask();
|
||||
|
||||
if (v_gequal && sum_lequal)
|
||||
{
|
||||
/* calculate t, scale parameters, ray intersects triangle */
|
||||
LLVector4a t;
|
||||
t.setAllDot3(edge2,qvec);
|
||||
|
||||
t.div(det);
|
||||
u.div(det);
|
||||
v.div(det);
|
||||
|
||||
intersection_a = u[0];
|
||||
intersection_b = v[0];
|
||||
intersection_t = t[0];
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
|
||||
F32& intersection_a, F32& intersection_b, F32& intersection_t)
|
||||
{
|
||||
F32 u, v, t;
|
||||
|
||||
|
|
@ -158,85 +274,42 @@ BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, co
|
|||
/* if determinant is near zero, ray lies in plane of triangle */
|
||||
F32 det = edge1.dot3(pvec);
|
||||
|
||||
if (!two_sided)
|
||||
|
||||
if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
|
||||
{
|
||||
if (det < F_APPROXIMATELY_ZERO)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* calculate distance from vert0 to ray origin */
|
||||
LLVector4a tvec;
|
||||
tvec.setSub(orig, vert0);
|
||||
|
||||
/* calculate U parameter and test bounds */
|
||||
u = tvec.dot3(pvec);
|
||||
|
||||
if (u < 0.f || u > det)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* prepare to test V parameter */
|
||||
LLVector4a qvec;
|
||||
qvec.setCross3(tvec, edge1);
|
||||
|
||||
/* calculate V parameter and test bounds */
|
||||
v = dir.dot3(qvec);
|
||||
if (v < 0.f || u + v > det)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* calculate t, scale parameters, ray intersects triangle */
|
||||
t = edge2.dot3(qvec);
|
||||
F32 inv_det = 1.0 / det;
|
||||
t *= inv_det;
|
||||
u *= inv_det;
|
||||
v *= inv_det;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
F32 inv_det = 1.f / det;
|
||||
|
||||
/* calculate distance from vert0 to ray origin */
|
||||
LLVector4a tvec;
|
||||
tvec.setSub(orig, vert0);
|
||||
|
||||
else // two sided
|
||||
{
|
||||
if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
F32 inv_det = 1.0 / det;
|
||||
|
||||
/* calculate distance from vert0 to ray origin */
|
||||
LLVector4a tvec;
|
||||
tvec.setSub(orig, vert0);
|
||||
|
||||
/* calculate U parameter and test bounds */
|
||||
u = (tvec.dot3(pvec)) * inv_det;
|
||||
if (u < 0.f || u > 1.f)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* prepare to test V parameter */
|
||||
LLVector4a qvec;
|
||||
qvec.setSub(tvec, edge1);
|
||||
|
||||
/* calculate V parameter and test bounds */
|
||||
v = (dir.dot3(qvec)) * inv_det;
|
||||
|
||||
if (v < 0.f || u + v > 1.f)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* calculate t, ray intersects triangle */
|
||||
t = (edge2.dot3(qvec)) * inv_det;
|
||||
/* calculate U parameter and test bounds */
|
||||
u = (tvec.dot3(pvec)) * inv_det;
|
||||
if (u < 0.f || u > 1.f)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* prepare to test V parameter */
|
||||
tvec.sub(edge1);
|
||||
|
||||
/* calculate V parameter and test bounds */
|
||||
v = (dir.dot3(tvec)) * inv_det;
|
||||
|
||||
if (intersection_a != NULL)
|
||||
*intersection_a = u;
|
||||
if (intersection_b != NULL)
|
||||
*intersection_b = v;
|
||||
if (intersection_t != NULL)
|
||||
*intersection_t = t;
|
||||
if (v < 0.f || u + v > 1.f)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* calculate t, ray intersects triangle */
|
||||
t = (edge2.dot3(tvec)) * inv_det;
|
||||
|
||||
intersection_a = u;
|
||||
intersection_b = v;
|
||||
intersection_t = t;
|
||||
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -244,7 +317,7 @@ BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, co
|
|||
|
||||
//helper for non-aligned vectors
|
||||
BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
|
||||
F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided)
|
||||
F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided)
|
||||
{
|
||||
LLVector4a vert0a, vert1a, vert2a, origa, dira;
|
||||
vert0a.load3(vert0.mV);
|
||||
|
|
@ -253,11 +326,130 @@ BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, cons
|
|||
origa.load3(orig.mV);
|
||||
dira.load3(dir.mV);
|
||||
|
||||
return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira,
|
||||
intersection_a, intersection_b, intersection_t, two_sided);
|
||||
if (two_sided)
|
||||
{
|
||||
return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira,
|
||||
intersection_a, intersection_b, intersection_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira,
|
||||
intersection_a, intersection_b, intersection_t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeFace::Triangle>
|
||||
{
|
||||
public:
|
||||
|
||||
LLVolumeOctreeListener(LLOctreeNode<LLVolumeFace::Triangle>* node)
|
||||
{
|
||||
node->addListener(this);
|
||||
|
||||
mBounds = (LLVector4a*) _mm_malloc(sizeof(LLVector4a)*4, 16);
|
||||
mExtents = mBounds+2;
|
||||
}
|
||||
|
||||
~LLVolumeOctreeListener()
|
||||
{
|
||||
_mm_free(mBounds);
|
||||
}
|
||||
|
||||
//LISTENER FUNCTIONS
|
||||
virtual void handleChildAddition(const LLOctreeNode<LLVolumeFace::Triangle>* parent,
|
||||
LLOctreeNode<LLVolumeFace::Triangle>* child)
|
||||
{
|
||||
new LLVolumeOctreeListener(child);
|
||||
}
|
||||
|
||||
virtual void handleStateChange(const LLTreeNode<LLVolumeFace::Triangle>* node) { }
|
||||
virtual void handleChildRemoval(const LLOctreeNode<LLVolumeFace::Triangle>* parent,
|
||||
const LLOctreeNode<LLVolumeFace::Triangle>* child) { }
|
||||
virtual void handleInsertion(const LLTreeNode<LLVolumeFace::Triangle>* node, LLVolumeFace::Triangle* tri) { }
|
||||
virtual void handleRemoval(const LLTreeNode<LLVolumeFace::Triangle>* node, LLVolumeFace::Triangle* tri) { }
|
||||
virtual void handleDestruction(const LLTreeNode<LLVolumeFace::Triangle>* node) { }
|
||||
|
||||
|
||||
public:
|
||||
LLVector4a* mBounds; // bounding box (center, size) of this node and all its children (tight fit to objects)
|
||||
LLVector4a* mExtents; // extents (min, max) of this node and all its children
|
||||
};
|
||||
|
||||
class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeFace::Triangle>
|
||||
{
|
||||
public:
|
||||
const LLVolumeFace* mFace;
|
||||
|
||||
LLVolumeOctreeRebound(const LLVolumeFace* face)
|
||||
{
|
||||
mFace = face;
|
||||
}
|
||||
|
||||
virtual void visit(const LLOctreeNode<LLVolumeFace::Triangle>* branch)
|
||||
{
|
||||
LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
|
||||
|
||||
LLVector4a& min = node->mExtents[0];
|
||||
LLVector4a& max = node->mExtents[1];
|
||||
|
||||
if (branch->getElementCount() != 0)
|
||||
{
|
||||
const LLVolumeFace::Triangle* tri = *(branch->getData().begin());
|
||||
|
||||
min = *(tri->mV[0]);
|
||||
max = *(tri->mV[0]);
|
||||
|
||||
for (LLOctreeNode<LLVolumeFace::Triangle>::const_element_iter iter =
|
||||
branch->getData().begin(); iter != branch->getData().end(); ++iter)
|
||||
{
|
||||
//stretch by triangles in node
|
||||
tri = *iter;
|
||||
|
||||
min.setMin(*tri->mV[0]);
|
||||
min.setMin(*tri->mV[1]);
|
||||
min.setMin(*tri->mV[2]);
|
||||
|
||||
max.setMax(*tri->mV[0]);
|
||||
max.setMax(*tri->mV[1]);
|
||||
max.setMax(*tri->mV[2]);
|
||||
}
|
||||
|
||||
for (S32 i = 0; i < branch->getChildCount(); ++i)
|
||||
{ //stretch by child extents
|
||||
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
|
||||
min.setMin(child->mExtents[0]);
|
||||
max.setMax(child->mExtents[1]);
|
||||
}
|
||||
}
|
||||
else if (branch->getChildCount() != 0)
|
||||
{
|
||||
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
|
||||
|
||||
min = child->mExtents[0];
|
||||
max = child->mExtents[1];
|
||||
|
||||
for (S32 i = 1; i < branch->getChildCount(); ++i)
|
||||
{ //stretch by child extents
|
||||
child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
|
||||
min.setMin(child->mExtents[0]);
|
||||
max.setMax(child->mExtents[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
llerrs << "WTF? Empty leaf" << llendl;
|
||||
}
|
||||
|
||||
node->mBounds[0].setAdd(min, max);
|
||||
node->mBounds[0].mul(0.5f);
|
||||
|
||||
node->mBounds[1].setSub(max,min);
|
||||
node->mBounds[1].mul(0.5f);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// statics
|
||||
//-------------------------------------------------------------------
|
||||
|
|
@ -4244,6 +4436,114 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
|
|||
|
||||
}
|
||||
|
||||
class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeFace::Triangle>
|
||||
{
|
||||
public:
|
||||
const LLVolumeFace* mFace;
|
||||
LLVector4a mStart;
|
||||
LLVector4a mDir;
|
||||
LLVector4a mEnd;
|
||||
LLVector3* mIntersection;
|
||||
LLVector2* mTexCoord;
|
||||
LLVector3* mNormal;
|
||||
LLVector3* mBinormal;
|
||||
F32* mClosestT;
|
||||
bool mHitFace;
|
||||
|
||||
LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
|
||||
const LLVolumeFace* face, F32* closest_t,
|
||||
LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
|
||||
: mFace(face),
|
||||
mStart(start),
|
||||
mDir(dir),
|
||||
mIntersection(intersection),
|
||||
mTexCoord(tex_coord),
|
||||
mNormal(normal),
|
||||
mBinormal(bi_normal),
|
||||
mClosestT(closest_t),
|
||||
mHitFace(false)
|
||||
{
|
||||
mEnd.setAdd(mStart, mDir);
|
||||
}
|
||||
|
||||
void traverse(const LLOctreeNode<LLVolumeFace::Triangle>* node)
|
||||
{
|
||||
LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0);
|
||||
|
||||
/*const F32* start = mStart.getF32();
|
||||
const F32* end = mEnd.getF32();
|
||||
const F32* center = vl->mBounds[0].getF32();
|
||||
const F32* size = vl->mBounds[1].getF32();*/
|
||||
|
||||
if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
|
||||
{
|
||||
node->accept(this);
|
||||
for (S32 i = 0; i < node->getChildCount(); ++i)
|
||||
{
|
||||
traverse(node->getChild(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void visit(const LLOctreeNode<LLVolumeFace::Triangle>* node)
|
||||
{
|
||||
for (LLOctreeNode<LLVolumeFace::Triangle>::const_element_iter iter =
|
||||
node->getData().begin(); iter != node->getData().end(); ++iter)
|
||||
{
|
||||
const LLVolumeFace::Triangle* tri = *iter;
|
||||
|
||||
F32 a, b, t;
|
||||
|
||||
if (LLTriangleRayIntersect(*tri->mV[0], *tri->mV[1], *tri->mV[2],
|
||||
mStart, mDir, a, b, t))
|
||||
{
|
||||
if ((t >= 0.f) && // if hit is after start
|
||||
(t <= 1.f) && // and before end
|
||||
(t < *mClosestT)) // and this hit is closer
|
||||
{
|
||||
*mClosestT = t;
|
||||
mHitFace = true;
|
||||
|
||||
if (mIntersection != NULL)
|
||||
{
|
||||
LLVector4a intersect = mDir;
|
||||
intersect.mul(*mClosestT);
|
||||
intersect.add(mStart);
|
||||
mIntersection->set(intersect.getF32());
|
||||
}
|
||||
|
||||
|
||||
if (mTexCoord != NULL)
|
||||
{
|
||||
LLVector2* tc = (LLVector2*) mFace->mTexCoords;
|
||||
*mTexCoord = ((1.f - a - b) * tc[tri->mIndex[0]] +
|
||||
a * tc[tri->mIndex[1]] +
|
||||
b * tc[tri->mIndex[2]]);
|
||||
|
||||
}
|
||||
|
||||
if (mNormal != NULL)
|
||||
{
|
||||
LLVector4* norm = (LLVector4*) mFace->mNormals;
|
||||
|
||||
*mNormal = ((1.f - a - b) * LLVector3(norm[tri->mIndex[0]]) +
|
||||
a * LLVector3(norm[tri->mIndex[1]]) +
|
||||
b * LLVector3(norm[tri->mIndex[2]]));
|
||||
}
|
||||
|
||||
if (mBinormal != NULL)
|
||||
{
|
||||
LLVector4* binormal = (LLVector4*) mFace->mBinormals;
|
||||
*mBinormal = ((1.f - a - b) * LLVector3(binormal[tri->mIndex[0]]) +
|
||||
a * LLVector3(binormal[tri->mIndex[1]]) +
|
||||
b * LLVector3(binormal[tri->mIndex[2]]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
|
||||
S32 face,
|
||||
LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
|
||||
|
|
@ -4288,66 +4588,19 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
|
|||
{
|
||||
genBinormals(i);
|
||||
}
|
||||
|
||||
if (!face.mOctree)
|
||||
{
|
||||
face.createOctree();
|
||||
}
|
||||
|
||||
LLVector4a* p = (LLVector4a*) face.mPositions;
|
||||
|
||||
for (U32 tri = 0; tri < face.mNumIndices/3; tri++)
|
||||
LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
|
||||
intersect.traverse(face.mOctree);
|
||||
if (intersect.mHitFace)
|
||||
{
|
||||
S32 index1 = face.mIndices[tri*3+0];
|
||||
S32 index2 = face.mIndices[tri*3+1];
|
||||
S32 index3 = face.mIndices[tri*3+2];
|
||||
|
||||
F32 a, b, t;
|
||||
|
||||
if (LLTriangleRayIntersect(p[index1],
|
||||
p[index2],
|
||||
p[index3],
|
||||
start, dir, &a, &b, &t, FALSE))
|
||||
{
|
||||
if ((t >= 0.f) && // if hit is after start
|
||||
(t <= 1.f) && // and before end
|
||||
(t < closest_t)) // and this hit is closer
|
||||
{
|
||||
closest_t = t;
|
||||
hit_face = i;
|
||||
|
||||
if (intersection != NULL)
|
||||
{
|
||||
LLVector4a intersect = dir;
|
||||
intersect.mul(closest_t);
|
||||
intersect.add(start);
|
||||
intersection->set(intersect.getF32());
|
||||
}
|
||||
|
||||
|
||||
if (tex_coord != NULL)
|
||||
{
|
||||
LLVector2* tc = (LLVector2*) face.mTexCoords;
|
||||
*tex_coord = ((1.f - a - b) * tc[index1] +
|
||||
a * tc[index2] +
|
||||
b * tc[index3]);
|
||||
|
||||
}
|
||||
|
||||
if (normal != NULL)
|
||||
{
|
||||
LLVector4* norm = (LLVector4*) face.mNormals;
|
||||
|
||||
*normal = ((1.f - a - b) * LLVector3(norm[index1]) +
|
||||
a * LLVector3(norm[index2]) +
|
||||
b * LLVector3(norm[index3]));
|
||||
}
|
||||
|
||||
if (bi_normal != NULL)
|
||||
{
|
||||
LLVector4* binormal = (LLVector4*) face.mBinormals;
|
||||
*bi_normal = ((1.f - a - b) * LLVector3(binormal[index1]) +
|
||||
a * LLVector3(binormal[index2]) +
|
||||
b * LLVector3(binormal[index3]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
hit_face = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5128,13 +5381,29 @@ LLVolumeFace::LLVolumeFace() :
|
|||
mBinormals(NULL),
|
||||
mTexCoords(NULL),
|
||||
mIndices(NULL),
|
||||
mWeights(NULL)
|
||||
mWeights(NULL),
|
||||
mOctree(NULL)
|
||||
{
|
||||
mExtents = (LLVector4a*) _mm_malloc(48, 16);
|
||||
mCenter = mExtents+2;
|
||||
}
|
||||
|
||||
LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
|
||||
: mID(0),
|
||||
mTypeMask(0),
|
||||
mBeginS(0),
|
||||
mBeginT(0),
|
||||
mNumS(0),
|
||||
mNumT(0),
|
||||
mNumVertices(0),
|
||||
mNumIndices(0),
|
||||
mPositions(NULL),
|
||||
mNormals(NULL),
|
||||
mBinormals(NULL),
|
||||
mTexCoords(NULL),
|
||||
mIndices(NULL),
|
||||
mWeights(NULL),
|
||||
mOctree(NULL)
|
||||
{
|
||||
mExtents = (LLVector4a*) _mm_malloc(48, 16);
|
||||
mCenter = mExtents+2;
|
||||
|
|
@ -5157,13 +5426,9 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
|||
|
||||
mNumVertices = 0;
|
||||
mNumIndices = 0;
|
||||
mPositions = NULL;
|
||||
mNormals = NULL;
|
||||
mBinormals = NULL;
|
||||
mTexCoords = NULL;
|
||||
mWeights = NULL;
|
||||
mIndices = NULL;
|
||||
|
||||
freeData();
|
||||
|
||||
LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 12);
|
||||
|
||||
resizeVertices(src.mNumVertices);
|
||||
|
|
@ -5179,6 +5444,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
|||
LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
|
||||
LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, vert_size);
|
||||
|
||||
|
||||
if (src.mBinormals)
|
||||
{
|
||||
allocateBinormals(src.mNumVertices);
|
||||
|
|
@ -5217,17 +5483,37 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
|||
|
||||
LLVolumeFace::~LLVolumeFace()
|
||||
{
|
||||
_mm_free(mPositions);
|
||||
_mm_free(mNormals);
|
||||
_mm_free(mTexCoords);
|
||||
_mm_free(mIndices);
|
||||
_mm_free(mBinormals);
|
||||
_mm_free(mWeights);
|
||||
_mm_free(mExtents);
|
||||
mExtents = NULL;
|
||||
|
||||
freeData();
|
||||
}
|
||||
|
||||
void LLVolumeFace::freeData()
|
||||
{
|
||||
_mm_free(mPositions);
|
||||
mPositions = NULL;
|
||||
_mm_free(mNormals);
|
||||
mNormals = NULL;
|
||||
_mm_free(mTexCoords);
|
||||
mTexCoords = NULL;
|
||||
_mm_free(mIndices);
|
||||
mIndices = NULL;
|
||||
_mm_free(mBinormals);
|
||||
mBinormals = NULL;
|
||||
_mm_free(mWeights);
|
||||
mWeights = NULL;
|
||||
|
||||
delete mOctree;
|
||||
mOctree = NULL;
|
||||
}
|
||||
|
||||
BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
|
||||
{
|
||||
//tree for this face is no longer valid
|
||||
delete mOctree;
|
||||
mOctree = NULL;
|
||||
|
||||
if (mTypeMask & CAP_MASK)
|
||||
{
|
||||
return createCap(volume, partial_build);
|
||||
|
|
@ -5250,6 +5536,18 @@ void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv)
|
|||
cv.mTexCoord = mTexCoords[index];
|
||||
}
|
||||
|
||||
bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const
|
||||
{
|
||||
return getPosition().equal3(rhs.getPosition()) &&
|
||||
mTexCoord == rhs.mTexCoord &&
|
||||
getNormal().equal3(rhs.getNormal());
|
||||
}
|
||||
|
||||
bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector4a& a, const LLVector4a& b) const
|
||||
{
|
||||
return a.less3(b);
|
||||
}
|
||||
|
||||
void LLVolumeFace::optimize(F32 angle_cutoff)
|
||||
{
|
||||
LLVolumeFace new_face;
|
||||
|
|
@ -5305,6 +5603,65 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
|
|||
swapData(new_face);
|
||||
}
|
||||
|
||||
|
||||
void LLVolumeFace::createOctree()
|
||||
{
|
||||
mOctree = new LLOctreeRoot<Triangle>(LLVector3d(0,0,0), LLVector3d(1,1,1), NULL);
|
||||
new LLVolumeOctreeListener(mOctree);
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; i+= 3)
|
||||
{
|
||||
Triangle* tri = new Triangle();
|
||||
|
||||
const LLVector4a& v0 = mPositions[mIndices[i]];
|
||||
const LLVector4a& v1 = mPositions[mIndices[i+1]];
|
||||
const LLVector4a& v2 = mPositions[mIndices[i+2]];
|
||||
|
||||
tri->mV[0] = &v0;
|
||||
tri->mV[1] = &v1;
|
||||
tri->mV[2] = &v2;
|
||||
|
||||
tri->mIndex[0] = mIndices[i];
|
||||
tri->mIndex[1] = mIndices[i+1];
|
||||
tri->mIndex[2] = mIndices[i+2];
|
||||
|
||||
LLVector4a min = v0;
|
||||
min.setMin(v1);
|
||||
min.setMin(v2);
|
||||
|
||||
LLVector4a max = v0;
|
||||
max.setMax(v1);
|
||||
max.setMax(v2);
|
||||
|
||||
LLVector4a center;
|
||||
center.setAdd(min, max);
|
||||
center.mul(0.5f);
|
||||
|
||||
|
||||
tri->mPositionGroup.setVec(center[0], center[1], center[2]);
|
||||
|
||||
LLVector4a size;
|
||||
size.setSub(max,min);
|
||||
|
||||
tri->mRadius = size.length3() * 0.5f;
|
||||
|
||||
mOctree->insert(tri);
|
||||
}
|
||||
|
||||
LLVolumeOctreeRebound rebound(this);
|
||||
rebound.traverse(mOctree);
|
||||
}
|
||||
|
||||
const LLVector3d& LLVolumeFace::Triangle::getPositionGroup() const
|
||||
{
|
||||
return mPositionGroup;
|
||||
}
|
||||
|
||||
const F64& LLVolumeFace::Triangle::getBinRadius() const
|
||||
{
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
void LLVolumeFace::swapData(LLVolumeFace& rhs)
|
||||
{
|
||||
llswap(rhs.mPositions, mPositions);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ class LLPathParams;
|
|||
class LLVolumeParams;
|
||||
class LLProfile;
|
||||
class LLPath;
|
||||
|
||||
template <class T> class LLOctreeNode;
|
||||
class LLVector4a;
|
||||
class LLVolumeFace;
|
||||
class LLVolume;
|
||||
|
||||
|
|
@ -49,15 +52,14 @@ class LLVolume;
|
|||
//#include "vmath.h"
|
||||
#include "v2math.h"
|
||||
#include "v3math.h"
|
||||
#include "v3dmath.h"
|
||||
#include "v4math.h"
|
||||
#include "llvector4a.h"
|
||||
#include "llquaternion.h"
|
||||
#include "llstrider.h"
|
||||
#include "v4coloru.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llfile.h"
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
const S32 MIN_DETAIL_FACES = 6;
|
||||
|
|
@ -830,6 +832,9 @@ public:
|
|||
LLVolumeFace& operator=(const LLVolumeFace& rhs);
|
||||
|
||||
~LLVolumeFace();
|
||||
private:
|
||||
void freeData();
|
||||
public:
|
||||
|
||||
BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
|
||||
void createBinormals();
|
||||
|
|
@ -855,26 +860,19 @@ public:
|
|||
public:
|
||||
U16 mIndex;
|
||||
|
||||
bool operator==(const LLVolumeFace::VertexData& rhs) const
|
||||
{
|
||||
return getPosition().equal3(rhs.getPosition()) &&
|
||||
mTexCoord == rhs.mTexCoord &&
|
||||
getNormal().equal3(rhs.getNormal());
|
||||
}
|
||||
bool operator==(const LLVolumeFace::VertexData& rhs) const;
|
||||
|
||||
struct ComparePosition
|
||||
{
|
||||
bool operator()(const LLVector4a& a, const LLVector4a& b) const
|
||||
{
|
||||
return a.less3(b);
|
||||
}
|
||||
bool operator()(const LLVector4a& a, const LLVector4a& b) const;
|
||||
};
|
||||
|
||||
typedef std::map<LLVector4a, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
|
||||
};
|
||||
|
||||
void optimize(F32 angle_cutoff = 2.f);
|
||||
|
||||
void createOctree();
|
||||
|
||||
enum
|
||||
{
|
||||
SINGLE_MASK = 0x0001,
|
||||
|
|
@ -919,6 +917,21 @@ public:
|
|||
// mWeights.size() should be empty or match mVertices.size()
|
||||
LLVector4a* mWeights;
|
||||
|
||||
class Triangle : public LLRefCount
|
||||
{
|
||||
public:
|
||||
const LLVector4a* mV[3];
|
||||
U16 mIndex[3];
|
||||
|
||||
LLVector3d mPositionGroup;
|
||||
F64 mRadius;
|
||||
|
||||
virtual const LLVector3d& getPositionGroup() const;
|
||||
virtual const F64& getBinRadius() const;
|
||||
};
|
||||
|
||||
LLOctreeNode<Triangle>* mOctree;
|
||||
|
||||
private:
|
||||
BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
|
||||
BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
|
||||
|
|
@ -1084,10 +1097,12 @@ BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* cent
|
|||
BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
|
||||
|
||||
BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
|
||||
F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided);
|
||||
F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided);
|
||||
|
||||
BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
|
||||
F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided);
|
||||
F32& intersection_a, F32& intersection_b, F32& intersection_t);
|
||||
BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
|
||||
F32& intersection_a, F32& intersection_b, F32& intersection_t);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -286,7 +286,6 @@ BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
|
|||
LLVector4a upper_right;
|
||||
upper_right.setAdd(lower_right, y_scalea);
|
||||
|
||||
F32 t = 0.f;
|
||||
LLVector4a enda;
|
||||
enda.load3(end.mV);
|
||||
LLVector4a starta;
|
||||
|
|
@ -294,8 +293,10 @@ BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
|
|||
LLVector4a dir;
|
||||
dir.setSub(enda, starta);
|
||||
|
||||
if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, starta, dir, NULL, NULL, &t, FALSE) ||
|
||||
LLTriangleRayIntersect(upper_left, lower_left, lower_right, starta, dir, NULL, NULL, &t, FALSE))
|
||||
F32 a,b,t;
|
||||
|
||||
if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, starta, dir, a,b,t) ||
|
||||
LLTriangleRayIntersect(upper_left, lower_left, lower_right, starta, dir, a,b,t))
|
||||
{
|
||||
if (intersection)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -207,10 +207,11 @@ BOOL LLHUDText::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
|
|||
}
|
||||
|
||||
LLVector3 dir = end-start;
|
||||
F32 t = 0.f;
|
||||
F32 a,b,t;
|
||||
|
||||
if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, NULL, NULL, &t, FALSE) ||
|
||||
LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, NULL, NULL, &t, FALSE) )
|
||||
|
||||
if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE) ||
|
||||
LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, a, b, t, FALSE) )
|
||||
{
|
||||
if (t <= 1.f)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
#include "llweb.h"
|
||||
#include "llwindow.h"
|
||||
#include "llfloatertools.h" // to enable hide if build tools are up
|
||||
#include "llvector4a.h"
|
||||
|
||||
// Functions pulled from pipeline.cpp
|
||||
glh::matrix4f glh_get_current_modelview();
|
||||
|
|
|
|||
|
|
@ -2769,6 +2769,19 @@ void renderLights(LLDrawable* drawablep)
|
|||
}
|
||||
}
|
||||
|
||||
class LLRenderOctree : public LLOctreeTraveler<LLVolumeFace::Triangle>
|
||||
{
|
||||
public:
|
||||
void visit(const LLOctreeNode<LLVolumeFace::Triangle>* branch)
|
||||
{
|
||||
const LLVector3d& c = branch->getCenter();
|
||||
const LLVector3d& s = branch->getSize();
|
||||
|
||||
LLVector3 pos((F32) c.mdV[0], (F32) c.mdV[1], (F32) c.mdV[2]);
|
||||
LLVector3 size((F32) s.mdV[0], (F32) s.mdV[1], (F32) s.mdV[2]);
|
||||
drawBoxOutline(pos, size);
|
||||
}
|
||||
};
|
||||
|
||||
void renderRaycast(LLDrawable* drawablep)
|
||||
{
|
||||
|
|
@ -2787,6 +2800,23 @@ void renderRaycast(LLDrawable* drawablep)
|
|||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
LLVOVolume* vobj = drawablep->getVOVolume();
|
||||
LLVolume* volume = vobj->getVolume();
|
||||
if (volume && volume->getNumVolumeFaces() > gDebugRaycastFaceHit)
|
||||
{
|
||||
const LLVolumeFace& face = volume->getVolumeFace(gDebugRaycastFaceHit);
|
||||
if (!face.mOctree)
|
||||
{
|
||||
((LLVolumeFace*) &face)->createOctree();
|
||||
}
|
||||
|
||||
gGL.pushMatrix();
|
||||
glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
|
||||
LLRenderOctree render;
|
||||
render.traverse(face.mOctree);
|
||||
gGL.popMatrix();
|
||||
}
|
||||
}
|
||||
else if (drawablep->isAvatar())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -647,23 +647,23 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
|
|||
|
||||
U32 idx0 = 0,idx1 = 0,idx2 = 0;
|
||||
|
||||
if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, &a, &b, &t, FALSE))
|
||||
if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE))
|
||||
{
|
||||
hit = TRUE;
|
||||
idx0 = 0; idx1 = 1; idx2 = 2;
|
||||
}
|
||||
else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, &a, &b, &t, FALSE))
|
||||
else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, a, b, t, FALSE))
|
||||
{
|
||||
hit = TRUE;
|
||||
idx0 = 1; idx1 = 3; idx2 = 2;
|
||||
}
|
||||
else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, &a, &b, &t, FALSE))
|
||||
else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, a, b, t, FALSE))
|
||||
{
|
||||
normal1 = -normal1;
|
||||
hit = TRUE;
|
||||
idx0 = 2; idx1 = 1; idx2 = 0;
|
||||
}
|
||||
else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, &a, &b, &t, FALSE))
|
||||
else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, a, b, t, FALSE))
|
||||
{
|
||||
normal1 = -normal1;
|
||||
hit = TRUE;
|
||||
|
|
|
|||
Loading…
Reference in New Issue