예제 #1
0
        // Build the Jacobian
        public void Build(
            MTransform aFromConstraint, MTransform bFromConstraint,
            MotionVelocity velocityA, MotionVelocity velocityB,
            MotionData motionA, MotionData motionB,
            Constraint constraint, sfloat tau, sfloat damping)
        {
            // Copy the constraint data
            int freeIndex = constraint.FreeAxis2D;

            AxisAinA = aFromConstraint.Rotation[freeIndex];
            AxisBinB = bFromConstraint.Rotation[freeIndex];
            MinAngle = constraint.Min;
            MaxAngle = constraint.Max;
            Tau      = tau;
            Damping  = damping;
            BFromA   = math.mul(math.inverse(motionB.WorldFromMotion.rot), motionA.WorldFromMotion.rot);

            // Calculate the initial error
            {
                float3 axisAinB = math.mul(BFromA, AxisAinA);
                sfloat sinAngle = math.length(math.cross(axisAinB, AxisBinB));
                sfloat cosAngle = math.dot(axisAinB, AxisBinB);
                sfloat angle    = math.atan2(sinAngle, cosAngle);
                InitialError = JacobianUtilities.CalculateError(angle, MinAngle, MaxAngle);
            }
        }
예제 #2
0
            internal static void ExecuteImpl(int i, NativeArray <MotionData> motionDatas, NativeArray <MotionVelocity> motionVelocities, sfloat timeStep)
            {
                MotionData     motionData     = motionDatas[i];
                MotionVelocity motionVelocity = motionVelocities[i];

                // Update motion space
                {
                    // center of mass
                    IntegratePosition(ref motionData.WorldFromMotion.pos, motionVelocity.LinearVelocity, timeStep);

                    // orientation
                    IntegrateOrientation(ref motionData.WorldFromMotion.rot, motionVelocity.AngularVelocity, timeStep);
                }

                // Update velocities
                {
                    // damping
                    motionVelocity.LinearVelocity  *= math.clamp(sfloat.One - motionData.LinearDamping * timeStep, sfloat.Zero, sfloat.One);
                    motionVelocity.AngularVelocity *= math.clamp(sfloat.One - motionData.AngularDamping * timeStep, sfloat.Zero, sfloat.One);
                }

                // Write back
                motionDatas[i]      = motionData;
                motionVelocities[i] = motionVelocity;
            }
예제 #3
0
        // Build the Jacobian
        public void Build(
            MTransform aFromConstraint, MTransform bFromConstraint,
            MotionVelocity velocityA, MotionVelocity velocityB,
            MotionData motionA, MotionData motionB,
            Constraint constraint, sfloat tau, sfloat damping)
        {
            WorldFromA = motionA.WorldFromMotion;
            WorldFromB = motionB.WorldFromMotion;

            PivotAinA = aFromConstraint.Translation;
            PivotBinB = bFromConstraint.Translation;

            AxisInB = float3.zero;
            Is1D    = false;

            MinDistance = constraint.Min;
            MaxDistance = constraint.Max;

            Tau     = tau;
            Damping = damping;

            // TODO.ma - this code is not always correct in its choice of pivotB.
            // The constraint model is asymmetrical.  B is the master, and the constraint feature is defined in B-space as a region affixed to body B.
            // For example, we can conceive of a 1D constraint as a plane attached to body B through constraint.PivotB, and constraint.PivotA is constrained to that plane.
            // A 2D constraint is a line attached to body B.  A 3D constraint is a point.
            // So, while we always apply an impulse to body A at pivotA, we apply the impulse to body B somewhere on the constraint region.
            // This code chooses that point by projecting pivotA onto the point, line or plane, which seems pretty reasonable and also analogous to how contact constraints work.
            // However, if the limits are nonzero, then the region is not a point, line or plane.  It is a spherical shell, cylindrical shell, or the space between two parallel planes.
            // In that case, it is not projecting A to a point on the constraint region.  This will not prevent solving the constraint, but the solution may not look correct.
            // For now I am leaving it because it is not important to get the most common constraint situations working.  If you use a ball and socket, or a prismatic constraint with a
            // static master body, or a stiff spring, then there's no problem.  However, I think it should eventually be fixed.  The min and max limits have different projections, so
            // probably the best solution is to make two jacobians whenever min != max.  My assumption is that 99% of these are ball and sockets with min = max = 0, so I would rather have
            // some waste in the min != max case than generalize this code to deal with different pivots and effective masses depending on which limit is hit.

            if (!math.all(constraint.ConstrainedAxes))
            {
                Is1D = constraint.ConstrainedAxes.x ^ constraint.ConstrainedAxes.y ^ constraint.ConstrainedAxes.z;

                // Project pivot A onto the line or plane in B that it is attached to
                RigidTransform bFromA    = math.mul(math.inverse(WorldFromB), WorldFromA);
                float3         pivotAinB = math.transform(bFromA, PivotAinA);
                float3         diff      = pivotAinB - PivotBinB;
                for (int i = 0; i < 3; i++)
                {
                    float3 column = bFromConstraint.Rotation[i];
                    AxisInB = math.select(column, AxisInB, Is1D ^ constraint.ConstrainedAxes[i]);

                    float3 dot = math.select(math.dot(column, diff), sfloat.Zero, constraint.ConstrainedAxes[i]);
                    PivotBinB += column * dot;
                }
            }

            // Calculate the current error
            InitialError = CalculateError(
                new MTransform(WorldFromA.rot, WorldFromA.pos),
                new MTransform(WorldFromB.rot, WorldFromB.pos),
                out float3 directionUnused);
        }
예제 #4
0
        // Build the Jacobian
        public void Build(
            MTransform aFromConstraint, MTransform bFromConstraint,
            MotionVelocity velocityA, MotionVelocity velocityB,
            MotionData motionA, MotionData motionB,
            Constraint constraint, sfloat tau, sfloat damping)
        {
            BFromA    = math.mul(math.inverse(motionB.WorldFromMotion.rot), motionA.WorldFromMotion.rot);
            RefBFromA = new quaternion(math.mul(bFromConstraint.Rotation, aFromConstraint.InverseRotation));
            MinAngle  = constraint.Min;
            MaxAngle  = constraint.Max;
            Tau       = tau;
            Damping   = damping;

            quaternion jointOrientation = math.mul(math.inverse(RefBFromA), BFromA);
            sfloat     initialAngle     = math.asin(math.length(jointOrientation.value.xyz)) * (sfloat)2.0f;

            InitialError = JacobianUtilities.CalculateError(initialAngle, MinAngle, MaxAngle);
        }
예제 #5
0
        // Build the Jacobian
        public void Build(
            MTransform aFromConstraint, MTransform bFromConstraint,
            MotionVelocity velocityA, MotionVelocity velocityB,
            MotionData motionA, MotionData motionB,
            Constraint constraint, sfloat tau, sfloat damping)
        {
            // Copy the constraint into the jacobian
            AxisIndex        = constraint.ConstrainedAxis1D;
            AxisInMotionA    = aFromConstraint.Rotation[AxisIndex];
            MinAngle         = constraint.Min;
            MaxAngle         = constraint.Max;
            Tau              = tau;
            Damping          = damping;
            MotionBFromA     = math.mul(math.inverse(motionB.WorldFromMotion.rot), motionA.WorldFromMotion.rot);
            MotionAFromJoint = new quaternion(aFromConstraint.Rotation);
            MotionBFromJoint = new quaternion(bFromConstraint.Rotation);

            // Calculate the current error
            InitialError = CalculateError(MotionBFromA);
        }