Esempio n. 1
0
 /// <summary>
 /// By calling this method the shape inertia and mass is used.
 /// </summary>
 public void SetMassProperties()
 {
     this.inertia = Shape.inertia;
     JMatrix.Inverse(ref inertia, out invInertia);
     this.inverseMass       = 1.0f / Shape.mass;
     useShapeMassProperties = true;
 }
        private void OrientationCorrectionTorque(Matrix4 wantedOrientation, float scale)
        {
#if false
            // this is something like correction = wantedPosition - position
            JMatrix q = JMatrix.Inverse(wantedOrientation) * testBody.Orientation;
            JVector axis;

            float x = q.M32 - q.M23;
            float y = q.M13 - q.M31;
            float z = q.M21 - q.M12;

            float r = JMath.Sqrt(x * x + y * y + z * z);
            float t = q.M11 + q.M22 + q.M33;

            float angle = (float)Math.Atan2(r, t - 1);
            axis = new JVector(x, y, z) * angle;

            if (r != 0.0f)
            {
                axis = axis * (1.0f / r);
            }

            // 80.0f is the spring value "k"
            testBody.AddTorque(JVector.Transform(axis, JMatrix.Inverse(testBody.InverseInertiaWorld)) * 80.0f);

            // also apply some damping
            testBody.AngularVelocity *= 0.9f;
#endif
            Matrix4 q = Matrix4.Invert(wantedOrientation) * physicsObject.RigidBody.Orientation;
            float   x = q._12 - q._21;
            float   y = q._20 - q._02;
            float   z = q._01 - q._10;

            float r = (float)Math.Sqrt(x * x + y * y + z * z);
            float t = q._00 + q._11 + q._22;

            float   angle = (float)Math.Atan2(r, t - 1);
            Vector3 axis  = new Vector3(x, y, z) * angle;
            if (r != 0.0f)
            {
                axis *= (1.0f / r);
            }

            Matrix4 inertiaWorld = Matrix4.Invert(physicsObject.RigidBody.InverseInertiaWorld);
            inertiaWorld = Matrix4.Transpose(inertiaWorld);
            axis         = inertiaWorld.TransformDirection(axis);
            physicsObject.RigidBody.AddTorque(axis * scale);
            physicsObject.RigidBody.AngularVelocity *= 0.9f;
        }
Esempio n. 3
0
        /// <summary>
        /// Called once before iteration starts.
        /// </summary>
        /// <param name="timestep">The 5simulation timestep</param>
        public override void PrepareForIteration(double timestep)
        {
            effectiveMass = body1.invInertiaWorld + body2.invInertiaWorld;

            softnessOverDt = softness / timestep;

            effectiveMass.M11 += softnessOverDt;
            effectiveMass.M22 += softnessOverDt;
            effectiveMass.M33 += softnessOverDt;

            JMatrix.Inverse(ref effectiveMass, out effectiveMass);

            JMatrix orientationDifference;

            JMatrix.Multiply(ref initialOrientation1, ref initialOrientation2, out orientationDifference);
            JMatrix.Transpose(ref orientationDifference, out orientationDifference);

            JMatrix q = orientationDifference * body2.invOrientation * body1.orientation;
            JVector axis;

            double x = q.M32 - q.M23;
            double y = q.M13 - q.M31;
            double z = q.M21 - q.M12;

            double r = JMath.Sqrt(x * x + y * y + z * z);
            double t = q.M11 + q.M22 + q.M33;

            double angle = (double)Math.Atan2(r, t - 1);

            axis = new JVector(x, y, z) * angle;

            if (r != 0.0f)
            {
                axis = axis * (1.0f / r);
            }

            bias = axis * biasFactor * (-1.0f / timestep);

            // Apply previous frame solution as initial guess for satisfying the constraint.
            if (!body1.IsStatic)
            {
                body1.angularVelocity += JVector.Transform(accumulatedImpulse, body1.invInertiaWorld);
            }
            if (!body2.IsStatic)
            {
                body2.angularVelocity += JVector.Transform(-1.0f * accumulatedImpulse, body2.invInertiaWorld);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// The engine used the given values for inertia and mass and ignores
        /// the shape mass properties.
        /// </summary>
        /// <param name="inertia">The inertia/inverse inertia of the untransformed object.</param>
        /// <param name="mass">The mass/inverse mass of the object.</param>
        /// <param name="setAsInverseValues">Sets the InverseInertia and the InverseMass
        /// to this values.</param>
        public void SetMassProperties(JMatrix inertia, float mass, bool setAsInverseValues)
        {
            if (setAsInverseValues)
            {
                this.invInertia = inertia;
                JMatrix.Inverse(ref inertia, out this.inertia);
                this.inverseMass = mass;
            }
            else
            {
                this.inertia = inertia;
                JMatrix.Inverse(ref inertia, out this.invInertia);
                this.inverseMass = 1.0f / mass;
            }

            useShapeMassProperties = false;
            Update();
        }
Esempio n. 5
0
        /// <summary>
        /// Called once before iteration starts.
        /// </summary>
        /// <param name="timestep">The 5simulation timestep</param>
        public override void PrepareForIteration(float timestep)
        {
            effectiveMass = body1.invInertiaWorld;

            softnessOverDt = softness / timestep;

            effectiveMass.M11 += softnessOverDt;
            effectiveMass.M22 += softnessOverDt;
            effectiveMass.M33 += softnessOverDt;

            JMatrix.Inverse(ref effectiveMass, out effectiveMass);

            JMatrix q = JMatrix.Transpose(orientation) * body1.orientation;
            JVector axis;

            float x = q.M32 - q.M23;
            float y = q.M13 - q.M31;
            float z = q.M21 - q.M12;

            float r = JMath.Sqrt(x * x + y * y + z * z);
            float t = q.M11 + q.M22 + q.M33;

            float angle = (float)Math.Atan2(r, t - 1);

            axis = new JVector(x, y, z) * angle;

            if (r != 0.0f)
            {
                axis = axis * (1.0f / r);
            }

            bias = axis * biasFactor * (-1.0f / timestep);

            // Apply previous frame solution as initial guess for satisfying the constraint.
            if (!body1.IsStatic)
            {
                body1.angularVelocity += JVector.Transform(accumulatedImpulse, body1.invInertiaWorld);
            }
        }
Esempio n. 6
0
        // TODO: Apply edge forgiveness when sliding off the edge of a triangle (and becoming airborne).
        // TODO: For pseudo-static wall control, probably need to rotate the normal based on body orientation each step.
        public override void PreStep(float step)
        {
            // The alternative here is body-controlled (i.e. wall control on a pseudo-static body).
            bool isMeshControlled = wall != null;

            var body = Parent.ControllingBody;
            var v    = isMeshControlled ? body.LinearVelocity.ToVec3() : Parent.ManualVelocity;

            // TODO: Apply jump deceleration as appropriate (feels weird to keep gaining height when jump is released).
            // "Wall gravity" only applies when moving downward (in order to give the player a little more control when
            // setting up wall jumps).
            v.y -= (v.y > 0 ? PhysicsConstants.Gravity : wallGravity) * step;

            // TODO: Quickly decelerate if the wall is hit at a downward speed faster than terminal.
            if (v.y < -wallTerminalSpeed)
            {
                v.y = -wallTerminalSpeed;
            }

            // TODO: Consider applying wall press logic (i.e. only move side to side if you're angled enough).
            var flatV = v.swizzle.xz;

            // Acceleration
            if (Utilities.LengthSquared(FlatDirection) > 0)
            {
                var perpendicular = flatNormal.swizzle.xz;
                perpendicular = new vec2(-perpendicular.y, perpendicular.x);
                flatV        += Utilities.Project(FlatDirection, perpendicular) * acceleration * step;

                // TODO: Quickly decelerate local max if the wall is hit with fast sideways speed.
                // This limits maximum speed based on flat direction. To me, this feels more natural than accelerating
                // up to full speed even when barely moving sideways (relative to the wall).
                var localMax = Math.Abs(Utilities.Dot(FlatDirection, perpendicular)) * maxSpeed;

                if (Utilities.LengthSquared(flatV) > localMax * localMax)
                {
                    flatV = Utilities.Normalize(flatV) * localMax;
                }
            }
            // Deceleration
            else if (Utilities.LengthSquared(flatV) > 0)
            {
                int oldSign = Math.Sign(flatV.x != 0 ? flatV.x : flatV.y);

                flatV -= Utilities.Normalize(flatV) * deceleration * step;

                int newSign = Math.Sign(flatV.x != 0 ? flatV.x : flatV.y);

                if (oldSign != newSign)
                {
                    flatV = vec2.Zero;
                }
            }

            v.x = flatV.x;
            v.z = flatV.y;

            if (isMeshControlled)
            {
                body.LinearVelocity = v.ToJVector();
            }
            else
            {
                Parent.ManualVelocity  = v;
                Parent.ManualPosition += JVector.Transform(v.ToJVector(), JMatrix.Inverse(wallBody.Orientation)) *
                                         step;
            }

            // TODO: Apply a thin forgiveness range for staying on a wall.
            var d = Utilities.Dot(FlatDirection, flatNormal.swizzle.xz);

            // This means that the flat direction is pressing away the wall. A thin forgiveness angle (specified as a
            // dot product value) is used to help stick the player while still moving in a direction *near* parallel
            // to the wall.
            if (d > stickForgiveness)
            {
                wallStickTimer.IsPaused = false;
            }
        }
    public override void PrepareForIteration(float timestep)
    {
        // send a ray from our feet position down.
        // if we collide with something which is 0.05f units below our feets remember this!

        RigidBody resultingBody = null;
        JVector   normal;
        float     frac;

        var  rayOrigin = Body1.Position + JVector.Down * (feetPosition - 0.1f);
        bool result    = JPhysics.World.CollisionSystem.Raycast(
            rayOrigin,
            JVector.Down,
            (body, hitNormal, fraction) => body != Body1,
            out resultingBody,
            out normal,
            out frac);

        if (BodyWalkingOn != null)
        {
            contactPoint      = rayOrigin + JVector.Down * frac;
            localContactPoint = JVector.Transform(contactPoint - BodyWalkingOn.Position, JMatrix.Inverse(BodyWalkingOn.Orientation));
        }

        BodyWalkingOn = (result && frac <= 0.2f) ? resultingBody : null;
        shouldIJump   = TryJump && result && (frac <= 0.2f) && (Body1.LinearVelocity.Y < JumpVelocity);
    }