50
52
#include "MT_MinMax.h"
54
static const MT_Scalar ImpulseThreshold = -10.;
55
static const MT_Scalar FixThreshold = 0.01;
56
static const MT_Scalar FixVelocity = 0.01;
54
MT_Scalar SM_Object::ImpulseThreshold = -1.0;
63
// Sort objects by height
64
bool operator()(const Contact *a, const Contact *b)
66
return a->pos[2] < b->pos[2];
69
Contact(SM_Object *o1, SM_Object *o2, const MT_Vector3 nor, const MT_Point3 p)
83
if (obj1->m_static || obj2->m_static)
85
if (obj1->isDynamic())
87
if (obj1->m_static && obj2->m_static)
89
if (obj1->m_static < obj2->m_static)
91
obj2->m_error -= normal;
92
obj2->m_static = obj1->m_static + 1;
96
obj1->m_error += normal;
97
obj1->m_static = obj2->m_static + 1;
104
obj2->m_error -= normal;
105
obj2->m_static = obj1->m_static + 1;
109
obj1->m_error += normal;
110
obj1->m_static = obj2->m_static + 1;
116
obj2->m_error -= normal;
122
// This distinction between dynamic and non-dynamic objects should not be
123
// necessary. Non-dynamic objects are assumed to have infinite mass.
124
if (obj1->isDynamic()) {
125
MT_Vector3 error = normal * 0.5f;
126
obj1->m_error += error;
127
obj2->m_error -= error;
130
// Same again but now obj1 is non-dynamic
131
obj2->m_error -= normal;
132
obj2->m_static = obj1->m_static + 1;
139
typedef std::set<Contact*, Contact> Set;
142
static Contact::Set contacts;
57
144
SM_Object::SM_Object(
58
145
DT_ShapeHandle shape,
59
146
const SM_MaterialProps *materialProps,
63
150
m_dynamicParent(dynamicParent),
64
151
m_client_object(0),
152
m_physicsClientObject(0),
67
154
m_materialProps(materialProps),
68
155
m_materialPropsBackup(0),
69
156
m_shapeProps(shapeProps),
70
157
m_shapePropsBackup(0),
71
m_object(DT_CreateObject(this, shape)),
73
159
m_scaling(1.0, 1.0, 1.0),
74
160
m_reaction_impulse(0.0, 0.0, 0.0),
75
161
m_reaction_force(0.0, 0.0, 0.0),
77
m_prev_kinematic(false),
78
m_is_rigid_body(false),
79
162
m_lin_mom(0.0, 0.0, 0.0),
80
163
m_ang_mom(0.0, 0.0, 0.0),
81
164
m_force(0.0, 0.0, 0.0),
85
168
m_combined_ang_vel (0.0, 0.0, 0.0),
88
m_inv_inertia(0., 0., 0.)
171
m_inv_inertia(0., 0., 0.),
173
m_prev_kinematic(false),
174
m_is_rigid_body(false),
177
m_object = DT_CreateObject(this, shape);
90
178
m_xform.setIdentity();
91
179
m_xform.getValue(m_ogl_matrix);
121
210
m_lin_mom *= pow(m_shapeProps->m_lin_drag, timeStep);
122
211
m_ang_mom *= pow(m_shapeProps->m_ang_drag, timeStep);
123
212
// Set velocities according momentum
124
m_lin_vel = m_lin_mom * m_inv_mass;
125
m_ang_vel = m_inv_inertia_tensor * m_ang_mom;
213
getNextFrame().setLinearVelocity(m_lin_mom * m_inv_mass);
214
getNextFrame().setAngularVelocity(m_inv_inertia_tensor * m_ang_mom);
148
237
//#define BACKWARD
151
m_pos += (m_prev_state.getLinearVelocity() + actualLinVelocity()) * (timeStep * 0.5);
152
m_orn += (m_prev_state.getAngularVelocity() * m_prev_state.getOrientation() + actualAngVelocity() * m_orn) * (timeStep * 0.25);
240
getNextFrame().integrateMidpoint(timeStep, m_prev_state, actualLinVelocity(), actualAngVelocity());
153
241
#elif defined BACKWARD
154
242
// Backward Euler
155
m_pos += actualLinVelocity() * timeStep;
156
m_orn += actualAngVelocity() * m_orn * (timeStep * 0.5);
243
getNextFrame().integrateBackward(timeStep, actualLinVelocity(), actualAngVelocity());
160
m_pos += m_prev_state.getLinearVelocity() * timeStep;
161
m_orn += m_prev_state.getAngularVelocity() * m_orn * (timeStep * 0.5);
246
getNextFrame().integrateForward(timeStep, m_prev_state);
163
m_orn.normalize(); // I might not be necessary to do this every call
197
281
* if rel_vel_normal > 0, the objects are moving apart!
199
if (rel_vel_normal < 0.) {
283
if (rel_vel_normal < -MT_EPSILON) {
201
285
* if rel_vel_normal < ImpulseThreshold, scale the restitution down.
202
286
* This should improve the simulation where the object is stacked.
204
288
restitution *= MT_min(MT_Scalar(1.0), rel_vel_normal/ImpulseThreshold);
206
290
MT_Scalar impulse = -(1.0 + restitution) * rel_vel_normal;
325
409
(invMass + lateral.dot(temp.cross(local2)));
327
411
MT_Scalar friction = MT_min(impulse_lateral, max_friction);
328
applyImpulse(local2 + m_pos, -lateral * friction);
412
applyImpulse(local2 + getNextFrame().getPosition(), -lateral * friction);
331
415
MT_Scalar impulse_lateral = rel_vel_lateral / invMass;
430
static void AddCallback(SM_Scene *scene, SM_Object *obj1, SM_Object *obj2)
432
// If we have callbacks on either of the client objects, do a collision test
433
// and add a callback if they intersect.
435
if ((obj1->getClientObject() && obj1->getClientObject()->hasCollisionCallback()) ||
436
(obj2->getClientObject() && obj2->getClientObject()->hasCollisionCallback()) &&
437
DT_GetIntersect(obj1->getObjectHandle(), obj2->getObjectHandle(), v))
438
scene->notifyCollision(obj1, obj2);
346
441
DT_Bool SM_Object::boing(
347
442
void *client_data,
350
445
const DT_CollData *coll_data
353
// return DT_CONTINUE;
355
447
SM_Scene *scene = (SM_Scene *)client_data;
356
448
SM_Object *obj1 = (SM_Object *)object1;
357
449
SM_Object *obj2 = (SM_Object *)object2;
359
scene->addPair(obj1, obj2); // Record this collision for client callbacks
451
// at this point it is unknown whether we are really intersecting (broad phase)
454
if (!obj2->isDynamic()) {
455
std::swap(obj1, obj2);
361
458
// If one of the objects is a ghost then ignore it for the dynamics
362
459
if (obj1->isGhost() || obj2->isGhost()) {
460
AddCallback(scene, obj1, obj2);
363
461
return DT_CONTINUE;
366
464
// Objects do not collide with parent objects
367
465
if (obj1->getDynamicParent() == obj2 || obj2->getDynamicParent() == obj1) {
466
AddCallback(scene, obj1, obj2);
368
467
return DT_CONTINUE;
371
470
if (!obj2->isDynamic()) {
372
std::swap(obj1, obj2);
375
if (!obj2->isDynamic()) {
471
AddCallback(scene, obj1, obj2);
376
472
return DT_CONTINUE;
379
475
// Get collision data from SOLID
381
476
if (!DT_GetPenDepth(obj1->getObjectHandle(), obj2->getObjectHandle(), p1, p2))
382
477
return DT_CONTINUE;
383
479
MT_Point3 local1(p1), local2(p2);
384
480
MT_Vector3 normal(local2 - local1);
385
481
MT_Scalar dist = normal.length();
387
483
if (dist < MT_EPSILON)
388
484
return DT_CONTINUE;
486
// Now we are definitely intersecting.
488
// Set callbacks for game engine.
489
if ((obj1->getClientObject() && obj1->getClientObject()->hasCollisionCallback()) ||
490
(obj2->getClientObject() && obj2->getClientObject()->hasCollisionCallback()))
491
scene->notifyCollision(obj1, obj2);
390
local1 -= obj1->m_pos;
391
local2 -= obj2->m_pos;
493
local1 -= obj1->getNextFrame().getPosition();
494
local2 -= obj2->getNextFrame().getPosition();
393
496
// Calculate collision parameters
394
497
MT_Vector3 rel_vel = obj1->getVelocity(local1) - obj2->getVelocity(local2);
410
513
obj1->dynamicCollision(local1, normal, dist, rel_vel, restitution, friction_factor, invMass);
412
515
if (obj2->isDynamic())
413
517
obj2->dynamicCollision(local2, -normal, dist, -rel_vel, restitution, friction_factor, invMass);
518
if (!obj1->isDynamic() || obj1->m_static)
519
obj2->m_static = obj1->m_static + 1;
415
522
return DT_CONTINUE;
450
556
// Get collision data from SOLID
451
557
MT_Vector3 normal(local2 - local1);
453
if (normal.dot(normal) < MT_EPSILON)
559
MT_Scalar dist = normal.dot(normal);
560
if (dist < MT_EPSILON || dist > obj2->m_shapeProps->m_radius*obj2->m_shapeProps->m_radius)
454
561
return DT_CONTINUE;
456
// This distinction between dynamic and non-dynamic objects should not be
457
// necessary. Non-dynamic objects are assumed to have infinite mass.
458
if (obj1->isDynamic()) {
459
MT_Vector3 error = normal * 0.5f;
460
obj1->m_error += error;
461
obj2->m_error -= error;
462
// Remove the velocity component in the normal direction
463
// Calculate collision parameters
464
/*MT_Vector3 rel_vel = obj1->getLinearVelocity() - obj2->getLinearVelocity();
465
if (normal.length() > FixThreshold && rel_vel.length() < FixVelocity) {
467
MT_Scalar rel_vel_normal = 0.49*(normal.dot(rel_vel));
469
obj1->addLinearVelocity(-rel_vel_normal*normal);
470
obj2->addLinearVelocity(rel_vel_normal*normal);
474
// Same again but now obj1 is non-dynamic
475
obj2->m_error -= normal;
476
/*MT_Vector3 rel_vel = obj2->getLinearVelocity();
477
if (normal.length() > FixThreshold && rel_vel.length() < FixVelocity) {
478
// Calculate collision parameters
480
MT_Scalar rel_vel_normal = -0.99*(normal.dot(rel_vel));
482
obj2->addLinearVelocity(rel_vel_normal*normal);
564
if ((obj1->m_static || !obj1->isDynamic()) && obj1->m_static < obj2->m_static)
566
obj2->m_static = obj1->m_static + 1;
567
} else if (obj2->m_static && obj2->m_static < obj1->m_static)
569
obj1->m_static = obj2->m_static + 1;
572
contacts.insert(new Contact(obj1, obj2, normal, MT_Point3(local1 + 0.5*(local2 - local1))));
486
575
return DT_CONTINUE;
489
578
void SM_Object::relax(void)
580
for (Contact::Set::iterator csit = contacts.begin() ; csit != contacts.end(); ++csit)
491
587
if (m_error.fuzzyZero())
493
589
//std::cout << "SM_Object::relax: { " << m_error << " }" << std::endl;
591
getNextFrame().setPosition(getNextFrame().getPosition() + m_error);
496
592
m_error.setValue(0., 0., 0.);
497
/* m_pos.getValue(pos);
498
DT_SetPosition(m_object, pos);
499
m_xform.setOrigin(m_pos);
500
m_xform.getValue(m_ogl_matrix); */
505
597
SM_Object::SM_Object() :
506
598
m_dynamicParent(0),
507
599
m_client_object(0),
600
m_physicsClientObject(0),
510
602
m_materialProps(0),
511
603
m_materialPropsBackup(0),
516
608
m_scaling(1.0, 1.0, 1.0),
517
609
m_reaction_impulse(0.0, 0.0, 0.0),
518
610
m_reaction_force(0.0, 0.0, 0.0),
520
m_prev_kinematic(false),
521
m_is_rigid_body(false),
522
611
m_lin_mom(0.0, 0.0, 0.0),
523
612
m_ang_mom(0.0, 0.0, 0.0),
524
613
m_force(0.0, 0.0, 0.0),
645
737
printf(" m_scaling = { %-0.5f, %-0.5f, %-0.5f }\n",
646
738
m_scaling[0], m_scaling[1], m_scaling[2]);
648
m_xform.setOrigin(m_pos);
649
m_xform.setBasis(MT_Matrix3x3(m_orn, m_scaling));
740
m_xform.setOrigin(getNextFrame().getPosition());
741
m_xform.setBasis(MT_Matrix3x3(getNextFrame().getOrientation(), m_scaling));
650
742
m_xform.getValue(m_ogl_matrix);
652
744
/* Blender has been known to crash here.
653
745
This usually means SM_Object *this has been deleted more than once. */
654
746
DT_SetMatrixd(m_object, m_ogl_matrix);
655
747
if (m_fh_object) {
656
m_fh_object->setPosition(m_pos);
748
m_fh_object->setPosition(getNextFrame().getPosition());
657
749
m_fh_object->calcXform();
659
751
updateInvInertiaTensor();
905
993
if (isDynamic()) {
908
m_lin_vel += lin_vel;
909
m_ang_vel += ang_vel;
996
getNextFrame().setLinearVelocity(getNextFrame().getLinearVelocity() + lin_vel);
997
getNextFrame().setAngularVelocity(getNextFrame().getAngularVelocity() + ang_vel);
912
1000
//compute the component of the physics velocity in the
913
1001
// direction of the set velocity and set it to zero.
914
1002
MT_Vector3 lin_vel_norm = lin_vel.normalized();
916
m_lin_vel -= (m_lin_vel.dot(lin_vel_norm) * lin_vel_norm);
1004
setLinearVelocity(getNextFrame().getLinearVelocity() - (getNextFrame().getLinearVelocity().dot(lin_vel_norm) * lin_vel_norm));
918
m_lin_mom = m_lin_vel * m_shapeProps->m_mass;
919
m_ang_mom = m_ang_vel * m_shapeProps->m_inertia;
1006
m_lin_mom = getNextFrame().getLinearVelocity() * m_shapeProps->m_mass;
1007
m_ang_mom = getNextFrame().getAngularVelocity() * m_shapeProps->m_inertia;
920
1008
clearCombinedVelocities();
1117
1205
actualAngVelocity(
1119
return m_combined_ang_vel + m_ang_vel;
1207
return m_combined_ang_vel + getNextFrame().getAngularVelocity();
1232
const SM_MotionState &
1234
getCurrentFrame() const
1239
const SM_MotionState &
1241
getPreviousFrame() const
1246
const SM_MotionState &
1248
getNextFrame() const
1258
return m_frames[1].getPosition();
1261
const MT_Quaternion&
1263
getOrientation() const
1265
return m_frames[1].getOrientation();
1270
getLinearVelocity() const
1272
return m_frames[1].getLinearVelocity();
1277
getAngularVelocity() const
1279
return m_frames[1].getAngularVelocity();
1284
interpolate(MT_Scalar timeStep)
1286
if (!actualLinVelocity().fuzzyZero() || !actualAngVelocity().fuzzyZero())
1288
getCurrentFrame().setTime(timeStep);
1289
getCurrentFrame().lerp(getPreviousFrame(), getNextFrame());
1298
getPreviousFrame() = getNextFrame();
1299
getCurrentFrame() = getNextFrame();