コード例 #1
0
ファイル: contact.go プロジェクト: tbogdala/cubez
// calculateFrictionImpulse calculates the impulse needed to resolve this contact,
// given that the contact has a non-zero coefficient of friction.
func (c *Contact) calculateFrictionImpulse(inverseInertiaTensors [2]m.Matrix3) (impulseContact m.Vector3) {
	inverseMass := c.Bodies[0].GetInverseMass()

	// the equivalent of a cross product in matrices is multiplication
	// by a skew symmetric matrix - we build the matrix for converting
	// between linear and angular quantities.
	var impulseToTorque m.Matrix3
	setSkewSymmetric(&impulseToTorque, &c.relativeContactPosition[0])

	// build the matrix to convert contact impulse to change in velocity in
	// world coordinates
	deltaVelWorld := impulseToTorque.MulMatrix3(&inverseInertiaTensors[0])
	deltaVelWorld = deltaVelWorld.MulMatrix3(&impulseToTorque)
	deltaVelWorld.MulWith(-1.0)

	// check to see if we need to add the second body's data
	if c.Bodies[1] != nil {
		// set the cross product matrix
		setSkewSymmetric(&impulseToTorque, &c.relativeContactPosition[1])

		// calculate the velocity change matrix
		deltaVelWorld2 := impulseToTorque.MulMatrix3(&inverseInertiaTensors[1])
		deltaVelWorld2 = deltaVelWorld2.MulMatrix3(&impulseToTorque)
		deltaVelWorld2.MulWith(-1.0)

		// add to the total delta velocity
		deltaVelWorld.Add(&deltaVelWorld2)

		// add to the inverse mass
		inverseMass += c.Bodies[1].GetInverseMass()
	}

	// do a change of basis to convert into contact coordinates
	deltaVelocity := c.contactToWorld.Transpose()
	deltaVelocity = deltaVelocity.MulMatrix3(&deltaVelWorld)
	deltaVelocity = deltaVelocity.MulMatrix3(&c.contactToWorld)

	// add in the linear velocity change
	deltaVelocity[0] += inverseMass
	deltaVelocity[4] += inverseMass
	deltaVelocity[8] += inverseMass

	// invert to get the impulse needed per unit velocity
	impulseMatrix := deltaVelocity.Invert()

	// find the target velocities to kill
	velKill := m.Vector3{
		c.desiredDeltaVelocity,
		-c.contactVelocity[1],
		-c.contactVelocity[2],
	}

	// find the impulse to kill target velocities
	impulseContact = impulseMatrix.MulVector3(&velKill)

	// check for exceeding friction
	planarImpulse := m.RealSqrt(impulseContact[1]*impulseContact[1] + impulseContact[2]*impulseContact[2])
	if planarImpulse > impulseContact[0]*c.Friction {
		// we need to use dynamic friction
		impulseContact[1] /= planarImpulse
		impulseContact[2] /= planarImpulse

		impulseContact[0] = deltaVelocity[0] +
			deltaVelocity[3]*c.Friction*impulseContact[1] +
			deltaVelocity[6]*c.Friction*impulseContact[2]
		impulseContact[0] = c.desiredDeltaVelocity / impulseContact[0]
		impulseContact[1] *= c.Friction * impulseContact[0]
		impulseContact[2] *= c.Friction * impulseContact[0]
	}

	return
}