Exemplo n.º 1
0
// Integrate - Integrates particle forward in time by specified amount.
void Particle::Integrate(marb duration)
{
    assert(duration > 0.0);

    position.AddScaledVector(velocity, duration); // Updates linear position.

    // Work out the acceleration from the force.
    Vector3 resultingAcc = acceleration;
    resultingAcc.AddScaledVector(forceAccum, inverseMass);

    velocity.AddScaledVector(resultingAcc, duration); // Update linear velocity based on the calculated acceleration.

    velocity *= marb_pow(damping, duration); // Inflicts drag on the object by applying damping

    ClearAccumulator(); // Clear the forces acting on the particle
}
Exemplo n.º 2
0
void Particle::Integrate(real duration)
{
	if(inverseMass <= 0.0f) return;

	assert(duration > 0.0);

	//update linear position
	position.AddScaledVector(velocity, duration);

	//Work out the acceleration from the force
	Vector3 resultingAcceleration = acceleration;
	resultingAcceleration.AddScaledVector(forceAccum, inverseMass);

	//Update linear velocity from the accerlation
	velocity.AddScaledVector(resultingAcceleration, duration);

	//Impose Drag
	velocity *= real_pow(damping, duration);

	//clear the forces
	ClearAccumlator();
}
Exemplo n.º 3
0
void Contact::ApplyPositionChange(Vector3 linearChange[2], Vector3 angularChange[2], marb penetration) {
    const marb angularLimit = (marb)0.2f;
    marb angularMove[2];
    marb linearMove[2];

    marb totalInertia = 0;
    marb linearInertia[2];
    marb angularInertia[2];

    // We need to work out the inertia of each object in the direction
    // of the contact normal, due to angular inertia only.
    for (unsigned i = 0; i < 2; i++) if (body[i]) {
        Matrix3 inverseInertiaTensor;
        body[i]->GetInverseInertiaTensorWorld(&inverseInertiaTensor);

        // Use the same procedure as for calculating frictionless
        // velocity change to work out the angular inertia.
        Vector3 angularInertiaWorld =
            relativeContactPosition[i] % contactNormal;
        angularInertiaWorld =
            inverseInertiaTensor.Transform(angularInertiaWorld);
        angularInertiaWorld =
            angularInertiaWorld % relativeContactPosition[i];
        angularInertia[i] =
            angularInertiaWorld * contactNormal;

        // The linear component is simply the inverse mass
        linearInertia[i] = body[i]->GetInverseMass();

        // Keep track of the total inertia from all components
        totalInertia += linearInertia[i] + angularInertia[i];

        // We break the loop here so that the totalInertia value is
        // completely calculated (by both iterations) before
        // continuing.
    }

    // Loop through again calculating and applying the changes
    for (unsigned i = 0; i < 2; i++) if (body[i]) {
        // The linear and angular movements required are in proportion to
        // the two inverse inertias.
        marb sign = (i == 0)?1:-1;
        angularMove[i] =
            sign * penetration * (angularInertia[i] / totalInertia);
        linearMove[i] =
            sign * penetration * (linearInertia[i] / totalInertia);

        // To avoid angular projections that are too great (when mass is large
        // but inertia tensor is small) limit the angular move.
        Vector3 projection = relativeContactPosition[i];
        projection.AddScaledVector(
            contactNormal,
            -relativeContactPosition[i].ScalarProduct(contactNormal)
            );

        // Use the small angle approximation for the sine of the angle (i.e.
        // the magnitude would be sine(angularLimit) * projection.magnitude
        // but we approximate sine(angularLimit) to angularLimit).
        marb maxMagnitude = angularLimit * projection.Magnitude();

        if (angularMove[i] < -maxMagnitude) {
            marb totalMove = angularMove[i] + linearMove[i];
            angularMove[i] = -maxMagnitude;
            linearMove[i] = totalMove - angularMove[i];

        } else if (angularMove[i] > maxMagnitude) {
            marb totalMove = angularMove[i] + linearMove[i];
            angularMove[i] = maxMagnitude;
            linearMove[i] = totalMove - angularMove[i];
        }

        // We have the linear amount of movement required by turning
        // the rigid body (in angularMove[i]). We now need to
        // calculate the desired rotation to achieve that.
        if (angularMove[i] == 0) {
            // Easy case - no angular movement means no rotation.
            angularChange[i].Clear();

        } else {
            // Work out the direction we'd like to rotate in.
            Vector3 targetAngularDirection =
                relativeContactPosition[i].VectorProduct(contactNormal);

            Matrix3 inverseInertiaTensor;
            body[i]->GetInverseInertiaTensorWorld(&inverseInertiaTensor);

            // Work out the direction we'd need to rotate to achieve that
            angularChange[i] =
                inverseInertiaTensor.Transform(targetAngularDirection) *
                (angularMove[i] / angularInertia[i]);
        }

        // Velocity change is easier - it is just the linear movement
        // along the contact normal.
        linearChange[i] = contactNormal * linearMove[i];

        // Now we can start to apply the values we've calculated.
        // Apply the linear movement
        Vector3 pos;
        body[i]->GetPosition(&pos);
        pos.AddScaledVector(contactNormal, linearMove[i]);
        body[i]->SetPosition(pos);

        // And the change in orientation
        Quaternion q;
        body[i]->GetOrientation(&q);
        q.AddScaledVector(angularChange[i], ((marb)1.0));
        body[i]->SetOrientation(q);

        // We need to calculate the derived data for any body that is
        // asleep, so that the changes are reflected in the object's
        // data. Otherwise the resolution will not change the position
        // of the object, and the next collision detection round will
        // have the same penetration.
        if (!body[i]->GetAwake()) body[i]->CalculateDerivedData();
    }
}