mirror of
https://github.com/tribes2/engine.git
synced 2026-01-20 19:54:46 +00:00
263 lines
6.3 KiB
C++
263 lines
6.3 KiB
C++
//-----------------------------------------------------------------------------
|
|
// V12 Engine
|
|
//
|
|
// Copyright (c) 2001 GarageGames.Com
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "game/rigid.h"
|
|
#include "console/console.h"
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
Rigid::Rigid()
|
|
{
|
|
state.force = state.torque =
|
|
state.linVelocity =
|
|
state.linPosition =
|
|
state.linMomentum =
|
|
state.angVelocity =
|
|
state.angMomentum = Point3F(0,0,0);
|
|
state.angPosition.identity();
|
|
state.invWorldInertia.identity();
|
|
|
|
mass = oneOverMass = 1.0;
|
|
invObjectInertia.identity();
|
|
restitution = 0.3;
|
|
friction = 0.5;
|
|
angDamping = 0;
|
|
linDamping = 0;
|
|
atRest = false;
|
|
microCount = 0;
|
|
}
|
|
|
|
void Rigid::clearForces()
|
|
{
|
|
state.force.set(0,0,0);
|
|
state.torque.set(0,0,0);
|
|
}
|
|
|
|
void Rigid::integrate(State& t,F32 delta)
|
|
{
|
|
lastDelta = delta;
|
|
|
|
t.linPosition += t.linVelocity * delta;
|
|
t.linMomentum += t.force * delta;
|
|
t.linVelocity = t.linMomentum * oneOverMass;
|
|
|
|
// // Linear momentum and velocity
|
|
// t.linPosition = state.linPosition + (state.linVelocity * delta);
|
|
// t.linMomentum = state.linMomentum + (state.force * delta);
|
|
// t.linVelocity = t.linMomentum * oneOverMass;
|
|
|
|
// Angular position is average velocity * delta
|
|
F32 sinHalfAngle;
|
|
F32 angle = state.angVelocity.len();
|
|
if (angle != 0.0f) {
|
|
QuatF dq;
|
|
mSinCos(angle * delta * -0.5,
|
|
sinHalfAngle,
|
|
dq.w);
|
|
sinHalfAngle *= 1 / angle;
|
|
dq.x = t.angVelocity.x * sinHalfAngle;
|
|
dq.y = t.angVelocity.y * sinHalfAngle;
|
|
dq.z = t.angVelocity.z * sinHalfAngle;
|
|
QuatF temp = t.angPosition;
|
|
t.angPosition.mul(temp, dq);
|
|
t.angPosition.normalize();
|
|
}
|
|
else
|
|
{
|
|
//t.angPosition = state.angPosition;
|
|
}
|
|
|
|
t.angMomentum += t.torque * delta;
|
|
|
|
// Move angular momentum into world space
|
|
MatrixF iv,qmat;
|
|
t.angPosition.setMatrix(&qmat);
|
|
iv.mul(qmat,invObjectInertia);
|
|
qmat.transpose();
|
|
t.invWorldInertia.mul(iv,qmat);
|
|
t.invWorldInertia.mulV(t.angMomentum, &t.angVelocity);
|
|
}
|
|
|
|
void Rigid::updateVelocity(State& t)
|
|
{
|
|
t.linVelocity.x = t.linMomentum.x * oneOverMass;
|
|
t.linVelocity.y = t.linMomentum.y * oneOverMass;
|
|
t.linVelocity.z = t.linMomentum.z * oneOverMass;
|
|
t.invWorldInertia.mulV(t.angMomentum,&t.angVelocity);
|
|
}
|
|
|
|
void Rigid::applyImpulse(State& t, const Point3F &r, const Point3F &impulse)
|
|
{
|
|
atRest = false;
|
|
|
|
// Linear momentum and velocity
|
|
t.linMomentum += impulse;
|
|
t.linVelocity.x = t.linMomentum.x * oneOverMass;
|
|
t.linVelocity.y = t.linMomentum.y * oneOverMass;
|
|
t.linVelocity.z = t.linMomentum.z * oneOverMass;
|
|
|
|
// Rotational momentum and velocity
|
|
Point3F tv;
|
|
mCross(r,impulse,&tv);
|
|
t.angMomentum += tv;
|
|
t.invWorldInertia.mulV(t.angMomentum, &t.angVelocity);
|
|
}
|
|
|
|
// bool Rigid::resolveCollision(State& s, const Point3F& p, Point3F normal, Rigid* rigid)
|
|
// {
|
|
// atRest = false;
|
|
// Point3F v1,v2,r1,r2;
|
|
// r1 = p - s.linPosition;
|
|
// s.getVelocity(r1,&v1);
|
|
// r2 = p - rigid->state.linPosition;
|
|
// rigid->getVelocity(r2,&v2);
|
|
|
|
// // Make sure they are converging
|
|
// F32 nv = mDot(v1,normal);
|
|
// nv -= mDot(v2,normal);
|
|
// if (nv > 0)
|
|
// return false;
|
|
|
|
// // Compute impulse
|
|
// F32 d, n = -nv * (1 + restitution) * rigid->restitution;
|
|
// Point3F a1,b1,c1;
|
|
// mCross(r1,normal,&a1);
|
|
// s.invWorldInertia.mulV(a1,&b1);
|
|
// mCross(b1,r1,&c1);
|
|
|
|
// Point3F a2,b2,c2;
|
|
// mCross(r2,normal,&a2);
|
|
// rigid->state.invWorldInertia.mulV(a2,&b2);
|
|
// mCross(b2,r2,&c2);
|
|
|
|
// Point3F c3 = c1 + c2;
|
|
// d = oneOverMass + rigid->oneOverMass + mDot(c3,normal);
|
|
// Point3F impulse = normal * (n / d);
|
|
|
|
// applyImpulse(s, r1,impulse);
|
|
// impulse.neg();
|
|
// rigid->applyImpulse(r2,impulse);
|
|
// return true;
|
|
// }
|
|
|
|
bool Rigid::resolveCollision(State& s, const Point3F& p, Point3F normal)
|
|
{
|
|
atRest = false;
|
|
Point3F v1,r1 = p - s.linPosition;
|
|
s.getVelocity(r1,&v1);
|
|
F32 n = -mDot(v1,normal);
|
|
if (n >= 0) {
|
|
|
|
// Collision impulse
|
|
F32 d = getZeroImpulse(s,r1,normal);
|
|
F32 j = n * (1 + restitution) * d;
|
|
Point3F impulse = normal * j;
|
|
|
|
// Friction impulse
|
|
Point3F uv = v1 + (normal * n);
|
|
F32 ul = uv.len();
|
|
if (ul) {
|
|
uv /= -ul;
|
|
F32 u = n * d * friction * getZeroImpulse(s,r1,uv);
|
|
impulse += uv * u;
|
|
}
|
|
|
|
//
|
|
applyImpulse(s, r1,impulse);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
F32 Rigid::getZeroImpulse(State& s,const Point3F& r,const Point3F& normal)
|
|
{
|
|
Point3F a,b,c;
|
|
mCross(r,normal,&a);
|
|
s.invWorldInertia.mulV(a,&b);
|
|
mCross(b,r,&c);
|
|
return 1 / (oneOverMass + mDot(c,normal));
|
|
}
|
|
|
|
void Rigid::getVelocity(const Point3F &r, Point3F *v)
|
|
{
|
|
state.getVelocity(r, v);
|
|
}
|
|
|
|
F32 Rigid::getKineticEnergy(const MatrixF& wto)
|
|
{
|
|
Point3F w;
|
|
wto.mulV(state.angVelocity,&w);
|
|
const F32* f = invObjectInertia;
|
|
return 0.5 * ((mass * mDot(state.linVelocity,state.linVelocity)) +
|
|
w.x * w.x / f[0] +
|
|
w.y * w.y / f[5] +
|
|
w.z * w.z / f[10]);
|
|
}
|
|
|
|
void Rigid::State::getVelocity(const Point3F& r, Point3F* v)
|
|
{
|
|
mCross(angVelocity, r, v);
|
|
*v += linVelocity;
|
|
}
|
|
|
|
void Rigid::State::getTransform(MatrixF* mat)
|
|
{
|
|
angPosition.setMatrix(mat);
|
|
mat->setColumn(3,linPosition);
|
|
}
|
|
|
|
void Rigid::State::setTransform(const MatrixF& mat)
|
|
{
|
|
angPosition.set(mat);
|
|
mat.getColumn(3,&linPosition);
|
|
}
|
|
|
|
|
|
void Rigid::setObjectInertia(const Point3F& r)
|
|
{
|
|
// Rotational moment of inertia of a box
|
|
F32 ot = mass/12;
|
|
F32 a = r.x * r.x;
|
|
F32 b = r.y * r.y;
|
|
F32 c = r.z * r.z;
|
|
|
|
F32* f = invObjectInertia;
|
|
invObjectInertia.identity();
|
|
// f[0] = 1 / (ot * (b + c));
|
|
// f[5] = 1 / (ot * (c + a));
|
|
// f[10] = 1 / (ot * (a + b));
|
|
|
|
MatrixF iv,qmat;
|
|
state.angPosition.setMatrix(&qmat);
|
|
iv.mul(qmat,invObjectInertia);
|
|
qmat.transpose();
|
|
state.invWorldInertia.mul(iv,qmat);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
bool Rigid::checkRestCondition()
|
|
{
|
|
if (state.linMomentum.len() < 0.1f &&
|
|
state.angMomentum.len() < 0.05f) {
|
|
setAtRest();
|
|
}
|
|
return atRest;
|
|
}
|
|
|
|
void Rigid::setAtRest()
|
|
{
|
|
atRest = true;
|
|
state.linVelocity =
|
|
state.linMomentum =
|
|
state.angVelocity =
|
|
state.angMomentum =
|
|
Point3F(0,0,0);
|
|
}
|