📄 iogrecollisionshape.cpp
字号:
///////////////////////////////////////////////////////////////////////////////
/// @file IOgreCollisionShape.cpp
/// @brief <TODO: insert file description here>
///
/// @author The OgreOpcode Team
///
///////////////////////////////////////////////////////////////////////////////
///
/// This file is part of OgreOpcode.
///
/// A lot of the code is based on the Nebula Opcode Collision module, see docs/Nebula_license.txt
///
/// OgreOpcode is free software; you can redistribute it and/or
/// modify it under the terms of the GNU Lesser General Public
/// License as published by the Free Software Foundation; either
/// version 2.1 of the License, or (at your option) any later version.
///
/// OgreOpcode is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
/// Lesser General Public License for more details.
///
/// You should have received a copy of the GNU Lesser General Public
/// License along with OgreOpcode; if not, write to the Free Software
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
///
///////////////////////////////////////////////////////////////////////////////
#include "OgreOpcodeExports.h"
#include "IOgreCollisionShape.h"
#include "OgreCollisionReporter.h"
#include "OgreCollisionManager.h"
#include "OgreOpcodeMath.h"
#include "OgreOpcodeUtils.h"
using namespace Ogre;
using namespace OgreOpcode::Details;
namespace OgreOpcode
{
namespace Details
{
template<class NodeT>
inline void GetOpcodeNodeCenter(const NodeT &n, Vector3 &ctr)
{
ctr.x = n.mAABB.mCenter.x;
ctr.y = n.mAABB.mCenter.y;
ctr.z = n.mAABB.mCenter.z;
}
template<class TreeT, class NodeT>
inline void GetOpcodeQuantizedNodeCenter(const TreeT &tree, const NodeT &n, Vector3 &ctr)
{
ctr = Vector3(float(n.mAABB.mCenter[0]), float(n.mAABB.mCenter[1]), float(n.mAABB.mCenter[2]));
ctr.x *= tree.mCenterCoeff.x;
ctr.y *= tree.mCenterCoeff.y;
ctr.z *= tree.mCenterCoeff.z;
}
template<class NodeT>
inline void GetOpcodeNodeMinMaxBox(const NodeT &n, Vector3 &bmin, Vector3 &bMax)
{
Vector3 center(n.mAABB.mCenter.x, n.mAABB.mCenter.y, n.mAABB.mCenter.z);
Vector3 extent(n.mAABB.mExtents.x, n.mAABB.mExtents.y, n.mAABB.mExtents.z);
bmin = center;
bmin -= extent;
bMax = center;
bMax += extent;
}
template<class TreeT, class NodeT>
inline void GetOpcodeQuantizedNodeMinMaxBox(const TreeT &tree, const NodeT &n, Vector3 &bmin, Vector3 &bMax)
{
Vector3 center(float(n.mAABB.mCenter[0]), float(n.mAABB.mCenter[1]), float(n.mAABB.mCenter[2]));
Vector3 extent(float(n.mAABB.mExtents[0]), float(n.mAABB.mExtents[1]), float(n.mAABB.mExtents[2]));
extent.x *= tree.mExtentsCoeff.x;
extent.y *= tree.mExtentsCoeff.y;
extent.z *= tree.mExtentsCoeff.z;
center.x *= tree.mCenterCoeff.x;
center.y *= tree.mCenterCoeff.y;
center.z *= tree.mCenterCoeff.z;
bmin = center;
bmin -= extent;
bMax = center;
bMax += extent;
}
inline void GetOpcodeRootCenter(const Opcode::Model &mdl, Vector3 &ctr)
{
if (mdl.IsQuantized()) {
if (mdl.HasLeafNodes()) {
const Opcode::AABBQuantizedTree& tree = *static_cast<const Opcode::AABBQuantizedTree*>(mdl.GetTree());
GetOpcodeQuantizedNodeCenter(tree, *tree.GetNodes(), ctr);
}
else{
const Opcode::AABBQuantizedNoLeafTree& tree = *static_cast<const Opcode::AABBQuantizedNoLeafTree*>(mdl.GetTree());
GetOpcodeQuantizedNodeCenter(tree, *tree.GetNodes(), ctr);
}
}
else{
if (mdl.HasLeafNodes()) {
const Opcode::AABBCollisionNode& root = *static_cast<const Opcode::AABBCollisionTree*>(mdl.GetTree())->GetNodes();
GetOpcodeNodeCenter(root, ctr);
}
else{
const Opcode::AABBNoLeafNode& root = *static_cast<const Opcode::AABBNoLeafTree*>(mdl.GetTree())->GetNodes();
GetOpcodeNodeCenter(root, ctr);
}
}
}
inline void GetOpcodeRootMinMaxBox(const Opcode::Model &mdl, Vector3 &bmin, Vector3 &bMax)
{
if (mdl.IsQuantized()) {
if (mdl.HasLeafNodes()) {
const Opcode::AABBQuantizedTree& tree = *static_cast<const Opcode::AABBQuantizedTree*>(mdl.GetTree());
GetOpcodeQuantizedNodeMinMaxBox(tree, *tree.GetNodes(), bmin, bMax);
}
else{
const Opcode::AABBQuantizedNoLeafTree& tree = *static_cast<const Opcode::AABBQuantizedNoLeafTree*>(mdl.GetTree());
GetOpcodeQuantizedNodeMinMaxBox(tree, *tree.GetNodes(), bmin, bMax);
}
}
else{
if (mdl.HasLeafNodes()) {
const Opcode::AABBCollisionNode& root = *static_cast<const Opcode::AABBCollisionTree*>(mdl.GetTree())->GetNodes();
GetOpcodeNodeMinMaxBox(root, bmin, bMax);
}
else{
const Opcode::AABBNoLeafNode& root = *static_cast<const Opcode::AABBNoLeafTree*>(mdl.GetTree())->GetNodes();
GetOpcodeNodeMinMaxBox(root, bmin, bMax);
}
}
}
} // Details
//------------------------------------------------------------------------
Ogre::String& ICollisionShape::getName()
{
return mName;
}
//------------------------------------------------------------------------
Vector3& ICollisionShape::getCenter()
{
// World space center
const Matrix4 &m = getFullTransform();
GetOpcodeRootCenter(opcModel, mCenter);
mCenter = m * mCenter;
return mCenter;
}
//------------------------------------------------------------------------
Vector3& ICollisionShape::getLocalCenter()
{
// Object space center
GetOpcodeRootCenter(opcModel, mLocalCenter);
return mLocalCenter;
}
//------------------------------------------------------------------------
void ICollisionShape::getMinMax(Vector3& bMin, Vector3& bMax) const
{
// Compute the tightest world space box around the current opcode AABB tree
const Matrix4 &m = getFullTransform();
Vector3 lMin,lMax;
GetOpcodeRootMinMaxBox(opcModel, lMin, lMax);
bMax = bMin = m * lMin;
Vector3 v;
v=m*Vector3(lMin.x,lMin.y,lMin.z); bMin.makeFloor(v); bMax.makeCeil(v);
v=m*Vector3(lMin.x,lMin.y,lMax.z); bMin.makeFloor(v); bMax.makeCeil(v);
v=m*Vector3(lMin.x,lMax.y,lMin.z); bMin.makeFloor(v); bMax.makeCeil(v);
v=m*Vector3(lMin.x,lMax.y,lMax.z); bMin.makeFloor(v); bMax.makeCeil(v);
v=m*Vector3(lMax.x,lMin.y,lMin.z); bMin.makeFloor(v); bMax.makeCeil(v);
v=m*Vector3(lMax.x,lMin.y,lMax.z); bMin.makeFloor(v); bMax.makeCeil(v);
v=m*Vector3(lMax.x,lMax.y,lMin.z); bMin.makeFloor(v); bMax.makeCeil(v);
v=m*Vector3(lMax.x,lMax.y,lMax.z); bMin.makeFloor(v); bMax.makeCeil(v);
}
//------------------------------------------------------------------------
void ICollisionShape::getLocalMinMax(Vector3& lMin, Vector3& lMax) const
{
// Get the local object space box around the current opcode AABB tree
GetOpcodeRootMinMaxBox(opcModel, lMin, lMax);
}
//------------------------------------------------------------------------
void ICollisionShape::calculateSize()
{
// This just calcs the radius. The world AABB has to be computed on demand
// because it depends on the current parent node transform.
// But the radius is the radius no matter what.
Vector3 lMin,lMax;
getMinMax(lMin,lMax);
lMax-=lMin;
mRadius = lMax.length()*0.5;
}
//void ICollisionShape::computeIceABB()
//{
// Vector3 vA, vB;
// getMinMax(vA,vB);
// mIceABB->SetMinMax(IceMaths::Point(vA.x, vA.y, vA.z), IceMaths::Point(vB.x, vB.y, vB.z));
//}
//------------------------------------------------------------------------
//IceMaths::AABB* ICollisionShape::getIceABB(void) const
//{
// return mIceABB;
//}
//------------------------------------------------------------------------
ICollisionShape::ICollisionShape(const Ogre::String& name)
: mInitialized(false),
mShapeIsStatic(false),
mHasCostumTransform(false),
mDoVisualizeAABBNodes(false),
mName(name),
mRadius(0.0f),
numVertices(0),
numFaces(0),
mVertexBuf(0),
mFaceBuf(0),
mFullTransform(Matrix4::IDENTITY),
mLocalTransform(Matrix4::IDENTITY),
mActiveDebugger(0),
mRefitCounter(0),
mNumFramesPerRefit(0),
mParentNode(0)
{
//mIceABB = new IceMaths::AABB();
//mIceABB->SetEmpty();
// initialize pointers to global OPCODE objects
opcTreeCache = &(CollisionManager::getSingletonPtr()->opcTreeCache);
opcFaceCache = &(CollisionManager::getSingletonPtr()->opcFaceCache);
mDebugObject = new ManualObject("__OgreOpcode__Debugger__" + mName);
}
//------------------------------------------------------------------------
ICollisionShape::~ICollisionShape()
{
//delete mIceABB;
//if(mDebugObject->isAttached())
// mDebugObject->getParentSceneNode()->detachObject(mDebugObject->getName());
delete mDebugObject;
}
void ICollisionShape::update(Ogre::Real dt)
{
if( mNumFramesPerRefit > 0 )
{
++mRefitCounter;
if( mRefitCounter >= mNumFramesPerRefit )
{
refit();
mRefitCounter = 0;
}
}
}
int ICollisionShape::getRefitRate()
{
return mNumFramesPerRefit;
}
void ICollisionShape::setRefitRate(unsigned int NumFramesPerRefit)
{
mNumFramesPerRefit = NumFramesPerRefit;
}
Matrix4 ICollisionShape::getFullTransform(void) const
{
if(!mHasCostumTransform)
{
getParentSceneNode()->_update(true, true);
getParentSceneNode()->getWorldTransforms(&mFullTransform);
}
return mFullTransform;
}
Matrix4& ICollisionShape::getLocalTransform(void) const
{
if(!mHasCostumTransform)
{
mLocalTransform = mFullTransform.inverse();
}
return mLocalTransform;
}
//------------------------------------------------------------------------
/// set a costum transform.
/// @param newTransform Matrix4 The matrix you want the shape to be transformed by.
void ICollisionShape::setTransform(const Matrix4 newTransform)
{
mLocalTransform = mFullTransform = newTransform;
mHasCostumTransform = true;
}
//------------------------------------------------------------------------
/// perform collision with other ICollisionShape.
/// @param collType CollisionType Collision type.
/// @param ownMatrix Matrix4 Own matrix.
/// @param otherShape ICollisionShape Shape to test against.
/// @param otherMatrix Matrix4 Other matrix.
/// @param collPair CollisionPair Collision report.
/// @return bool return true on collision.
bool ICollisionShape::collide(CollisionType collType, Matrix4& ownMatrix, ICollisionShape* otherShape, Matrix4& otherMatrix, CollisionPair& collPair)
{
assert(otherShape);
assert((collType == COLLTYPE_EXACT) || (collType == COLLTYPE_CONTACT));
ICollisionShape* opcodeOther = otherShape;
Opcode::AABBTreeCollider& collider = CollisionManager::getSingletonPtr()->opcTreeCollider;
if (collType == COLLTYPE_EXACT)
{
collider.SetFirstContact(false);
}
else
{
collider.SetFirstContact(true);
}
// setup the bvt cache
opcTreeCache->Model0 = &(opcModel);
opcTreeCache->Model1 = &(opcodeOther->opcModel);
// convert Matrix4's into Matrix4x4's
IceMaths::Matrix4x4 m0, m1;
OgreOpcodeUtils::ogreToIceMatrix4( ownMatrix, m0);
OgreOpcodeUtils::ogreToIceMatrix4( otherMatrix, m1);
// 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 test and checks errors
if( !collider.Collide(*(opcTreeCache), &m0, &m1) )
return false;
collPair.numBVBVTests = collider.GetNbBVBVTests();
collPair.numBVPrimTests = collider.GetNbBVPrimTests();
collPair.numPrimPrimTests = collider.GetNbPrimPrimTests();
bool collided = false;
// get the number of collided triangle pairs
int numPairs = collider.GetNbPairs();
//LogManager::getSingleton().logMessage("Collisionshape had " + StringConverter::toString(numPairs) + " collisions.");
if ( collider.GetContactStatus() && numPairs > 0 )
{
collided = true;
// get the list of collided triangles
const Pair* pairs = collider.GetPairs();
// clamp number of collisions to a reasonable amount
if (numPairs > 10) numPairs = 10;
int i;
Vector3 vThis0, vThis1, vThis2;
Vector3 vOther0, vOther1, vOther2;
for (i = 0; i < numPairs; i++)
{
// get the current contact triangle coordinates
getTriCoords(pairs[i].id0, vThis0, vThis1, vThis2);
opcodeOther->getTriCoords(pairs[i].id1, vOther0, vOther1, vOther2);
// they are now in object space - transform to world space
vThis0 = ownMatrix * vThis0;
vThis1 = ownMatrix * vThis1;
vThis2 = ownMatrix * vThis2;
vOther0 = otherMatrix * vOther0;
vOther1 = otherMatrix * vOther1;
vOther2 = otherMatrix * vOther2;
// calculate midpoints and normals in world space
Vector3 thisCenter = (vThis0+vThis1+vThis2)*0.33333333333333333333f;
Vector3 thisNormal = (vThis1-vThis0).crossProduct(vThis2-vThis0);
thisNormal.normalise();
Vector3 otherCenter = (vOther0+vOther1+vOther2)*0.33333333333333333333f;
Vector3 otherNormal = (vOther1-vOther0).crossProduct(vOther2-vOther0);
otherNormal.normalise();
// fill out CollisionPair's CollisionInfo
CollisionInfo collInfo;
collInfo.contact = otherCenter;
collInfo.this_contact = thisCenter;
collInfo.other_contact = otherCenter;
collInfo.this_normal = thisNormal;
collInfo.other_normal = otherNormal;
// fill triangle vertex info (world space)
collInfo.this_tri_verts[0] = vThis0;
collInfo.this_tri_verts[1] = vThis1;
collInfo.this_tri_verts[2] = vThis2;
collInfo.other_tri_verts[0] = vOther0;
collInfo.other_tri_verts[1] = vOther1;
collInfo.other_tri_verts[2] = vOther2;
collPair.collInfos.push_back(collInfo);
if(0 == i) // if this is the first contact
{
collPair.contact = otherCenter;
collPair.this_contact = thisCenter;
collPair.other_contact = otherCenter;
collPair.this_normal = thisNormal;
collPair.other_normal = otherNormal;
}
}
}
return collided;
}
//------------------------------------------------------------------------
/// Check contact of line with shape.
/// The collType is interpreted as follows:
/// - COLLTYPE_IGNORE: illegal (makes no sense)
/// - COLLTYPE_QUICK: occlusion check only
/// - COLLTYPE_CONTACT: return closest contact
/// - COLLTYPE_EXACT: return a sorted list of contacts
/// @param collType see above
/// @param ownMatrix position/orientation of this shape
/// @param line line definition in world space
/// @param collPair will be filled with result
/// @return true if line intersects shape
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -