Added plane vs sphere penetration test.

remotes/origingl/master
Martin Felis 2020-10-05 21:47:25 +02:00
parent 7e7b08b919
commit c02255d64c
4 changed files with 90 additions and 5 deletions

View File

@ -15,10 +15,13 @@ struct SimShape;
struct SimBody; struct SimBody;
struct CollisionInfo; struct CollisionInfo;
const double cCollisionEps = 1.0e-4;
struct SimShape { struct SimShape {
enum ShapeType { enum ShapeType {
Box = 0, Box = 0,
Sphere = 1, Sphere = 1,
Plane = 2
}; };
ShapeType mType; ShapeType mType;
Vector3d pos; Vector3d pos;
@ -68,6 +71,11 @@ bool CheckPenetration(
const SimShape& shape_b, const SimShape& shape_b,
CollisionInfo& cinfo); CollisionInfo& cinfo);
bool CheckPenetrationSphereVsPlane(
const SimShape& shape_a,
const SimShape& shape_b,
CollisionInfo& cinfo);
SimBody CreateSphereBody( SimBody CreateSphereBody(
double mass, double mass,
double radius, double radius,

View File

@ -12,10 +12,10 @@ void simplesim() {
world.mBodies.push_back(sphere_body); world.mBodies.push_back(sphere_body);
SimShape ground_shape; SimShape ground_shape;
ground_shape.mType = SimShape::Box; ground_shape.mType = SimShape::Plane;
ground_shape.pos.set(0., -5.0, 0.); ground_shape.pos.set(0., 0., 0.);
ground_shape.orientation.set(0., 0., 0., 1.); ground_shape.orientation.set(0., 0., 0., 1.);
ground_shape.scale.set(25.0, 10.0, 25.0); ground_shape.scale.set(1.0, 1.0, 1.0);
world.mStaticShapes.push_back(ground_shape); world.mStaticShapes.push_back(ground_shape);
@ -28,7 +28,7 @@ void simplesim() {
world.detectCollisions(); world.detectCollisions();
world.resolveCollisions(dt); world.resolveCollisions(dt);
world.integrateWorld(dt); world.integrateWorld(dt);
} while (world.mSimTime < 1.01); } while (world.mSimTime < 10.01);
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {

View File

@ -82,6 +82,9 @@ void SimShapeSupport(
} else { } else {
ccdVec3Set(v, CCD_ZERO, CCD_ZERO, CCD_ZERO); ccdVec3Set(v, CCD_ZERO, CCD_ZERO, CCD_ZERO);
} }
} else {
cerr << "Unknown shape type: " << shape->mType << endl;
abort();
} }
// transform support point according to position and rotation of object // transform support point according to position and rotation of object
@ -93,6 +96,15 @@ bool CheckPenetration(
const SimShape& shape_a, const SimShape& shape_a,
const SimShape& shape_b, const SimShape& shape_b,
CollisionInfo& cinfo) { CollisionInfo& cinfo) {
if (shape_a.mType == SimShape::Sphere && shape_b.mType == SimShape::Plane) {
return CheckPenetrationSphereVsPlane(shape_a, shape_b, cinfo);
}
if (shape_b.mType == SimShape::Sphere && shape_a.mType == SimShape::Plane) {
bool result = CheckPenetrationSphereVsPlane(shape_b, shape_a, cinfo);
cinfo.dir *= -1.;
return result;
}
ccd_t ccd; ccd_t ccd;
CCD_INIT(&ccd); CCD_INIT(&ccd);
ccd.support1 = SimShapeSupport; ccd.support1 = SimShapeSupport;
@ -114,6 +126,31 @@ bool CheckPenetration(
return !intersect; return !intersect;
} }
bool CheckPenetrationSphereVsPlane(
const SimShape& shape_a,
const SimShape& shape_b,
CollisionInfo& cinfo) {
assert(shape_a.mType == SimShape::Sphere);
assert(shape_b.mType == SimShape::Plane);
// For now only support aligned spheres
assert((shape_a.orientation - Quaternion(0., 0., 0., 1.)).squaredNorm() < cCollisionEps);
Vector3d plane_normal = shape_b.orientation.toMatrix().block(0,1,3,1);
Vector3d plane_point = shape_b.pos;
Vector3d sphere_point_to_plane = shape_a.pos - plane_normal * shape_a.scale[0];
double sphere_center_height = plane_normal.transpose() * (sphere_point_to_plane - plane_point);
if (sphere_center_height < cCollisionEps) {
cinfo.pos = sphere_point_to_plane;
cinfo.dir = plane_normal;
cinfo.depth = sphere_center_height;
return 1;
}
return 0;
}
void SimBody::updateCollisionShapes() { void SimBody::updateCollisionShapes() {
UpdateKinematicsCustom(mModel, &q, nullptr, nullptr); UpdateKinematicsCustom(mModel, &q, nullptr, nullptr);
@ -241,7 +278,7 @@ void SimBody::resolveCollisions(
// Solve for the impules hlambda // Solve for the impules hlambda
A = G * Minv * G.transpose(); A = G * Minv * G.transpose();
b = (constr_value + VectorNd::Constant(nconstraints, 0.0001) ) * 1. / dt + G * (qdot + Minv * dt * (tau - N)) * -1.0; b = (constr_value ) * 1. / dt + G * (qdot + Minv * dt * (tau - N));
VectorNd hlambda (VectorNd::Zero(nconstraints)); VectorNd hlambda (VectorNd::Zero(nconstraints));
VectorNd hlambda_lo (VectorNd::Constant(nconstraints, 0.)); VectorNd hlambda_lo (VectorNd::Constant(nconstraints, 0.));
@ -438,4 +475,6 @@ SimBody CreateBoxBody(
return result; return result;
} }
} // namespace RBDLSim } // namespace RBDLSim

View File

@ -44,3 +44,41 @@ TEST_CASE("Simple Box vs Sphere Collision", "[Collision]") {
REQUIRE(cresult == false); REQUIRE(cresult == false);
} }
} }
TEST_CASE ("CheckCollisionSphereVsPlane", "[Collision]") {
SimShape plane;
plane.mType = SimShape::Plane;
plane.pos = Vector3d (0., 0., 0.);
plane.orientation = Quaternion (0., 1., 0., 1.);
plane.scale = Vector3d (1., 1., 1.);
SimShape sphere;
sphere.mType = SimShape::Sphere;
sphere.scale = Vector3d (1.5, 1.5, 1.5);
sphere.orientation = Quaternion(0., 0., 0., 1.);
CollisionInfo cinfo;
bool cresult = false;
SECTION ("Sphere above plane") {
sphere.pos = Vector3d (0., 2.0, 0.);
cresult = CheckPenetrationSphereVsPlane(sphere, plane, cinfo);
REQUIRE(cresult == false);
}
SECTION ("Sphere touching") {
sphere.pos = Vector3d (0., 1.5, 0.);
cresult = CheckPenetrationSphereVsPlane(sphere, plane, cinfo);
REQUIRE(cresult == false);
}
SECTION ("Sphere penetration") {
sphere.pos = Vector3d (0., -1., 0.);
cresult = CheckPenetrationSphereVsPlane(sphere, plane, cinfo);
REQUIRE(cresult == false);
}
}