⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iogrecollisionshape.cpp

📁 opcode是功能强大
💻 CPP
📖 第 1 页 / 共 3 页
字号:
///////////////////////////////////////////////////////////////////////////////
///  @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 + -