There is another method, replicated below, which can be used to arrive at the same manifold information + the separation at each contact point, in world space.
b2WorldManifold Class
As noted earlier, the basic manifold object is the b2Manifold class. Box2D comes with the following class to get the contact points information in world space.
//const b2_maxManifoldPoints = 2;
/// This is used to compute the current state of a contact manifold.
class b2WorldManifold {
constructor() {
this.normal = new Vec2(); /// < world vector pointing from A to B
this.points = new Array(b2_maxManifoldPoints); /// < world contact point (point of intersection)
this.separations = new Array(b2_maxManifoldPoints); ///float< a negative value indicates overlap, in meters
}
};
It is useful to look at the initialize method of this class, which transforms the b2Manifold contact point information into world space.
Remember that b2Manifold has a type, which can be:
e_circles - contact between circles
e_faceA - reference shape is shapeA
e_faceB - reference shape is shapeB
/// Evaluate the manifold with supplied transforms. This assumes
/// modest motion from the original state. This does not change the
/// point count, impulses, etc. The radii must come from the shapes
/// that generated the manifold.
initialize(manifold, xfA, radiusA, xfB, radiusB) {
if (manifold.pointCount == 0) {
return;
}
this.pointCount = manifold.pointCount;
switch (manifold.type) {
case b2Manifold.e_circles:
{
this.normal.set(1.0, 0.0);
let pointA = b2Mul(xfA, manifold.localPoint); //b2b2Vec2
let pointB = b2Mul(xfB, manifold.points[0].localPoint); //b2b2Vec2
if (b2Vec2.DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon) {
this.normal = b2Vec2.Subtract(pointB, pointA);
this.normal.normalize();
}
let cA = b2Vec2.Add(pointA, b2Vec2.Scale(radiusA, this.normal)); //b2b2Vec2
let cB = b2Vec2.Subtract(pointB, b2Vec2.Scale(radiusB, this.normal)); //b2b2Vec2
this.points[0] = b2Vec2.Scale(b2Vec2.Add(cA, cB),0.5);
this.separations[0] = b2Vec2.b2Dot(b2Vec2.Subtract(cB, cA), this.normal);
break;
}
case b2Manifold.e_faceA:
{
this.normal = Rot.MulQV(xfA.q, manifold.localNormal);
let planePoint = b2Mul(xfA, manifold.localPoint); //b2b2Vec2
for (let i = 0; i < manifold.pointCount; i++)
{
let clipPoint = b2Mul(xfB, manifold.points[i].localPoint); //b2b2Vec2
let cA = b2Vec2.Add(clipPoint, b2Vec2.Scale((radiusA - b2Vec2.b2Dot(b2Vec2.Subtract(clipPoint, planePoint), this.normal)), this.normal)); //b2b2Vec2
let cB = b2Vec2.Subtract(clipPoint, b2Vec2.Scale(radiusB, this.normal)); //b2b2Vec2
this.points[i] = b2Vec2.Scale(b2Vec2.Add(cA, cB),0.5);
this.separations[i] = b2Vec2.b2Dot(b2Vec2.Subtract(cB, cA), this.normal);
}
break;
}
case b2Manifold.e_faceB:
{
this.normal = Rot.MulQV(xfB.q, manifold.localNormal);
let planePoint = b2Mul(xfB, manifold.localPoint);
for (let i = 0; i < manifold.pointCount; i++) {
let clipPoint = b2Mul(xfA, manifold.points[i].localPoint);
//b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;
let cB = b2Vec2.Add(clipPoint, b2Vec2.Scale((radiusB - b2Vec2.b2Dot(b2Vec2.Subtract(clipPoint, planePoint), this.normal)), this.normal)); //b2b2Vec2
//b2Vec2 cA = clipPoint - radiusA * normal;
let cA = b2Vec2.Subtract(clipPoint, b2Vec2.Scale(radiusA, this.normal));
//points[i] = 0.5f * (cA + cB);
this.points[i] = b2Vec2.Scale(b2Vec2.Add(cA, cB),0.5);
//separations[i] = b2Dot(cA - cB, normal);
this.separations[i] = b2Vec2.b2Dot(b2Vec2.Subtract(cA, cB), this.normal);
}
// Ensure normal points from A to B.
this.normal.negate();
break;
}
}
};
Let us look deeper into what the code is doing, in case type = e_faceB. Remember ths in the case of collision between polyA and polyB,
the reference body is polyB, incident body is polyA
normal is the collision normal in local space of the reference body, ie polyB
planepoint = manifold.local point is the mid-point of the reference edge
points[i].localPoint is the clipped point of incident edge (ie edge of polyA) in local space of polyA
clipPoint is the clipped point on incident edge, transformed into world space
cA and cB are points (in world space) on either side of the clipPoint, along the collision normal on the reference edge and the incident edge, but adjusted for the 'skin'
cA is the clipped point (which is basically the contact point sitting on the incident edge), but shifted along the collision normal, by the skin width - ie cA is the contact point on the incident edge adjusted for the skin width
cB is the clipped point shifted along the collision normal so it sits on the reference edge adjusted for the skin width
Finally,
Contact point (in world space) is the midpoint of cA and cB.
Separation is the distance between cA and CB
Komentar