📄 ogreopcodeline.cpp
字号:
}
else
{
// (0,+,0)
Case00(1,0,2,kPnt,kDir,rkBox,pfLParam,fSqrDistance);
}
}
else
{
if ( kDir.z > (Real)0.0 )
{
// (0,0,+)
Case00(2,0,1,kPnt,kDir,rkBox,pfLParam,fSqrDistance);
}
else
{
// (0,0,0)
Case000(kPnt,rkBox,fSqrDistance);
if ( pfLParam )
*pfLParam = (Real)0.0;
}
}
}
// undo reflections
for (i = 0; i < 3; i++)
{
if ( bReflect[i] )
kPnt[i] = -kPnt[i];
}
if ( pfBParam0 )
*pfBParam0 = kPnt.x;
if ( pfBParam1 )
*pfBParam1 = kPnt.y;
if ( pfBParam2 )
*pfBParam2 = kPnt.z;
return fSqrDistance;
}
// --------------------------------------------------------------------
// Utility functions for picking
// --------------------------------------------------------------------
bool Clip( Real fDenom, Real fNumer, Real& rfT0, Real& rfT1)
{
// Return value is 'true' if line segment intersects the current test
// plane. Otherwise 'false' is returned in which case the line segment
// is entirely clipped.
if ( fDenom > 0.0 )
{
if ( fNumer > fDenom*rfT1 )
return false;
if ( fNumer > fDenom*rfT0 )
rfT0 = fNumer/fDenom;
return true;
}
else if ( fDenom < 0.0 )
{
if ( fNumer > fDenom*rfT0 )
return false;
if ( fNumer > fDenom*rfT1 )
rfT1 = fNumer/fDenom;
return true;
}
else
{
return fNumer <= 0.0;
}
}
// --------------------------------------------------------------------
bool FindIntersection( const Vector3& rkOrigin,
const Vector3& rkDirection,
const Vector3& afExtent,
Real& rfT0,
Real& rfT1)
{
Real fSaveT0 = rfT0, fSaveT1 = rfT1;
return Clip(+rkDirection.x,-rkOrigin.x-afExtent[0],rfT0,rfT1) &&
Clip(-rkDirection.x,+rkOrigin.x-afExtent[0],rfT0,rfT1) &&
Clip(+rkDirection.y,-rkOrigin.y-afExtent[1],rfT0,rfT1) &&
Clip(-rkDirection.y,+rkOrigin.y-afExtent[1],rfT0,rfT1) &&
Clip(+rkDirection.z,-rkOrigin.z-afExtent[2],rfT0,rfT1) &&
Clip(-rkDirection.z,+rkOrigin.z-afExtent[2],rfT0,rfT1) &&
( rfT0 != fSaveT0 || rfT1 != fSaveT1 );
}
//---------------------------------------------------------------------
Real Line::squaredDistance( const OrientedBox& rkBox ) const
{
Vector3 direction = end - start;
Real fLP, fBP0, fBP1, fBP2;
Real pfBParam0,pfBParam1,pfBParam2;
Real fSqrDistance = sqrDistance(start, direction, rkBox,&fLP,&fBP0,&fBP1,&fBP2);
if ( fLP >= (Real)0.0 )
{
if ( fLP <= (Real)1.0 )
{
//if ( pfLParam ) *pfLParam = fLP;
//if ( pfBParam0 ) *pfBParam0 = fBP0;
//if ( pfBParam1 ) *pfBParam1 = fBP1;
//if ( pfBParam2 ) *pfBParam2 = fBP2;
return fSqrDistance;
}
else
{
// TODO implement distance between a point and a box
fSqrDistance = sqrDistance( end, rkBox, &pfBParam0,&pfBParam1,&pfBParam2);
//if ( pfLParam ) *pfLParam = (Real)1.0;
return fSqrDistance;
}
}
else
{
fSqrDistance = sqrDistance(start,rkBox, &pfBParam0,&pfBParam1,&pfBParam2);
// if ( pfLParam ) *pfLParam = (Real)0.0;
return fSqrDistance;
}
return 0.0;
}
// --------------------------------------------------------------------
Real Line::distance( const OrientedBox& obb ) const
{
return Math::Sqrt( squaredDistance(obb) );
}
// --------------------------------------------------------------------
// INTERSECTION TESTS
// --------------------------------------------------------------------
bool Line::intersect( const Aabb& aabb ) const
{
OBB obb(aabb);
return intersect(obb);
}
// --------------------------------------------------------------------
bool Line::intersect( const OBB& rkBox ) const
{
Vector3 dir = end - start;
Real fAWdU[3], fADdU[3], fAWxDdU[3], fRhs;
Vector3 kSDir = 0.5*dir;
Vector3 kSCen = start + kSDir;
Vector3 rot[3] = { rkBox.getOrientation().GetColumn(0),
rkBox.getOrientation().GetColumn(1),
rkBox.getOrientation().GetColumn(2) };
Vector3 kDiff = kSCen - rkBox.getCenter();
fAWdU[0] = Math::Abs(kSDir | rot[0]);
fADdU[0] = Math::Abs(kDiff | rot[0]);
fRhs = rkBox.getExtents()[0] + fAWdU[0];
if ( fADdU[0] > fRhs )
return false;
fAWdU[1] = Math::Abs(kSDir | rot[1]);
fADdU[1] = Math::Abs(kDiff | rot[1]);
fRhs = rkBox.getExtents()[1] + fAWdU[1];
if ( fADdU[1] > fRhs )
return false;
fAWdU[2] = Math::Abs(kSDir | rot[2]);
fADdU[2] = Math::Abs(kDiff | rot[2]);
fRhs = rkBox.getExtents()[2] + fAWdU[2];
if ( fADdU[2] > fRhs )
return false;
Vector3 kWxD = kSDir ^ kDiff;
fAWxDdU[0] = Math::Abs(kWxD | rot[0]);
fRhs = rkBox.getExtents()[1]*fAWdU[2] + rkBox.getExtents()[2]*fAWdU[1];
if ( fAWxDdU[0] > fRhs )
return false;
fAWxDdU[1] = Math::Abs(kWxD | rot[1]);
fRhs = rkBox.getExtents()[0]*fAWdU[2] + rkBox.getExtents()[2]*fAWdU[0];
if ( fAWxDdU[1] > fRhs )
return false;
fAWxDdU[2] = Math::Abs(kWxD | rot[2]);
fRhs = rkBox.getExtents()[0]*fAWdU[1] + rkBox.getExtents()[1]*fAWdU[0];
if ( fAWxDdU[2] > fRhs )
return false;
return true;
}
// --------------------------------------------------------------------
bool Line::intersect( const Sphere& sphere ) const
{
Real fSqrDist = squaredDistance( sphere.getCenter() );
return fSqrDist <= sphere.getRadius()*sphere.getRadius();
}
// --------------------------------------------------------------------
bool Line::intersect( const Capsule& capsule ) const
{
Real fSqrDist = squaredDistance( Line(capsule.start, capsule.end) );
return fSqrDist <= capsule.radius*capsule.radius;
}
// --------------------------------------------------------------------
bool Line::pick( const Aabb& aabb, Real& dist ) const
{
OBB obb(aabb);
return pick(obb,dist);
}
// --------------------------------------------------------------------
bool Line::pick( const OBB& obb, Real& dist ) const
{
// convert line to box coordinates
Vector3 kDiff = start - obb.getCenter();
Vector3 rot[3] = { obb.getOrientation().GetColumn(0),
obb.getOrientation().GetColumn(1),
obb.getOrientation().GetColumn(2) };
Vector3 kOrigin(
kDiff | rot[0],
kDiff | rot[1],
kDiff | rot[2]
);
Vector3 direction = end - start;
Vector3 kDirection(
direction | rot[0],
direction | rot[1],
direction | rot[2]
);
Real fT0 = Math::NEG_INFINITY, fT1 = Math::POS_INFINITY;
bool ret = FindIntersection(kOrigin,kDirection,obb.getExtents(),
fT0,fT1);
if ( ret )
{
if ( fT0 != fT1 )
dist = std::min(fT0,fT1);
else
dist = fT0;
}
return ret;
}
// --------------------------------------------------------------------
bool Line::pick( const Sphere& sphere, Real& dist ) const
{
// set up quadratic Q(t) = a*t^2 + 2*b*t + c
Vector3 direction = end - start;
Vector3 kDiff = start - sphere.getCenter();
Real fA = direction.squaredLength();
Real fB = kDiff | direction;
Real fC = kDiff.squaredLength() - sphere.getRadius()*sphere.getRadius();
Real afT[2];
Real fDiscr = fB*fB - fA*fC;
if ( fDiscr < 0.0 )
{
return false;
}
else if ( fDiscr > 0.0 )
{
Real fRoot = Math::Sqrt(fDiscr);
Real fInvA = (1.0)/fA;
afT[0] = (-fB - fRoot)*fInvA;
afT[1] = (-fB + fRoot)*fInvA;
dist = std::min(afT[0],afT[1]);
return true;
}
else
{
dist = -fB/fA;
return true;
}
}
// --------------------------------------------------------------------
// Ray3 implementation
// --------------------------------------------------------------------
Real Ray3::squaredDistance( const Vector3& point ) const
{
Vector3 delta = point - origin;
Real proj = direction | delta;
if ( proj < 0.0 )
proj = 0.0;
else
{
proj /= direction.squaredLength();
delta += -proj*direction;
}
return delta.squaredLength();
}
// --------------------------------------------------------------------
Real Ray3::distance( const Vector3& point ) const
{
return Math::Sqrt( squaredDistance(point) );
}
// --------------------------------------------------------------------
Real Ray3::squaredDistance( const Line& line ) const
{
Vector3 lineDir = line.getDirection();
Vector3 kDiff = line.start - origin;
Real fA00 = lineDir.squaredLength();
Real fA01 = -(lineDir|direction );
Real fA11 = direction.squaredLength();
Real fB0 = (kDiff|lineDir );
Real fC = kDiff.squaredLength();
Real fDet = Math::Abs(fA00*fA11-fA01*fA01);
Real fB1, fS, fT, fSqrDist;
if ( fDet >= LINE_EPSILON )
{
fB1 = -(kDiff|direction);
fT = fA01*fB0-fA00*fB1;
if ( fT >= (Real)0.0 )
{
// two interior points are closest, one on line and one on ray
Real fInvDet = ((Real)1.0)/fDet;
fS = (fA01*fB1-fA11*fB0)*fInvDet;
fT *= fInvDet;
fSqrDist = fS*(fA00*fS+fA01*fT+((Real)2.0)*fB0) +
fT*(fA01*fS+fA11*fT+((Real)2.0)*fB1)+fC;
}
else
{
// end point of ray and interior point of line are closest
fS = -fB0/fA00;
fT = (Real)0.0;
fSqrDist = fB0*fS+fC;
}
}
else
{
// lines are parallel, closest pair with one point at ray origin
fS = -fB0/fA00;
fT = (Real)0.0;
fSqrDist = fB0*fS+fC;
}
return Math::Abs(fSqrDist);
}
// --------------------------------------------------------------------
Real Ray3::distance( const Line& line ) const
{
return Math::Sqrt( squaredDistance(line) );
}
// --------------------------------------------------------------------
bool Ray3::intersect( const Aabb& aabb ) const
{
OBB obb(aabb);
return intersect(obb);
}
// --------------------------------------------------------------------
bool Ray3::intersect( const OBB& rkBox ) const
{
Real fWdU[3], fAWdU[3], fDdU[3], fADdU[3], fAWxDdU[3], fRhs;
Vector3 rot[3] = { rkBox.getOrientation().GetColumn(0),
rkBox.getOrientation().GetColumn(1),
rkBox.getOrientation().GetColumn(2) };
Vector3 kDiff = origin - rkBox.getCenter();
fWdU[0] = direction | rot[0];
fAWdU[0] = Math::Abs( fWdU[0]);
fDdU[0] = kDiff | rot[0];
fADdU[0] = Math::Abs( fDdU[0]);
if ( fADdU[0] > rkBox.getExtents()[0] && fDdU[0]*fWdU[0] >= (Real)0.0 )
return false;
fWdU[1] = direction | rot[1];
fAWdU[1] = Math::Abs( fWdU[1]);
fDdU[1] = kDiff | rot[1];
fADdU[1] = Math::Abs( fDdU[1]);
if ( fADdU[1] > rkBox.getExtents()[1] && fDdU[1]*fWdU[1] >= (Real)0.0 )
return false;
fWdU[2] = direction | rot[2];
fAWdU[2] = Math::Abs( fWdU[2]);
fDdU[2] = kDiff | rot[2];
fADdU[2] = Math::Abs( fDdU[2]);
if ( fADdU[2] > rkBox.getExtents()[2] && fDdU[2]*fWdU[2] >= (Real)0.0 )
return false;
Vector3 kWxD = direction ^ kDiff;
fAWxDdU[0] = Math::Abs( kWxD | rot[0] );
fRhs = rkBox.getExtents()[1]*fAWdU[2] + rkBox.getExtents()[2]*fAWdU[1];
if ( fAWxDdU[0] > fRhs )
return false;
fAWxDdU[1] = Math::Abs( kWxD | rot[1] );
fRhs = rkBox.getExtents()[0]*fAWdU[2] + rkBox.getExtents()[2]*fAWdU[0];
if ( fAWxDdU[1] > fRhs )
return false;
fAWxDdU[2] = Math::Abs( kWxD | rot[2] );
fRhs = rkBox.getExtents()[0]*fAWdU[1] + rkBox.getExtents()[1]*fAWdU[0];
if ( fAWxDdU[2] > fRhs )
return false;
return true;
}
// --------------------------------------------------------------------
bool Ray3::intersect( const Sphere& sphere ) const
{
Real squaredDist = squaredDistance( sphere.getCenter() );
return squaredDist <= sphere.getRadius()*sphere.getRadius();
}
// --------------------------------------------------------------------
bool Ray3::intersect( const Capsule& capsule ) const
{
Real squaredDist = squaredDistance( Line(capsule.start, capsule.end) );
return squaredDist <= capsule.radius*capsule.radius;
}
// --------------------------------------------------------------------
bool Ray3::pick( const Aabb& aabb, Real& dist ) const
{
OBB obb(aabb);
return pick(obb, dist);
}
// --------------------------------------------------------------------
bool Ray3::pick( const OBB& obb, Real& dist ) const
{
dist = 0.0f;
// convert ray to box coordinates
Vector3 kDiff = origin - obb.getCenter();
Vector3 rot[3] = { obb.getOrientation().GetColumn(0),
obb.getOrientation().GetColumn(1),
obb.getOrientation().GetColumn(2) };
Vector3 kOrigin(
kDiff | rot[0],
kDiff | rot[1],
kDiff | rot[2]
);
Vector3 kDirection(
direction | rot[0],
direction | rot[1],
direction | rot[2]
);
Real fT0 = 0.0,
fT1 = Math::POS_INFINITY;
bool ret = FindIntersection(kOrigin,kDirection,obb.getExtents(), fT0,fT1);
if ( ret )
{
if ( fT0 > 0.0 )
dist = std::min(fT0,fT1);
else // fT0 == 0
dist = fT1;
}
return ret;
}
// --------------------------------------------------------------------
bool Ray3::pick( const Sphere& sphere, Real& dist ) const
{
// set up quadratic Q(t) = a*t^2 + 2*b*t + c
Vector3 kDiff = origin - sphere.getCenter();
Real fA = direction.squaredLength();
Real fB = kDiff | direction;
Real fC = kDiff.squaredLength() - sphere.getRadius()*sphere.getRadius();
Real afT[2];
Real fDiscr = fB*fB - fA*fC;
dist = 0.0;
// tests if the code won't return intersections
if ( fDiscr < 0.0 )
return false;
if ( fDiscr > 0.0 )
{
Real fRoot = Math::Sqrt(fDiscr);
Real fInvA = (1.0)/fA;
afT[0] = (-fB - fRoot)*fInvA;
afT[1] = (-fB + fRoot)*fInvA;
// aft[1]>=afT[0] >= 0.0
if ( afT[0] >= 0.0 )
{
dist = std::min(afT[0],afT[1]);
return true;
}
else if ( afT[1] >= 0.0 )
{
dist = afT[1];
return true;
}
else
return false;
}
else
{
afT[0] = -fB/fA;
if ( afT[0] >= 0.0 )
{
dist = afT[0];
return true;
}
else
return false;
}
}
// --------------------------------------------------------------------
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -