1
///////////////////////////////////////////////////////////////////////////////
2
/// @file OgreCollisionObject.cpp
3
/// @brief <TODO: insert file description here>
5
/// @author The OgreOpcode Team
7
///////////////////////////////////////////////////////////////////////////////
9
/// This file is part of OgreOpcode.
11
/// A lot of the code is based on the Nebula Opcode Collision module, see docs/Nebula_license.txt
13
/// OgreOpcode is free software; you can redistribute it and/or
14
/// modify it under the terms of the GNU Lesser General Public
15
/// License as published by the Free Software Foundation; either
16
/// version 2.1 of the License, or (at your option) any later version.
18
/// OgreOpcode is distributed in the hope that it will be useful,
19
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
20
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21
/// Lesser General Public License for more details.
23
/// You should have received a copy of the GNU Lesser General Public
24
/// License along with OgreOpcode; if not, write to the Free Software
25
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
///////////////////////////////////////////////////////////////////////////////
28
#include "OgreOpcodeExports.h"
29
#include "OgreCollisionObject.h"
30
#include "OgreCollisionReporter.h"
31
#include "OgreCollisionManager.h"
32
#include "OgreOpcodeMath.h"
33
#include "OgreOpcodeUtils.h"
38
using namespace OgreOpcode::Details;
42
void CollisionObject::getSAPMinMax(Vector3& sapMin, Vector3& sapMax) const
44
//sapMin = Vector3(n_min(old_minv.x,minv.x),
45
// n_min(old_minv.y,minv.y),
46
// n_min(old_minv.z,minv.z));
47
//sapMax = Vector3(n_max(old_maxv.x,maxv.x),
48
// n_max(old_maxv.y,maxv.y),
49
// n_max(old_maxv.z,maxv.z));
54
void CollisionObject::update(Real t, Matrix4& m)
58
mForcedUpdate = true; ///FIXME Blah. Do we really need this?
62
mNeedsUpdating = true;
66
Vector3 p0(old_matrix[0][3], old_matrix[1][3], old_matrix[2][3]);
67
Vector3 v0(new_matrix[0][3], new_matrix[1][3], new_matrix[2][3]);
68
Vector3 moved = p0 - v0;
70
bool hasMoved = (moved != Vector3::ZERO);
72
mNeedsUpdating = hasMoved;
77
// getShape()->computeIceABB();
80
old_matrix = new_matrix;
84
new_pos = getShape()->getParentSceneNode()->_getDerivedPosition();
85
// Get center in world space.
87
getShape()->getMinMax(lMin,lMax);
89
mRadius = lMax.length()*0.5;
93
getShape()->getMinMax(minv,maxv);
95
// if old_matrix etc are not yet valid,
96
// initialize with the current values, to prevent "startup popping"
97
bool oldValsInvalid = (m_tdelta <= 0.0);
100
old_matrix = new_matrix;
109
bool CollisionObject::contact(CollisionObject *other, // the other object
113
// This object moved from p0 to p0+v0, the other from p1 to p1+v1.
114
Vector3 p0(old_matrix[0][3], old_matrix[1][3], old_matrix[2][3]);
115
Vector3 p1(other->old_matrix[0][3], other->old_matrix[1][3], other->old_matrix[2][3]);
116
Vector3 v0(new_matrix[0][3], new_matrix[1][3], new_matrix[2][3]);
117
//Vector3 p0 = old_pos;
118
//Vector3 p1 = other->old_pos;
119
//Vector3 v0 = new_pos;
121
Vector3 v1(Vector3(other->new_matrix[0][3], other->new_matrix[1][3], other->new_matrix[2][3]) - p1);
122
//Vector3 v1(other->new_pos - p1);
124
bool has_contact = false;
129
// do a contact check between 'moving spheres'
130
sphere s0(p0,mRadius);
131
sphere s1(p1,other->mRadius);
133
if (s0.intersect_sweep(v0,s1,v1,u0,u1))
135
// there may be a valid contact somewhere along the path
136
if ((u0>=0.0f) && (u0<1.0f))
138
// compute the 2 midpoints at the time of collision
139
Vector3 c0(p0 + v0*u0);
140
Vector3 c1(p1 + v1*u0);
142
// compute the collide normal
144
if (d.length() > TINY)
149
d = Vector3(0.0f, 1.0f, 0.0f);
152
// compute the contact point
153
CollisionInfo collInfo;
154
collInfo.contact = (d*mRadius) + c0;
156
// compute the collide normals
157
collInfo.this_normal = d;
158
collInfo.other_normal = -d;
159
cr.collInfos.push_back(collInfo);
161
// compute the timestamp where the collision happened
162
cr.tstamp = m_tdelta*u0;
170
case COLLTYPE_CONTACT:
172
// If distance traveled is more then 1/8 then each of the object's
173
// radii, then we do several tests along the line
177
// This isn't likely to work particularly well for objects
178
// with large rotational motion. For that it would be better
179
// to blend the transformations along the path as well,
180
// and to also use amount of rotation in determining how many
181
// steps are necessary. That would bring this another step closer
182
// to being a true continuous collision detection system.
184
Real rq0 = mRadius * 0.125f;
185
Real rq1 = other->mRadius * 0.125f;
186
Real v0_len = v0.length();
187
Real v1_len = v1.length();
188
int num = (int) n_max((v0_len/rq0), (v1_len/rq1));
189
const int maxChecks = 16;
193
} else if (num > maxChecks)
197
Vector3 d0(v0 / float(num));
198
Vector3 d1(v1 / float(num));
199
Matrix4 self_matrix = old_matrix;
200
Matrix4 other_matrix = other->old_matrix;
203
for (i=0; i<num; i++)
207
self_matrix[0][3] = p0.x;
208
self_matrix[1][3] = p0.y;
209
self_matrix[2][3] = p0.z;
210
other_matrix[0][3] = p1.x;
211
other_matrix[1][3] = p1.y;
212
other_matrix[2][3] = p1.z;
213
if (mShape->collide(ct, self_matrix, other->getShape(), other_matrix, cr))
216
double dt = (m_tdelta) / num;
230
void CollisionObject::addToCollideList(CollisionObject* collObj)
232
collideList.push_back(collObj);
235
void CollisionObject::collide(void)
240
CollisionReporter *crh = &(mContext->collideReportHandler);
242
//LogManager::getSingleton().logMessage(getName() + " is about to test collisions.");
244
for (collideListIterator i = collideList.begin(); i != collideList.end(); ++i)
246
// is the candidate in the ignore types set?
247
CollisionObject *other = (*i);
249
//LogManager::getSingleton().logMessage(getName() + " is testing against " + other->getName());
251
// am I trying to collide with myself?
252
if ( id == other->id ) continue;
254
// query the collision type defined for those two objects
255
CollisionType ct = CollisionManager::getSingletonPtr()->queryCollType(getCollClass(),other->getCollClass());
258
if (COLLTYPE_IGNORE == ct) continue;
260
// has this collision already been checked by the other object?
261
if (!crh->collisionTested(id,other->id))
263
// no, we're first...
264
crh->mTotalObjObjTests++;
265
crh->addCollisionTest(id,other->id);
267
// ask objects whether they collide...
268
// FIXME: probably do velocity-based finer
269
// grained control here ?!?!?!
271
bool ret = contact(other,ct,cr);
272
crh->mTotalBVBVTests += cr.numBVBVTests;
273
crh->mTotalBVPrimTests += cr.numBVPrimTests;
274
crh->mTotalPrimPrimTests += cr.numPrimPrimTests;
277
cr.this_object = this;
278
cr.other_object = other;
279
crh->addCollision(cr,id,other->id);
286
mNeedsUpdating = false;
289
void CollisionObject::visualizeRadii()
291
// render the objects radii
293
Real dr = Ogre::Math::DegreesToRadians(5.0f);
294
Vector3 ctr = getShape()->getCenter();
295
for (dim=0; dim<3; dim++)
298
for (r=0.0f; r< Ogre::Math::DegreesToRadians(360.0f); r+=dr)
300
Real sin_r0 = (Real) sin(r);
301
Real cos_r0 = (Real) cos(r);
302
float sin_r1 = (Real) sin(r+dr);
303
Real cos_r1 = (Real) cos(r+dr);
304
Vector3 v0_x(0.0f, sin_r0*mRadius, cos_r0*mRadius); v0_x+=ctr;
305
Vector3 v1_x(0.0f, sin_r1*mRadius, cos_r1*mRadius); v1_x+=ctr;
306
Vector3 v0_y(sin_r0*mRadius, 0.0f, cos_r0*mRadius); v0_y+=ctr;
307
Vector3 v1_y(sin_r1*mRadius, 0.0f, cos_r1*mRadius); v1_y+=ctr;
308
Vector3 v0_z(sin_r0*mRadius, cos_r0*mRadius, 0.0f); v0_z+=ctr;
309
Vector3 v1_z(sin_r1*mRadius, cos_r1*mRadius, 0.0f); v1_z+=ctr;
311
getContext()->getVisualDebugger()->addRadiiLine(v0_x.x,v0_x.y,v0_x.z, v1_x.x,v1_x.y,v1_x.z);
312
getContext()->getVisualDebugger()->addRadiiLine(v0_y.x,v0_y.y,v0_y.z, v1_y.x,v1_y.y,v1_y.z);
313
getContext()->getVisualDebugger()->addRadiiLine(v0_z.x,v0_z.y,v0_z.z, v1_z.x,v1_z.y,v1_z.z);
318
void CollisionObject::visualizeContacts()
320
static int contactCount = 0;
321
static bool bufferContacts = true;
325
// Retrieve collision contact information and store them in mRecentContactList.
328
int num = mContext->getCollisions(this,pcr);
330
for (i = 0; i < num; i++)
332
CollisionPair *cr = pcr[i];
333
for (int currColl = 0; currColl < static_cast<int>(cr->collInfos.size()); currColl++)
338
CollisionInfo collInfo;
339
collInfo.contact = cr->collInfos[currColl].contact;
340
collInfo.this_normal = cr->collInfos[currColl].this_normal * 5;
341
collInfo.other_normal = cr->collInfos[currColl].other_normal * 5;
342
mRecentContactList.push_back(collInfo);
344
mRecentContactList.pop_front();
349
// render any collision contact points
350
if (mRecentContactList.size() > 0)
352
std::list<CollisionInfo>::iterator contactIter;
353
for (contactIter = mRecentContactList.begin(); contactIter != mRecentContactList.end(); ++contactIter)
355
Vector3 cnt = (*contactIter).contact;
356
getContext()->getVisualDebugger()->addContactLine(cnt.x-0.5f,cnt.y,cnt.z, cnt.x+0.5f,cnt.y,cnt.z);
357
getContext()->getVisualDebugger()->addContactLine(cnt.x,cnt.y-0.5f,cnt.z, cnt.x,cnt.y+0.5f,cnt.z);
358
getContext()->getVisualDebugger()->addContactLine(cnt.x,cnt.y,cnt.z-0.5f, cnt.x,cnt.y,cnt.z+0.5f);
360
Vector3 n = (*contactIter).this_normal * 5;
361
getContext()->getVisualDebugger()->addContactNormalsLine(cnt.x,cnt.y,cnt.z, cnt.x+n.x,cnt.y+n.y,cnt.z+n.z);
362
n = (*contactIter).other_normal * 5;
363
getContext()->getVisualDebugger()->addContactNormalsLine(cnt.x,cnt.y,cnt.z, cnt.x+n.x,cnt.y+n.y,cnt.z+n.z);
367
if(contactCount > 10)
368
bufferContacts = false;
371
void CollisionObject::visualizeBoundingBoxes()
373
// render the objects bounding boxes (stretched by their movement)
375
getShape()->getMinMax(v0,v1);
377
getContext()->getVisualDebugger()->addBBLine(v0.x,v0.y,v0.z, v1.x,v0.y,v0.z);
378
getContext()->getVisualDebugger()->addBBLine(v1.x,v0.y,v0.z, v1.x,v1.y,v0.z);
379
getContext()->getVisualDebugger()->addBBLine(v1.x,v1.y,v0.z, v0.x,v1.y,v0.z);
380
getContext()->getVisualDebugger()->addBBLine(v0.x,v1.y,v0.z, v0.x,v0.y,v0.z);
381
getContext()->getVisualDebugger()->addBBLine(v0.x,v0.y,v1.z, v1.x,v0.y,v1.z);
382
getContext()->getVisualDebugger()->addBBLine(v1.x,v0.y,v1.z, v1.x,v1.y,v1.z);
383
getContext()->getVisualDebugger()->addBBLine(v1.x,v1.y,v1.z, v0.x,v1.y,v1.z);
384
getContext()->getVisualDebugger()->addBBLine(v0.x,v1.y,v1.z, v0.x,v0.y,v1.z);
385
getContext()->getVisualDebugger()->addBBLine(v0.x,v0.y,v0.z, v0.x,v0.y,v1.z);
386
getContext()->getVisualDebugger()->addBBLine(v1.x,v0.y,v0.z, v1.x,v0.y,v1.z);
387
getContext()->getVisualDebugger()->addBBLine(v1.x,v1.y,v0.z, v1.x,v1.y,v1.z);
388
getContext()->getVisualDebugger()->addBBLine(v0.x,v1.y,v0.z, v0.x,v1.y,v1.z);
391
void CollisionObject::nodeUpdated(const Node* node)
393
mNeedsUpdating = true;
396
void CollisionObject::do_broadphase()
400
mProxy->setBBox(minv, maxv);
404
mProxy = mContext->getBroadPhase()->createProxy(this, minv, maxv);
408
void CollisionObject::remove_broadphase()
412
mContext->getBroadPhase()->deleteProxy(mProxy);
418
//------------------------------------------------------------------------