static	inline	void b3SetLinearAndAngular(const b3Vector3& n, const b3Vector3& r0, const b3Vector3& r1,
							 b3Vector3& linear, b3Vector3& angular0, b3Vector3& angular1)
{
	linear = -n;
	angular0 = -b3Cross(r0, n);
	angular1 = b3Cross(r1, n);
}
Esempio n. 2
0
void b3SphericalJoint::SolveVelocityConstraint(const b3SolverData* data) {
	u32 indexA = m_indexA;
	u32 indexB = m_indexB;

	r32 mA = m_mA;
	r32 mB = m_mB;
	b3Mat33 iA = m_iA;
	b3Mat33 iB = m_iB;
	b3Vec3 rA = m_rA;
	b3Vec3 rB = m_rB;
	b3Mat33 invMass = m_invMass;
	b3Vec3 velocityBias = m_velocityBias;	
	b3Vec3 lastImpulse = m_accImpulse;

	b3Vec3 vA = data->velocities[indexA].v;
	b3Vec3 wA = data->velocities[indexA].w;
	b3Vec3 vB = data->velocities[indexB].v;
	b3Vec3 wB = data->velocities[indexB].w;
	
	// Compute J * u.
	b3Vec3 dCdt = vB + b3Cross(wB, rB) - vA - b3Cross(wA, rA);

	// Compute the new, total, and delta impulses.
	b3Vec3 impulse = invMass * (-dCdt + velocityBias);
	b3Vec3 newImpulse = lastImpulse + impulse;
	// b3Vec3 deltaImpulse = newImpulse - lastImpulse <=> impulse;

	// Keep track of the accumulated impulse for the next iteration.
	lastImpulse = newImpulse;

	// Apply new impulse.
	vA -= mA * impulse;
	wA -= iA * b3Cross(rA, impulse);

	vB += mB * impulse;
	wB += iB * b3Cross(rB, impulse);

	// Copy the new old impulse for the next iteration.
	m_accImpulse = lastImpulse;
	
	// Update velocity vector.
	data->velocities[indexA].v = vA;
	data->velocities[indexA].w = wA;
	data->velocities[indexB].v = vB;
	data->velocities[indexB].w = wB;
}
Esempio n. 3
0
void b3SphericalJoint::WarmStart(const b3SolverData* data) {
	u32 indexA = m_indexA;
	u32 indexB = m_indexB;
	r32 mA = m_mA;
	r32 mB = m_mB;
	b3Mat33 iA = m_iA;
	b3Mat33 iB = m_iB;
	b3Vec3 rA = m_rA;
	b3Vec3 rB = m_rB;

	b3Vec3 impulse = m_accImpulse;

	data->velocities[indexA].v -= mA * impulse;
	data->velocities[indexA].w -= iA * b3Cross(rA, impulse);

	data->velocities[indexB].v += mB * impulse;
	data->velocities[indexB].w += iB * b3Cross(rB, impulse);
}
Esempio n. 4
0
// Box2D
static B3_FORCE_INLINE b3Vec3 b3SolveGyro(const b3Quat& q, const b3Mat33& Ib, const b3Vec3& w1, float32 h)
{
	// Convert angular velocity to body coordinates
	b3Vec3 w1b = b3MulT(q, w1);
	
	// Jacobian of f
	b3Mat33 J = Ib + h * (b3Skew(w1b) * Ib - b3Skew(Ib * w1b));
	
	// One iteration of Newton-Raphson
	// Residual vector
	b3Vec3 f;
	{
		f = h * b3Cross(w1b, Ib * w1b);
		w1b -= J.Solve(f);
	}
	
	// Convert angular velocity back to world coordinates
	b3Vec3 w2 = b3Mul(q, w1b);
	return w2;
}
Esempio n. 5
0
void b3BuildEdgeContact(b3Manifold& manifold,
	const b3Transform& xf1, u32 index1, const b3HullShape* s1,
	const b3Transform& xf2, u32 index2, const b3HullShape* s2)
{
	const b3Hull* hull1 = s1->m_hull;
	const b3HalfEdge* edge1 = hull1->GetEdge(index1);
	const b3HalfEdge* twin1 = hull1->GetEdge(index1 + 1);

	b3Vec3 C1 = xf1 * hull1->centroid;
	b3Vec3 P1 = xf1 * hull1->GetVertex(edge1->origin);
	b3Vec3 Q1 = xf1 * hull1->GetVertex(twin1->origin);
	b3Vec3 E1 = Q1 - P1;
	b3Vec3 N1 = E1;
	float32 L1 = N1.Normalize();
	B3_ASSERT(L1 > B3_LINEAR_SLOP);

	const b3Hull* hull2 = s2->m_hull;
	const b3HalfEdge* edge2 = hull2->GetEdge(index2);
	const b3HalfEdge* twin2 = hull2->GetEdge(index2 + 1);

	b3Vec3 C2 = xf2 * hull2->centroid;
	b3Vec3 P2 = xf2 * hull2->GetVertex(edge2->origin);
	b3Vec3 Q2 = xf2 * hull2->GetVertex(twin2->origin);
	b3Vec3 E2 = Q2 - P2;
	b3Vec3 N2 = E2;
	float32 L2 = N2.Normalize();
	B3_ASSERT(L2 > B3_LINEAR_SLOP);

	// Compute the closest points on the two lines.
	float32 b = b3Dot(N1, N2);
	float32 den = 1.0f - b * b;
	if (den <= 0.0f)
	{
		return;
	}

	float32 inv_den = 1.0f / den;

	b3Vec3 E3 = P1 - P2;

	float32 d = b3Dot(N1, E3);
	float32 e = b3Dot(N2, E3);

	float32 s = inv_den * (b * e - d);
	float32 t = inv_den * (e - b * d);

	b3Vec3 c1 = P1 + s * N1;
	b3Vec3 c2 = P2 + t * N2;

	// Ensure normal orientation to hull 2.
	b3Vec3 N = b3Cross(E1, E2);
	float32 LN = N.Normalize();
	B3_ASSERT(LN > 0.0f);
	if (b3Dot(N, P1 - C1) < 0.0f)
	{
		N = -N;
	}

	b3FeaturePair pair = b3MakePair(index1, index1 + 1, index2, index2 + 1);

	manifold.pointCount = 1;
	manifold.points[0].localNormal1 = b3MulT(xf1.rotation, N);
	manifold.points[0].localPoint1 = b3MulT(xf1, c1);
	manifold.points[0].localPoint2 = b3MulT(xf2, c2);
	manifold.points[0].key = b3MakeKey(pair);
}
Esempio n. 6
0
void b3ContactGraph::UpdateContacts() {
	// Update all contact constraints and its states.
	b3Contact* c = m_contactList;
	while (c) {
		const b3Shape* shapeA = c->m_shapeA;
		const b3Shape* shapeB = c->m_shapeB;

		b3Body* bodyA = c->m_shapeA->m_body;
		b3Body* bodyB = c->m_shapeB->m_body;

		if (bodyA == bodyB) {
			b3Contact* quack = c;
			c = c->m_next;
			DestroyContact(quack);
			continue;
		}

		bool activeA = bodyA->IsAwake() && (bodyA->m_type != e_staticBody);
		bool activeB = bodyB->IsAwake() && (bodyB->m_type != e_staticBody);
		if (!activeA && !activeB) {
			c = c->m_next;
			continue;
		}

		// Destroy the contact if is definately persistenting.
		if (!m_broadPhase.TestOverlap(shapeA->broadPhaseID, shapeB->broadPhaseID)) {
			b3Contact* quack = c;
			c = c->m_next;
			DestroyContact(quack);
			continue;
		}

		bool wasTouching = c->IsTouching();
		bool isTouching = false;
		bool isSensorContact = shapeA->IsSensor() || shapeB->IsSensor();

		if (isSensorContact) {
			// Simply, a sensor is active if its bounds is touching with another other shape's bounds.
			isTouching = m_broadPhase.TestOverlap(shapeA->broadPhaseID, shapeB->broadPhaseID);
			c->m_manifold.pointCount = 0;
		}
		else {
			// For the time being, Bounce can compute the closest distance between convex objects only.
			typedef void(*b3DistanceQuery) (b3Manifold&, const b3Transform&, const b3Shape*, const b3Transform&, const b3Shape*);

			// Simply, register the collision routines here.
			static b3DistanceQuery queryMatrix[e_maxShapes][e_maxShapes] = {
				{ &b3HullHullShapeContact },
			};

			b3ShapeType typeA = shapeA->GetType();
			b3ShapeType typeB = shapeB->GetType();

			b3Assert(typeA <= typeB);
			b3DistanceQuery Query = queryMatrix[typeA][typeB];
			b3Assert(Query);

			// Copy the old manifold so we can compare the new contact points with it.
			b3Manifold oldManifold = c->m_manifold;

			// Compute the a new contact manifold.
			c->m_manifold.pointCount = 0;
			Query(c->m_manifold, bodyA->m_transform * shapeA->m_local, shapeA, bodyB->m_transform * shapeB->m_local, shapeB);

			isTouching = c->m_manifold.pointCount > 0;

			// Look up the contact cache for identical contact points.
			b3Manifold* newManifold = &c->m_manifold;

			b3Vec3 normal = newManifold->normal;

			b3Vec3 xA = bodyA->m_worldCenter;
			b3Vec3 vA = bodyA->m_linearVelocity;
			b3Vec3 wA = bodyA->m_angularVelocity;

			b3Vec3 xB = bodyB->m_worldCenter;
			b3Vec3 vB = bodyB->m_linearVelocity;
			b3Vec3 wB = bodyB->m_angularVelocity;

			for (u32 i = 0; i < newManifold->pointCount; ++i) {
				b3ContactPoint* p2 = newManifold->points + i;

				b3Vec3 position = p2->position;
				b3Vec3 tangent1;
				b3Vec3 tangent2;

				p2->normalImpulse = B3_ZERO;
				p2->tangentImpulse[0] = B3_ZERO;
				p2->tangentImpulse[1] = B3_ZERO;
				p2->warmStarted = false;

				// Compute the (two) new tangent directions.
				b3Vec3 rA = position - xA;
				b3Vec3 rB = position - xB;

				b3Vec3 dv = vB + b3Cross(wB, rB) - vA - b3Cross(wA, rA);

				tangent1 = dv - b3Dot(dv, normal) * normal;
				r32 tangentMag = b3Dot(tangent1, tangent1);
				if (tangentMag > B3_EPSILON) {
					tangent1 *= B3_ONE / b3Sqrt(tangentMag);
					tangent2 = b3Cross(tangent1, normal);
				}
				else {
					b3ComputeBasis(normal, &tangent1, &tangent2);
				}

				p2->tangents[0] = tangent1;
				p2->tangents[1] = tangent2;

				// Initialize new contact point with the old contact point solution if they're identical.
				for (u32 j = 0; j < oldManifold.pointCount; ++j) {
					b3ContactPoint* p1 = oldManifold.points + j;
					if (p1->id.key == p2->id.key) {
						// Copy normal impulse.
						p2->warmStarted = true;
						p2->normalImpulse = p1->normalImpulse;
						// Project old friction solutions into the new tangential directions.
						b3Vec3 oldFrictionSolution = p1->tangentImpulse[0] * p1->tangents[0] + p1->tangentImpulse[1] * p1->tangents[1];
						p2->tangentImpulse[0] = b3Dot(oldFrictionSolution, p2->tangents[0]);
						p2->tangentImpulse[1] = b3Dot(oldFrictionSolution, p2->tangents[1]);
						break;
					}
				}
			}

			// If the contact has begun then awake the bodies.
			if (isTouching != wasTouching) {
				bodyA->SetAwake(true);
				bodyB->SetAwake(true);
			}
		}

		// Mark the contact as touching.
		if (isTouching) {
			c->m_flags |= b3Contact::e_touchingFlag;
		}
		else {
			c->m_flags &= ~b3Contact::e_touchingFlag;
		}

		// Notify the contact listener the contact state.
		if (m_contactListener) {
			if (!wasTouching && isTouching) {
				m_contactListener->BeginContact(c);
			}
			if (wasTouching && !isTouching) {
				m_contactListener->EndContact(c);
			}
			if (!isSensorContact && isTouching) {
				m_contactListener->Persisting(c);
			}
		}
		// Go to the next contact.
		c = c->m_next;
	}
}
Esempio n. 7
0
void b3Body::SetMassData(const b3MassData* massData)
{
	if (m_type != e_dynamicBody)
	{
		return;
	}

	m_invMass = 0.0f;
	m_I.SetZero();
	m_invI.SetZero();
	m_worldInvI.SetZero();

	m_mass = massData->mass;
	if (m_mass > 0.0f)
	{
		m_invMass = 1.0f / m_mass;
		m_I = massData->I - m_mass * b3Steiner(massData->center);
		
		B3_ASSERT(m_I.x.x > 0.0f);
		B3_ASSERT(m_I.y.y > 0.0f);
		B3_ASSERT(m_I.z.z > 0.0f);

		m_invI = b3Inverse(m_I);
		m_worldInvI = b3RotateToFrame(m_invI, m_xf.rotation);

		if (m_flags & e_fixedRotationX)
		{
			m_invI.y.y = 0.0f;
			m_invI.z.y = 0.0f;
			m_invI.y.z = 0.0f;
			m_invI.z.z = 0.0f;

			m_worldInvI.y.y = 0.0f;
			m_worldInvI.z.y = 0.0f;
			m_worldInvI.y.z = 0.0f;
			m_worldInvI.z.z = 0.0f;
		}

		if (m_flags & e_fixedRotationY)
		{
			m_invI.x.x = 0.0f;
			m_invI.x.z = 0.0f;
			m_invI.z.x = 0.0f;
			m_invI.z.z = 0.0f;

			m_worldInvI.x.x = 0.0f;
			m_worldInvI.x.z = 0.0f;
			m_worldInvI.z.x = 0.0f;
			m_worldInvI.z.z = 0.0f;
		}

		if (m_flags & e_fixedRotationZ)
		{
			m_invI.x.x = 0.0f;
			m_invI.x.y = 0.0f;
			m_invI.y.x = 0.0f;
			m_invI.y.y = 0.0f;

			m_worldInvI.x.x = 0.0f;
			m_worldInvI.x.y = 0.0f;
			m_worldInvI.y.x = 0.0f;
			m_worldInvI.y.y = 0.0f;
		}
	}
	else
	{
		m_mass = 1.0f;
		m_invMass = 1.0f;
	}

	// Move center of mass.
	b3Vec3 oldCenter = m_sweep.worldCenter;
	m_sweep.localCenter = massData->center;
	m_sweep.worldCenter = b3Mul(m_xf, m_sweep.localCenter);
	m_sweep.worldCenter0 = m_sweep.worldCenter;

	// Update center of mass velocity.
	m_linearVelocity += b3Cross(m_angularVelocity, m_sweep.worldCenter - oldCenter);
}
Esempio n. 8
0
void b3Body::ResetMass() 
{
	m_mass = 0.0f;
	m_invMass = 0.0f;
	m_I.SetZero();
	m_invI.SetZero();
	m_worldInvI.SetZero();
	m_sweep.localCenter.SetZero();

	// Static and kinematic bodies have zero mass.
	if (m_type == e_staticBody || m_type == e_kinematicBody)
	{
		m_sweep.worldCenter0 = m_xf.position;
		m_sweep.worldCenter = m_xf.position;
		m_sweep.orientation0 = m_sweep.orientation;
		return;
	}

	// Accumulate the mass about the body origin of all shapes.
	b3Vec3 localCenter;
	localCenter.SetZero();
	for (b3Shape* s = m_shapeList.m_head; s; s = s->m_next)
	{
		if (s->m_density == 0.0f) 
		{
			continue;
		}
	
		b3MassData massData;
		s->ComputeMass(&massData, s->m_density);
		
		localCenter += massData.mass * massData.center;
		m_mass += massData.mass;
		m_I += massData.I;
	}

	if (m_mass > 0.0f) 
	{
		// Compute local center of mass.
		m_invMass = 1.0f / m_mass;
		localCenter *= m_invMass;

		// Shift inertia about the body origin into the body local center of mass.
		m_I = m_I - m_mass * b3Steiner(localCenter);
		
		B3_ASSERT(m_I.x.x > 0.0f);
		B3_ASSERT(m_I.y.y > 0.0f);
		B3_ASSERT(m_I.z.z > 0.0f);

		// Compute inverse inertia about the body local center of mass.
		m_invI = b3Inverse(m_I);

		// Align the inverse inertia with the world frame of the body.
		m_worldInvI = b3RotateToFrame(m_invI, m_xf.rotation);

		// Fix rotation.
		if (m_flags & e_fixedRotationX)
		{
			m_invI.y.y = 0.0f;
			m_invI.z.y = 0.0f;
			m_invI.y.z = 0.0f;
			m_invI.z.z = 0.0f;

			m_worldInvI.y.y = 0.0f;
			m_worldInvI.z.y = 0.0f;
			m_worldInvI.y.z = 0.0f;
			m_worldInvI.z.z = 0.0f;
		}

		if (m_flags & e_fixedRotationY)
		{
			m_invI.x.x = 0.0f;
			m_invI.x.z = 0.0f;
			m_invI.z.x = 0.0f;
			m_invI.z.z = 0.0f;

			m_worldInvI.x.x = 0.0f;
			m_worldInvI.x.z = 0.0f;
			m_worldInvI.z.x = 0.0f;
			m_worldInvI.z.z = 0.0f;
		}

		if (m_flags & e_fixedRotationZ)
		{
			m_invI.x.x = 0.0f;
			m_invI.x.y = 0.0f;
			m_invI.y.x = 0.0f;
			m_invI.y.y = 0.0f;

			m_worldInvI.x.x = 0.0f;
			m_worldInvI.x.y = 0.0f;
			m_worldInvI.y.x = 0.0f;
			m_worldInvI.y.y = 0.0f;
		}
	}
	else 
	{
		// Force all dynamic bodies to have positive mass.
		m_mass = 1.0f;
		m_invMass = 1.0f;
	}

	// Move center of mass.
	b3Vec3 oldCenter = m_sweep.worldCenter;
	m_sweep.localCenter = localCenter;
	m_sweep.worldCenter = b3Mul(m_xf, m_sweep.localCenter);
	m_sweep.worldCenter0 = m_sweep.worldCenter;

	// Update center of mass velocity.
	m_linearVelocity += b3Cross(m_angularVelocity, m_sweep.worldCenter - oldCenter);
}