📄 iogrecollisionshape.cpp
字号:
{
Ogre::Vector3 velocity = movementVector;
Ogre::Vector3 base = position;
Ogre::Real velocitySqaredLength = (Ogre::Real)velocity.squaredLength();
Ogre::Real a,b,c;
Ogre::Real newT;
// for each edge or vertex a quadratic equation has to be solved:
// a*t^2 + b*t + c = 0. We calculate a,b, and c for each test.
// check against points
a = velocitySqaredLength;
// FIXME: turn these 3 into 1 function
// p1
b = 2.0f * (velocity.dotProduct(base - triangle.point(0)));
c = (Ogre::Real)((triangle.point(0)-base).squaredLength() - 1.0);
if (getLowestRoot(a,b,c,t, &newT))
{
t = newT;
foundCollision = true;
collisionPoint = triangle.point(0);
}
// p2
if (!foundCollision)
{
b = 2.0f * (velocity.dotProduct(base - triangle.point(1)));
c = (Ogre::Real)((triangle.point(1)-base).squaredLength() - 1.0);
if (getLowestRoot(a,b,c,t, &newT))
{
t = newT;
foundCollision = true;
collisionPoint = triangle.point(1);
}
}
// p3
if (!foundCollision)
{
b = 2.0f * (velocity.dotProduct(base - triangle.point(2)));
c = (Ogre::Real)((triangle.point(2)-base).squaredLength() - 1.0);
if (getLowestRoot(a,b,c,t, &newT))
{
t = newT;
foundCollision = true;
collisionPoint = triangle.point(2);
}
}
// check against edges:
Ogre::Vector3 edge;
Ogre::Vector3 baseToVertex;
edge = triangle.point(1) - triangle.point(0);
baseToVertex = triangle.point(0) - position;
Vector3 point = triangle.point(0);
sphereEdgeCheck(velocity, edge, baseToVertex, t, foundCollision, collisionPoint, point);
edge = triangle.point(2) - triangle.point(1);
baseToVertex = triangle.point(1) - position;
point = triangle.point(1);
sphereEdgeCheck(velocity, edge, baseToVertex, t, foundCollision, collisionPoint, point);
edge = triangle.point(0) - triangle.point(2);
baseToVertex = triangle.point(2) - position;
point = triangle.point(2);
sphereEdgeCheck(velocity, edge, baseToVertex, t, foundCollision, collisionPoint, point);
}// end no collision found
// set result:
if (foundCollision)
{
// Time to scale everything back..
// distance to collision is t
Ogre::Real distToCollision = (Ogre::Real)(t*movementVector.length() * radius);
// does this triangle qualify for closest hit?
if (distToCollision <= cp->distance)
{
cp->distance = distToCollision;
cp->contact = collisionPoint * radius;
cp->other_contact = cp->contact;
cp->this_contact = (position + (movementVector*t))*radius;
cp->other_normal = trianglePlane.normal;
Ogre::Vector3 vec_to_col = cp->contact - cp->this_contact;
cp->this_normal = vec_to_col.normalisedCopy();
}
return true;
}// end found collision
}// end if is front facing
return false;
}
/////////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------
/// Check contact of a sphere with shape.
/// The collType is interpreted as follows:
/// - COLLTYPE_IGNORE: illegal (makes no sense)
/// - COLLTYPE_QUICK: first contact check only
/// - COLLTYPE_CONTACT: return closest contact
/// - COLLTYPE_EXACT: return a sorted list of contacts
/// Currently, sphere checks always work in first constact mode (COLLTYPE_QUICK).
/// @param collType see above
/// @param ownMatrix position/orientation of this shape
/// @param ball sphere definition in world space
/// @param collPair will be filled with result
/// @return true if line intersects shape
bool ICollisionShape::sphereCheck(CollisionType collType,
const Matrix4& ownMatrix,
const Sphere& ball,
CollisionPair& collPair)
{
assert(COLLTYPE_IGNORE != collType);
// setup sphere collider
Opcode::SphereCollider& collider = CollisionManager::getSingletonPtr()->opcSphereCollider;
Opcode::SphereCache& cache = CollisionManager::getSingletonPtr()->opcSphereCache;
switch (collType)
{
case COLLTYPE_QUICK:
case COLLTYPE_CONTACT:
collider.SetFirstContact(true);
break;
case COLLTYPE_EXACT:
collider.SetFirstContact(false);
break;
default:
break;
}
// convert Matrix4 to Opcode Matrix4x4
IceMaths::Matrix4x4 opcMatrix;
IceMaths::Matrix4x4 *ptrOpcMatrix = &opcMatrix;
OgreOpcodeUtils::ogreToIceMatrix4( ownMatrix, opcMatrix);
// build identity matrix because sphere is already in world space
IceMaths::Matrix4x4 identity;
IceMaths::Matrix4x4 *ptrIdentity = &identity;
identity.Identity();
IceMaths::Sphere opcSphere;
OgreOpcodeUtils::ogreToIceSphere(ball, opcSphere);
// validate settings: asserts that we can check collision
// another option is to display some annoying error windows using: Ogre::String(collider.ValidateSettings() )
assert( collider.ValidateSettings() == 0 );
// perform collision
if( !collider.Collide(cache, opcSphere, opcModel, ptrIdentity, ptrOpcMatrix) )
return false;
collPair.numBVBVTests = collider.GetNbVolumeBVTests();
collPair.numBVPrimTests = collider.GetNbVolumePrimTests();
collPair.numPrimPrimTests = 0;
// get collision result
if (collider.GetContactStatus())
{
// fill out contact point and collision normal of closest contact
const udword* collFaces = collider.GetTouchedPrimitives();
int numFaces = collider.GetNbTouchedPrimitives();
//LogManager::getSingleton().logMessage("sphereCheck returned " + StringConverter::toString(numFaces) + " numfaces");
if (numFaces > 0)
{
for(int i = 0; i < numFaces; i++)
{
//assert(1 == numFaces);
// build triangle from from faceIndex
Vector3 v0,v1,v2;
getTriCoords(collFaces[i], v0, v1, v2);
// Compute the centered normal
Vector3 vCenter = (v0+v1+v2)*0.33333333333333333333f;
Vector3 vNormal = (v1-v0).crossProduct(v2-v0);
vNormal.normalise();
Vector3 thePoint = ownMatrix * vCenter;
Plane thePlane(vNormal, thePoint);
Real theDist = thePlane.getDistance(ball.getCenter());
// fill collide report
if(0 == i)
{
collPair.this_normal = vNormal;
collPair.other_normal = -collPair.this_normal;
collPair.contact = ownMatrix * vCenter;//ball.getCenter() + collPair.this_normal * theDist;
}
CollisionInfo collInfo;
collInfo.this_normal = vNormal;
collInfo.other_normal = -collPair.this_normal;
collInfo.contact = ownMatrix * vCenter;
collPair.collInfos.push_back(collInfo);
}
return true;
}
else
{
//n_printf("nOpcodeShape::sphereCheck(): contact but no faces!\n");
return false;
}
}
// FIXME!
return false;
}
//------------------------------------------------------------------------
/// Render a AABBCollisionNode and recurse.
/// @param [in, out] node const Opcode::AABBCollisionNode * AABBCollisionNode to visualize.
void ICollisionShape::visualizeAABBCollisionNode(const Opcode::AABBCollisionNode* node)
{
assert(node);
Vector3 center(node->mAABB.mCenter.x, node->mAABB.mCenter.y, node->mAABB.mCenter.z);
Vector3 extent(node->mAABB.mExtents.x, node->mAABB.mExtents.y, node->mAABB.mExtents.z);
Vector3 v00(center.x - extent.x, center.y - extent.y, center.z - extent.z);
Vector3 v01(center.x - extent.x, center.y - extent.y, center.z + extent.z);
Vector3 v02(center.x + extent.x, center.y - extent.y, center.z + extent.z);
Vector3 v03(center.x + extent.x, center.y - extent.y, center.z - extent.z);
Vector3 v10(center.x - extent.x, center.y + extent.y, center.z - extent.z);
Vector3 v11(center.x - extent.x, center.y + extent.y, center.z + extent.z);
Vector3 v12(center.x + extent.x, center.y + extent.y, center.z + extent.z);
Vector3 v13(center.x + extent.x, center.y + extent.y, center.z - extent.z);
const Matrix4 &m = getFullTransform();
v00 = m * v00;
v01 = m * v01;
v02 = m * v02;
v03 = m * v03;
v10 = m * v10;
v11 = m * v11;
v12 = m * v12;
v13 = m * v13;
//// render ground rect
mActiveDebugger->addAABBLine(v00.x, v00.y, v00.z, v01.x, v01.y, v01.z);
mActiveDebugger->addAABBLine(v01.x, v01.y, v01.z, v02.x, v02.y, v02.z);
mActiveDebugger->addAABBLine(v02.x, v02.y, v02.z, v03.x, v03.y, v03.z);
mActiveDebugger->addAABBLine(v03.x, v03.y, v03.z, v00.x, v00.y, v00.z);
//// render top rect
mActiveDebugger->addAABBLine(v10.x, v10.y, v10.z, v11.x, v11.y, v11.z);
mActiveDebugger->addAABBLine(v11.x, v11.y, v11.z, v12.x, v12.y, v12.z);
mActiveDebugger->addAABBLine(v12.x, v12.y, v12.z, v13.x, v13.y, v13.z);
mActiveDebugger->addAABBLine(v13.x, v13.y, v13.z, v10.x, v10.y, v10.z);
//// render vertical lines
mActiveDebugger->addAABBLine(v00.x, v00.y, v00.z, v10.x, v10.y, v10.z);
mActiveDebugger->addAABBLine(v01.x, v01.y, v01.z, v11.x, v11.y, v11.z);
mActiveDebugger->addAABBLine(v02.x, v02.y, v02.z, v12.x, v12.y, v12.z);
mActiveDebugger->addAABBLine(v03.x, v03.y, v03.z, v13.x, v13.y, v13.z);
if (!node->IsLeaf())
{
const Opcode::AABBCollisionNode* neg = node->GetNeg();
const Opcode::AABBCollisionNode* pos = node->GetPos();
if (neg)
visualizeAABBCollisionNode(neg);
if (pos)
visualizeAABBCollisionNode(pos);
}
}
//------------------------------------------------------------------------
/// Render a AABBCollisionNode and recurse.
/// @param [in, out] node const Opcode::AABBNoLeafNode * AABBNoLeafNode to visualize.
void ICollisionShape::visualizeAABBNoLeafNode(const Opcode::AABBNoLeafNode* node)
{
assert(node);
Vector3 center(node->mAABB.mCenter.x, node->mAABB.mCenter.y, node->mAABB.mCenter.z);
Vector3 extent(node->mAABB.mExtents.x, node->mAABB.mExtents.y, node->mAABB.mExtents.z);
Vector3 v00(center.x - extent.x, center.y - extent.y, center.z - extent.z);
Vector3 v01(center.x - extent.x, center.y - extent.y, center.z + extent.z);
Vector3 v02(center.x + extent.x, center.y - extent.y, center.z + extent.z);
Vector3 v03(center.x + extent.x, center.y - extent.y, center.z - extent.z);
Vector3 v10(center.x - extent.x, center.y + extent.y, center.z - extent.z);
Vector3 v11(center.x - extent.x, center.y + extent.y, center.z + extent.z);
Vector3 v12(center.x + extent.x, center.y + extent.y, center.z + extent.z);
Vector3 v13(center.x + extent.x, center.y + extent.y, center.z - extent.z);
const Matrix4 &m = getFullTransform();
v00 = m * v00;
v01 = m * v01;
v02 = m * v02;
v03 = m * v03;
v10 = m * v10;
v11 = m * v11;
v12 = m * v12;
v13 = m * v13;
//// render ground rect
mActiveDebugger->addAABBLine(v00.x, v00.y, v00.z, v01.x, v01.y, v01.z);
mActiveDebugger->addAABBLine(v01.x, v01.y, v01.z, v02.x, v02.y, v02.z);
mActiveDebugger->addAABBLine(v02.x, v02.y, v02.z, v03.x, v03.y, v03.z);
mActiveDebugger->addAABBLine(v03.x, v03.y, v03.z, v00.x, v00.y, v00.z);
//// render top rect
mActiveDebugger->addAABBLine(v10.x, v10.y, v10.z, v11.x, v11.y, v11.z);
mActiveDebugger->addAABBLine(v11.x, v11.y, v11.z, v12.x, v12.y, v12.z);
mActiveDebugger->addAABBLine(v12.x, v12.y, v12.z, v13.x, v13.y, v13.z);
mActiveDebugger->addAABBLine(v13.x, v13.y, v13.z, v10.x, v10.y, v10.z);
//// render vertical lines
mActiveDebugger->addAABBLine(v00.x, v00.y, v00.z, v10.x, v10.y, v10.z);
mActiveDebugger->addAABBLine(v01.x, v01.y, v01.z, v11.x, v11.y, v11.z);
mActiveDebugger->addAABBLine(v02.x, v02.y, v02.z, v12.x, v12.y, v12.z);
mActiveDebugger->addAABBLine(v03.x, v03.y, v03.z, v13.x, v13.y, v13.z);
if (!node->HasNegLeaf())
{
const Opcode::AABBNoLeafNode* neg = node->GetNeg();
visualizeAABBNoLeafNode(neg);
}
if (!node->HasPosLeaf())
{
const Opcode::AABBNoLeafNode* pos = node->GetPos();
visualizeAABBNoLeafNode(pos);
}
}
//------------------------------------------------------------------------
/// Renders the collide model triangle soup.
void ICollisionShape::visualize(Details::OgreOpcodeDebugger* activeDebugger)
{
if(!mDebugObject->isAttached())
mParentNode->attachObject(mDebugObject);
mDebugObject->begin("OgreOpcodeDebug/Shapes", Ogre::RenderOperation::OT_LINE_LIST);
mActiveDebugger = activeDebugger;
assert(mVertexBuf && mFaceBuf);
// render the triangle soup
size_t i;
for (i = 0; i < numFaces; i++)
{
size_t* indexPtr = mFaceBuf + 3 * i;
float* v0 = mVertexBuf + 3 * indexPtr[0];
float* v1 = mVertexBuf + 3 * indexPtr[1];
float* v2 = mVertexBuf + 3 * indexPtr[2];
//const Matrix4 &m = getFullTransform();
Vector3 vect0(v0[0],v0[1],v0[2]);
Vector3 vect1(v1[0],v1[1],v1[2]);
Vector3 vect2(v2[0],v2[1],v2[2]);
//vect0 = m * vect0;
//vect1 = m * vect1;
//vect2 = m * vect2;
mDebugObject->position(vect0.x, vect0.y, vect0.z);
mDebugObject->position(vect1.x, vect1.y, vect1.z);
mDebugObject->position(vect1.x, vect1.y, vect1.z);
mDebugObject->position(vect2.x, vect2.y, vect2.z);
mDebugObject->position(vect2.x, vect2.y, vect2.z);
mDebugObject->position(vect0.x, vect0.y, vect0.z);
}
mDebugObject->end();
}
//------------------------------------------------------------------------
/// <TODO: insert function description here>
void ICollisionShape::visualizeAABBs(Details::OgreOpcodeDebugger* activeDebugger)
{
mActiveDebugger = activeDebugger;
// render the AABB tree
if (opcModel.HasLeafNodes())
{
const Opcode::AABBCollisionTree* tree = static_cast<const Opcode::AABBCollisionTree*>(opcModel.GetTree());
visualizeAABBCollisionNode(tree->GetNodes());
}
else
{
const Opcode::AABBNoLeafTree* tree = static_cast<const Opcode::AABBNoLeafTree*>(opcModel.GetTree());
visualizeAABBNoLeafNode(tree->GetNodes());
}
}
//------------------------------------------------------------------------
void ICollisionShape::_prepareOpcodeCreateParams(Opcode::OPCODECREATE& opcc)
{
opcc.mIMesh = &opcMeshAccess;
//opcc.mSettings.mRules = Opcode::SPLIT_BEST_AXIS;//Opcode::SPLIT_SPLATTER_POINTS; // split by splattering primitive centers (???)
opcc.mSettings.mRules = Opcode::SPLIT_GEOM_CENTER | Opcode::SPLIT_SPLATTER_POINTS; // Recommended by Opcode manual
opcc.mSettings.mLimit = 1; // build a complete tree, 1 primitive/node
opcc.mNoLeaf = true; // false;
opcc.mQuantized = false; // true;
}
}
//------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -