Added applying slight separation impulse in case of penetration, also started working on friction along tangents.

master
Martin Felis 2020-11-21 21:18:57 +01:00
parent ae9ec36325
commit 3fd715611d
3 changed files with 73 additions and 16 deletions

View File

@ -62,6 +62,18 @@ struct CollisionInfo {
MatrixNd MInvB = MatrixNd::Zero(1, 1); MatrixNd MInvB = MatrixNd::Zero(1, 1);
double GMInvGTA = 0.; double GMInvGTA = 0.;
double GMInvGTB = 0.; double GMInvGTB = 0.;
double tangentAccumImpulse0 = 0.;
double tangentAccumImpulse1 = 0.;
double tangentDeltaImpulse0 = 0.;
double tangentDeltaImpulse1 = 0.;
Vector3d tangent0 = Vector3d::Zero();
Vector3d tangent1 = Vector3d::Zero();
VectorNd tangentJacA = MatrixNd::Zero(2,2);
VectorNd tangentJacB = MatrixNd::Zero(2,2);
MatrixNd tangentMInvA = MatrixNd::Zero(2, 2);
MatrixNd tangentMInvB = MatrixNd::Zero(2, 2);
MatrixNd tangentGMInvGTA = MatrixNd::Zero(2,2);
MatrixNd tangentGMInvGTB = MatrixNd::Zero(2,2);
double effectiveRestitution = 1.0; double effectiveRestitution = 1.0;
double depth = 0.; double depth = 0.;

View File

@ -102,29 +102,48 @@ static void sSwapCollisionInfoShapeOrder(CollisionInfo& cinfo) {
cinfo.posB = temp_pos; cinfo.posB = temp_pos;
} }
static void sCalcTangentVectors(const Vector3d &normal, Vector3d* tangent0, Vector3d* tangent1) {
if (fabs(normal.dot(Vector3d(0., 0., 1.))) < 0.6) {
*tangent0 = normal.cross(Vector3d(0., 0., 1.));
*tangent1 = tangent0->cross(normal);
} else {
*tangent0 = normal.cross(Vector3d(1., 0., 0.));
*tangent1 = tangent0->cross(normal);
}
}
bool CheckPenetration( bool CheckPenetration(
const SimShape& shape_a, const SimShape& shape_a,
const SimShape& shape_b, const SimShape& shape_b,
CollisionInfo& cinfo) { CollisionInfo& cinfo) {
cinfo.mShapeA = &shape_a; cinfo.mShapeA = &shape_a;
cinfo.mShapeB = &shape_b; cinfo.mShapeB = &shape_b;
bool result = false;
if (shape_a.mType == SimShape::Sphere && shape_b.mType == SimShape::Plane) { if (shape_a.mType == SimShape::Sphere && shape_b.mType == SimShape::Plane) {
return CheckPenetrationSphereVsPlane(shape_a, shape_b, cinfo); result = CheckPenetrationSphereVsPlane(shape_a, shape_b, cinfo);
} sCalcTangentVectors(cinfo.dir, &cinfo.tangent0, &cinfo.tangent1);
if (shape_b.mType == SimShape::Sphere && shape_a.mType == SimShape::Plane) {
bool result = CheckPenetrationSphereVsPlane(shape_b, shape_a, cinfo);
sSwapCollisionInfoShapeOrder(cinfo);
return result; return result;
} } else if (
if (shape_a.mType == SimShape::Sphere && shape_b.mType == SimShape::Sphere) { shape_b.mType == SimShape::Sphere && shape_a.mType == SimShape::Plane) {
return CheckPenetrationSphereVsSphere(shape_a, shape_b, cinfo); result = CheckPenetrationSphereVsPlane(shape_b, shape_a, cinfo);
} sSwapCollisionInfoShapeOrder(cinfo);
if (shape_a.mType == SimShape::Box && shape_b.mType == SimShape::Plane) { sCalcTangentVectors(cinfo.dir, &cinfo.tangent0, &cinfo.tangent1);
return CheckPenetrationBoxVsPlane(shape_a, shape_b, cinfo); return result;
} } else if (
if (shape_a.mType == SimShape::Plane && shape_b.mType == SimShape::Box) { shape_a.mType == SimShape::Sphere && shape_b.mType == SimShape::Sphere) {
result = CheckPenetrationSphereVsSphere(shape_a, shape_b, cinfo);
sCalcTangentVectors(cinfo.dir, &cinfo.tangent0, &cinfo.tangent1);
return result;
} else if (
shape_a.mType == SimShape::Box && shape_b.mType == SimShape::Plane) {
result = CheckPenetrationBoxVsPlane(shape_a, shape_b, cinfo);
sCalcTangentVectors(cinfo.dir, &cinfo.tangent0, &cinfo.tangent1);
return result;
} else if (
shape_a.mType == SimShape::Plane && shape_b.mType == SimShape::Box) {
bool result = CheckPenetrationBoxVsPlane(shape_b, shape_a, cinfo); bool result = CheckPenetrationBoxVsPlane(shape_b, shape_a, cinfo);
sSwapCollisionInfoShapeOrder(cinfo); sSwapCollisionInfoShapeOrder(cinfo);
sCalcTangentVectors(cinfo.dir, &cinfo.tangent0, &cinfo.tangent1);
return result; return result;
} }
@ -487,13 +506,19 @@ void CalcCollisions(
} }
void CalcImpulseVariables( void CalcImpulseVariables(
double dt,
SimBody* body, SimBody* body,
unsigned int body_index, unsigned int body_index,
const Vector3d& pos, const Vector3d& pos,
const Vector3d& dir, const Vector3d& dir,
const double depth,
const Vector3d& tangent0,
const Vector3d& tangent1,
MatrixNd* MInv, MatrixNd* MInv,
VectorNd* jac, VectorNd* jac,
double* G_MInv_GT, double* G_MInv_GT,
MatrixNd* tangentJac,
MatrixNd* tangentGMInvGT,
double* bias_vel, double* bias_vel,
double restitution) { double restitution) {
if (body == nullptr || body->mIsStatic) { if (body == nullptr || body->mIsStatic) {
@ -527,32 +552,52 @@ void CalcImpulseVariables(
*G_MInv_GT = (*jac) * (*MInv) * (*jac).transpose(); *G_MInv_GT = (*jac) * (*MInv) * (*jac).transpose();
assert(!isnan(*G_MInv_GT)); assert(!isnan(*G_MInv_GT));
*bias_vel = (*jac) * qdot * restitution; double beta = 0.01;
double delta_slop = cCollisionEps;
*bias_vel = (*jac) * qdot * restitution - beta / dt * std::max (0., -depth - 0.05);
(*tangentJac).resize(2,ndof);
(*tangentJac).block(0,0,1,ndof) = tangent0.transpose() * G_constr;
(*tangentJac).block(1,0,1,ndof) = tangent0.transpose() * G_constr;
(*tangentGMInvGT) = (*tangentJac) * (*MInv) * (*tangentJac).transpose();
} }
void PrepareConstraintImpulse( void PrepareConstraintImpulse(
double dt,
SimBody* body_a, SimBody* body_a,
SimBody* body_b, SimBody* body_b,
CollisionInfo& cinfo) { CollisionInfo& cinfo) {
CalcImpulseVariables( CalcImpulseVariables(
dt,
body_a, body_a,
cinfo.mBodyAIndex, cinfo.mBodyAIndex,
cinfo.posA, cinfo.posA,
cinfo.dir, cinfo.dir,
cinfo.depth,
cinfo.tangent0,
cinfo.tangent1,
&cinfo.MInvA, &cinfo.MInvA,
&cinfo.jacA, &cinfo.jacA,
&cinfo.GMInvGTA, &cinfo.GMInvGTA,
&cinfo.tangentJacA,
&cinfo.tangentGMInvGTA,
&cinfo.biasVelocityA, &cinfo.biasVelocityA,
cinfo.effectiveRestitution); cinfo.effectiveRestitution);
CalcImpulseVariables( CalcImpulseVariables(
dt,
body_b, body_b,
cinfo.mBodyBIndex, cinfo.mBodyBIndex,
cinfo.posB, cinfo.posB,
cinfo.dir, cinfo.dir,
-cinfo.depth,
cinfo.tangent0,
cinfo.tangent1,
&cinfo.MInvB, &cinfo.MInvB,
&cinfo.jacB, &cinfo.jacB,
&cinfo.GMInvGTB, &cinfo.GMInvGTB,
&cinfo.tangentJacB,
&cinfo.tangentGMInvGTB,
&cinfo.biasVelocityB, &cinfo.biasVelocityB,
cinfo.effectiveRestitution); cinfo.effectiveRestitution);
} }
@ -678,7 +723,7 @@ void World::detectCollisions() {
void World::resolveCollisions(double dt) { void World::resolveCollisions(double dt) {
for (CollisionInfo& cinfo : mContactPoints) { for (CollisionInfo& cinfo : mContactPoints) {
PrepareConstraintImpulse(cinfo.mBodyA, cinfo.mBodyB, cinfo); PrepareConstraintImpulse(dt, cinfo.mBodyA, cinfo.mBodyB, cinfo);
} }
int num_iter = 20; int num_iter = 20;

View File

@ -102,7 +102,7 @@ void simulator_reset() {
for (int i = 0; i < sWorld.mBodies.size(); i++) { for (int i = 0; i < sWorld.mBodies.size(); i++) {
sWorld.mBodies[i].q.block(0, 0, 3, 1) = sWorld.mBodies[i].q.block(0, 0, 3, 1) =
Vector3d::Random() * 3. + Vector3d(0., 5., 0.); Vector3d::Random() * 0.3 + Vector3d(0., 5., 0.);
sWorld.mBodies[i].q[2] = 0.; sWorld.mBodies[i].q[2] = 0.;
} }