📄 ogrecollisioncontext.cpp
字号:
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
if( (*i)->hasCollisions() || (*i)->hasCheckCollisions() )
(*i)->getShape()->visualize(mVisualDebugger);
}
//mVisualDebugger->endShapes();
}
if(doAABBs)
{
mVisualDebugger->beginAABBs();
for (attached_list_iterator i = attached_list.begin(); i != attached_list.end(); ++i)
{
if( (*i)->hasCollisions() || (*i)->hasCheckCollisions() )
(*i)->getShape()->visualizeAABBs(mVisualDebugger);
}
mVisualDebugger->endAABBs();
}
}
}
}
/// Do an instant check of a moving sphere in the collision volume.
/// Fills out the provided collide report array and
/// returns number of detected collisions.
/// @param p0 [in] starting position
/// @param v0 [in] vector to ending position
/// @param radius [in] radius
/// @param collClass [in] collision class for collision type query
/// @param cr_ptr [out] pointer to array of pointers to CollisionPair's
/// @return number of detected contacts (1 per collide object)
int CollisionContext::sweptSphereCheck(const Vector3& position, const Vector3& movementVector, Real radius, CollisionClass collClass, CollisionPair **& cpPtr, String ignorename)
{
// create a bounding box from the start and end position
Vector3 endPosition(position + movementVector);
Vector3 minv(n_min(position.x, endPosition.x) - radius,
n_min(position.y, endPosition.y) - radius,
n_min(position.z, endPosition.z) - radius);
Vector3 maxv(n_max(position.x, endPosition.x) + radius,
n_max(position.y, endPosition.y) + radius,
n_max(position.z, endPosition.z) + radius);
const int own_id = 0xffff;
// initialize collision report handler
checkReportHandler.beginFrame();
// This simply goes through all attached objects, and
// checks them for overlap, so ITS SLOW! Every object is
// tested exactly once
for (attached_list_iterator other = attached_list.begin(); other != attached_list.end(); ++other)
{
// see if we have overlaps in all 3 dimensions
if ((minv.x < (*other)->maxv.x) && (maxv.x > (*other)->minv.x) &&
(minv.y < (*other)->maxv.y) && (maxv.y > (*other)->minv.y) &&
(minv.z < (*other)->maxv.z) && (maxv.z > (*other)->minv.z))
{
// see if the candidate is in the ignore types set
CollisionType ct = CollisionManager::getSingletonPtr()->queryCollType(collClass,(*other)->getCollClass());
if (COLLTYPE_IGNORE == ct) continue;
checkReportHandler.mTotalObjObjTests++;
if((*other)->getName() != ignorename)
{
if (COLLTYPE_QUICK == ct)
{
// Trying to extract position information from provided matrices.
Vector3 p1 = Vector3((*other)->old_matrix[0][3], (*other)->old_matrix[1][3], (*other)->old_matrix[2][3]);
Vector3 v1 = Vector3(Vector3((*other)->new_matrix[0][3], (*other)->new_matrix[1][3], (*other)->new_matrix[2][3]) - p1);
// do the contact check between 2 moving spheres
sphere s0(position,radius);
sphere s1(p1,(*other)->getRadius());
float u0,u1;
checkReportHandler.mTotalBVBVTests++;
if (s0.intersect_sweep(movementVector,s1,v1,u0,u1))
{
if ((u0>=0.0f) && (u0<1.0f))
{
// we have contact!
// compute the 2 midpoints at the time of collision
Vector3 c0(position + movementVector*u0);
Vector3 c1(p1 + v1*u0);
// compute the collide normal
Vector3 d(c1-c0);
if (d.length() > TINY)
{
d.normalise();
} else
{
d = Vector3(0.0f, 1.0f, 0.0f);
}
// fill out a collide report and add to report handler
CollisionPair cr;
cr.this_object = (*other);
cr.other_object = (*other);
cr.tstamp = 0.0;
CollisionInfo collInfo;
collInfo.contact = (d*radius) + c0;
collInfo.this_normal = d;
collInfo.other_normal = -d;
cr.collInfos.push_back(collInfo);
checkReportHandler.addCollision(cr,own_id,(*other)->id);
}
}
}
else // CONTACT and EXACT
{
// do sphere-shape collision check
ICollisionShape* shape = (*other)->getShape();
if (shape)
{
CollisionPair cp;
cp.this_object = (*other);
cp.other_object = (*other);
bool ret = shape->sweptSphereCheck(ct, (*other)->getTransform(), position, movementVector, radius, cp);
checkReportHandler.mTotalBVBVTests += cp.numBVBVTests;
checkReportHandler.mTotalBVPrimTests += cp.numBVPrimTests;
if (ret)
{
cp.this_object = (*other);
cp.other_object = (*other);
checkReportHandler.addCollision(cp, own_id, (*other)->id);
}
}
}
}
}
}
checkReportHandler.endFrame();
return checkReportHandler.getAllCollisions(cpPtr);
}
/// Test a ray against the collide objects in the collide context.
/// The collType will be interpreted as follows:
/// - COLLTYPE_IGNORE: illegal (makes no sense)
/// - COLLTYPE_QUICK: occlusion check only
/// - COLLTYPE_CONTACT: return closest contact only
/// - COLLTYPE_EXACT: return all contacts (unsorted)
/// @param line [in] the ray to test in global space
/// @param collType [in] the collision type
/// @param collClass [in] optional coll class (COLLCLASS_ALWAYS_* if no coll class filtering wanted)
/// @param cpPtr [out] will be filled with pointer to collide report pointers
/// @return number of detected contacts (1 per collide object)
int CollisionContext::rayCheck(const Ogre::Ray line, const Real dist, CollisionType collType, CollisionClass collClass, CollisionPair**& cpPtr)
{
assert(collType != COLLTYPE_IGNORE);
// create a bounding box from the line
bbox3 bbox;
bbox.begin_grow();
bbox.grow(line.getOrigin());
bbox.grow(line.getPoint(dist));
const int ownId = 0xffff;
// initialize collision report handler
checkReportHandler.beginFrame();
// go through all attached collide objects
for (attached_list_iterator co = attached_list.begin(); co != attached_list.end(); ++co)
{
Vector3 coMin = (*co)->minv;
Vector3 coMax = (*co)->maxv;
// see if we have overlaps in all 3 dimensions
if (intervalOverlap(bbox.vmin.x,bbox.vmax.x,coMin.x,coMax.x) &&
intervalOverlap(bbox.vmin.y,bbox.vmax.y,coMin.y,coMax.y) &&
intervalOverlap(bbox.vmin.z,bbox.vmax.z,coMin.z,coMax.z) )
{
// see if the candidate is in the ignore types set
CollisionType ct = CollisionManager::getSingletonPtr()->queryCollType(collClass, (*co)->getCollClass());
if (COLLTYPE_IGNORE == ct)
{
continue;
}
// check collision
ICollisionShape* shape = (*co)->getShape();
if (shape)
{
checkReportHandler.mTotalObjObjTests++;
CollisionPair cp;
bool ret = shape->rayCheck(collType, (*co)->getTransform(), line, dist, cp, mRayCulling);
checkReportHandler.mTotalBVBVTests += cp.numBVBVTests;
checkReportHandler.mTotalBVBVTests += cp.numBVPrimTests;
if (ret)
{
cp.this_object = (*co);
cp.other_object = (*co);
checkReportHandler.addCollision(cp, ownId, (*co)->id);
if (COLLTYPE_QUICK == collType)
{
// break out of loop
break;
}
}
}
}
}
checkReportHandler.endFrame();
//if (COLLTYPE_CONTACT == collType) // FIXME!
//{
// // get closest contact only
// return checkReportHandler.getClosestCollision(line.getOrigin(), cpPtr);
//}
//else
//{
// get all contacts (unsorted)
return checkReportHandler.getAllCollisions(cpPtr);
//}
}
/// Test a sphere against the collide objects in the collide context.
/// The collType will be interpreted as follows:
/// - COLLTYPE_IGNORE: illegal (makes no sense)
/// - COLLTYPE_QUICK: return all contacts, do sphere-sphere check
/// - COLLTYPE_CONTACT: return closest contact only, sphere-shape
/// - COLLTYPE_EXACT: return all contacts (unsorted), sphere-shape
/// @param theSphere [in] the sphere to test in global space
/// @param collType [in] the collision type
/// @param collClass [in] optional coll class (COLLCLASS_ALWAYS_* if no coll class filtering wanted)
/// @param cpPtr [out] will be filled with pointer to collide report pointers
/// @return number of detected contacts (1 per collide object)
int CollisionContext::sphereCheck(const Sphere& theSphere, CollisionType collType, CollisionClass collClass, CollisionPair**& cpPtr)
{
assert(collType != COLLTYPE_IGNORE);
sphere ball;
ball.set(theSphere.getCenter(),theSphere.getRadius());
// create a bounding box from the sphere
Vector3 vmin(ball.p.x - ball.r, ball.p.y - ball.r, ball.p.z - ball.r);
Vector3 vmax(ball.p.x + ball.r, ball.p.y + ball.r, ball.p.z + ball.r);
bbox3 bbox(vmin, vmax);
const int ownId = 0xffff;
// initialize collision report handler
checkReportHandler.beginFrame();
// go through all attached collide objects
sphere s0;
for (attached_list_iterator co = attached_list.begin(); co != attached_list.end(); ++co)
{
// see if we have overlaps in all 3 dimensions
if ((bbox.vmin.x < (*co)->maxv.x) && (bbox.vmax.x > (*co)->minv.x) &&
(bbox.vmin.y < (*co)->maxv.y) && (bbox.vmax.y > (*co)->minv.y) &&
(bbox.vmin.z < (*co)->maxv.z) && (bbox.vmax.z > (*co)->minv.z))
{
// see if the candidate is in the ignore types set
CollisionType ct = CollisionManager::getSingletonPtr()->queryCollType(collClass, (*co)->getCollClass());
if (COLLTYPE_IGNORE == ct)
{
continue;
}
checkReportHandler.mTotalObjObjTests++;
if (COLLTYPE_QUICK == ct)
{
// do sphere-sphere collision check
const Matrix4 coTrans = (*co)->getTransform();
//s0.set(coTrans[0][3], coTrans[1][3], coTrans[2][3], (*co)->getRadius());
s0.set((*co)->getShape()->getCenter(), (*co)->getRadius());
checkReportHandler.mTotalBVBVTests++;
if (ball.intersects(s0))
{
CollisionPair cp;
cp.this_object = (*co);
cp.other_object = (*co);
checkReportHandler.addCollision(cp, ownId, (*co)->id);
}
}
else
{
// do sphere-shape collision check
ICollisionShape* shape = (*co)->getShape();
if (shape)
{
CollisionPair cp;
bool ret = shape->sphereCheck(collType, (*co)->getTransform(), theSphere, cp);
checkReportHandler.mTotalBVBVTests += cp.numBVBVTests;
checkReportHandler.mTotalBVPrimTests += cp.numBVPrimTests;
if (ret)
{
cp.this_object = (*co);
cp.other_object = (*co);
checkReportHandler.addCollision(cp, ownId, (*co)->id);
}
}
}
}
}
checkReportHandler.endFrame();
//if (COLLTYPE_CONTACT == collType)
//{
// // get closest contact only
// return checkReportHandler.getClosestCollision(ball.p, cpPtr);
//}
//else
//{
// get all contacts (unsorted)
return checkReportHandler.getAllCollisions(cpPtr);
//}
}
void CollisionContext::update(Real dt)
{
for (attached_list_iterator co = attached_list.begin(); co != attached_list.end(); ++co)
{
(*co)->update(dt);
}
}
/// reset position and timestamp of all attached collide objects to 0.0.
/// This is useful at the beginning of a level to prevent phantom collisions
/// (when objects are repositioned to their starting point in the level).
void CollisionContext::reset()
{
Matrix4 identity = Matrix4::IDENTITY;
for (attached_list_iterator co = attached_list.begin(); co != attached_list.end(); ++co)
{
// This must be done twice, so that old timestamp also becomes 0
(*co)->update(-1.0, identity);
(*co)->update(-1.0, identity);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -