Пример #1
0
 public void SupportCenter(out FPVector center)
 {
     center = owner.points[indices.I0].position;
     FPVector.Add(ref center, ref owner.points[indices.I1].position, out center);
     FPVector.Add(ref center, ref owner.points[indices.I2].position, out center);
     FPVector.Multiply(ref center, FP.One / (3 * FP.One), out center);
 }
Пример #2
0
        /// <summary>
        /// Recalculates the axis aligned bounding box and the inertia
        /// values in world space.
        /// </summary>
        public virtual void Update()
        {
            if (isParticle)
            {
                this.inertia        = FPMatrix.Zero;
                this.invInertia     = this.invInertiaWorld = FPMatrix.Zero;
                this.invOrientation = this.orientation = FPMatrix.Identity;
                this.boundingBox    = shape.boundingBox;
                FPVector.Add(ref boundingBox.min, ref this.position, out boundingBox.min);
                FPVector.Add(ref boundingBox.max, ref this.position, out boundingBox.max);

                angularVelocity.MakeZero();
            }
            else
            {
                // Given: Orientation, Inertia
                FPMatrix.Transpose(ref orientation, out invOrientation);
                this.Shape.GetBoundingBox(ref orientation, out boundingBox);
                FPVector.Add(ref boundingBox.min, ref this.position, out boundingBox.min);
                FPVector.Add(ref boundingBox.max, ref this.position, out boundingBox.max);


                if (!isStatic)
                {
                    FPMatrix.Multiply(ref invOrientation, ref invInertia, out invInertiaWorld);
                    FPMatrix.Multiply(ref invInertiaWorld, ref orientation, out invInertiaWorld);
                }
            }
        }
Пример #3
0
        /// <summary>
        /// SupportMapping. Finds the point in the shape furthest away from the given direction.
        /// Imagine a plane with a normal in the search direction. Now move the plane along the normal
        /// until the plane does not intersect the shape. The last intersection point is the result.
        /// </summary>
        /// <param name="direction">The direction.</param>
        /// <param name="result">The result.</param>
        public override void SupportMapping(ref FPVector direction, out FPVector result)
        {
            FPVector expandVector;

            FPVector.Normalize(ref direction, out expandVector);
            FPVector.Multiply(ref expandVector, sphericalExpansion, out expandVector);

            int minIndex = 0;
            FP  min      = FPVector.Dot(ref points[0], ref direction);
            FP  dot      = FPVector.Dot(ref points[1], ref direction);

            if (dot > min)
            {
                min      = dot;
                minIndex = 1;
            }
            dot = FPVector.Dot(ref points[2], ref direction);
            if (dot > min)
            {
                min      = dot;
                minIndex = 2;
            }

            FPVector.Add(ref points[minIndex], ref expandVector, out result);
        }
Пример #4
0
 /// <summary>
 /// Adds a force to the center of the body. The force gets applied
 /// the next time <see cref="World.Step"/> is called. The 'impact'
 /// of the force depends on the time it is applied to a body - so
 /// the timestep influences the energy added to the body.
 /// </summary>
 /// <param name="force">The force to add next <see cref="World.Step"/>.</param>
 /// <param name="pos">The position where the force is applied.</param>
 public void AddForce(FPVector force, FPVector pos)
 {
     FPVector.Add(ref this.force, ref force, out this.force);
     FPVector.Subtract(ref pos, ref this.position, out pos);
     FPVector.Cross(ref pos, ref force, out pos);
     FPVector.Add(ref pos, ref this.torque, out this.torque);
 }
        private void IntegrateForces()
        {
            for (int index = 0, length = rigidBodies.Count; index < length; index++)
            {
                RigidBody body = rigidBodies[index];
                if (!body.isStatic && body.IsActive)
                {
                    FPVector temp;
                    FPVector.Multiply(ref body.force, body.inverseMass * timestep, out temp);
                    FPVector.Add(ref temp, ref body.linearVelocity, out body.linearVelocity);

                    if (!(body.isParticle))
                    {
                        FPVector.Multiply(ref body.torque, timestep, out temp);
                        FPVector.Transform(ref temp, ref body.invInertiaWorld, out temp);
                        FPVector.Add(ref temp, ref body.angularVelocity, out body.angularVelocity);
                    }

                    if (body.affectedByGravity)
                    {
                        FPVector.Multiply(ref gravity, timestep, out temp);
                        FPVector.Add(ref body.linearVelocity, ref temp, out body.linearVelocity);
                    }
                }

                body.force.MakeZero();
                body.torque.MakeZero();
            }
        }
Пример #6
0
 private void SupportMapping(RigidBody body, Shape workingShape, ref FPVector direction, out FPVector result)
 {
     FPVector.Transform(ref direction, ref body.invOrientation, out result);
     workingShape.SupportMapping(ref result, out result);
     FPVector.Transform(ref result, ref body.orientation, out result);
     FPVector.Add(ref result, ref body.position, out result);
 }
Пример #7
0
        /// <summary>
        /// The points in wolrd space gets recalculated by transforming the
        /// local coordinates. Also new penetration depth is estimated.
        /// </summary>
        public void UpdatePosition()
        {
            if (body1IsMassPoint)
            {
                FPVector.Add(ref realRelPos1, ref body1.position, out p1);
            }
            else
            {
                FPVector.Transform(ref realRelPos1, ref body1.orientation, out p1);
                FPVector.Add(ref p1, ref body1.position, out p1);
            }

            if (body2IsMassPoint)
            {
                FPVector.Add(ref realRelPos2, ref body2.position, out p2);
            }
            else
            {
                FPVector.Transform(ref realRelPos2, ref body2.orientation, out p2);
                FPVector.Add(ref p2, ref body2.position, out p2);
            }


            FPVector dist; FPVector.Subtract(ref p1, ref p2, out dist);

            penetration = FPVector.Dot(ref dist, ref normal);
        }
 /// <summary>
 /// SupportMapping. Finds the point in the shape furthest away from the given direction.
 /// Imagine a plane with a normal in the search direction. Now move the plane along the normal
 /// until the plane does not intersect the shape. The last intersection point is the result.
 /// </summary>
 /// <param name="direction">The direction.</param>
 /// <param name="result">The result.</param>
 public override void SupportMapping(ref FPVector direction, out FPVector result)
 {
     FPVector.Transform(ref direction, ref shapes[currentShape].invOrientation, out result);
     shapes[currentShape].Shape.SupportMapping(ref direction, out result);
     FPVector.Transform(ref result, ref shapes[currentShape].orientation, out result);
     FPVector.Add(ref result, ref shapes[currentShape].position, out result);
 }
        /// <summary>
        /// Called once before iteration starts.
        /// </summary>
        /// <param name="timestep">The simulation timestep</param>
        public override void PrepareForIteration(FP timestep)
        {
            FPVector.Transform(ref localAnchor1, ref body1.orientation, out r1);
            FPVector.Transform(ref localAnchor2, ref body2.orientation, out r2);

            FPVector p1, p2, dp;

            FPVector.Add(ref body1.position, ref r1, out p1);
            FPVector.Add(ref body2.position, ref r2, out p2);

            FPVector.Subtract(ref p2, ref p1, out dp);

            FPVector l = FPVector.Transform(lineNormal, body1.orientation);

            l.Normalize();

            FPVector t = (p1 - p2) % l;

            if (t.sqrMagnitude != FP.Zero)
            {
                t.Normalize();
            }
            t = t % l;

            jacobian[0] = t;                      // linearVel Body1
            jacobian[1] = (r1 + p2 - p1) % t;     // angularVel Body1
            jacobian[2] = -FP.One * t;            // linearVel Body2
            jacobian[3] = -FP.One * r2 % t;       // angularVel Body2

            effectiveMass = body1.inverseMass + body2.inverseMass
                            + FPVector.Transform(jacobian[1], body1.invInertiaWorld) * jacobian[1]
                            + FPVector.Transform(jacobian[3], body2.invInertiaWorld) * jacobian[3];

            softnessOverDt = softness / timestep;
            effectiveMass += softnessOverDt;

            if (effectiveMass != 0)
            {
                effectiveMass = FP.One / effectiveMass;
            }

            bias = -(l % (p2 - p1)).magnitude * biasFactor * (FP.One / timestep);

            if (!body1.isStatic)
            {
                body1.linearVelocity  += body1.inverseMass * accumulatedImpulse * jacobian[0];
                body1.angularVelocity += FPVector.Transform(accumulatedImpulse * jacobian[1], body1.invInertiaWorld);
            }

            if (!body2.isStatic)
            {
                body2.linearVelocity  += body2.inverseMass * accumulatedImpulse * jacobian[2];
                body2.angularVelocity += FPVector.Transform(accumulatedImpulse * jacobian[3], body2.invInertiaWorld);
            }
        }
Пример #10
0
        /// <summary>
        /// Applies an impulse on the center of the body. Changing
        /// linear velocity.
        /// </summary>
        /// <param name="impulse">Impulse direction and magnitude.</param>
        public void ApplyImpulse(FPVector impulse)
        {
            if (this.isStatic)
            {
                return;
            }

            FPVector temp;

            FPVector.Multiply(ref impulse, inverseMass, out temp);
            FPVector.Add(ref linearVelocity, ref temp, out linearVelocity);
        }
Пример #11
0
        public override void SupportMapping(ref FPVector direction, out FPVector result)
        {
            FPVector temp1, temp2 = FPVector.zero;

            for (int i = 0; i < shapes.Count; i++)
            {
                shapes[i].SupportMapping(ref direction, out temp1);
                FPVector.Add(ref temp1, ref temp2, out temp2);
            }

            FPVector.Subtract(ref temp2, ref shifted, out result);
        }
        private void IntegrateCallback(object obj)
        {
            RigidBody body = obj as RigidBody;

            FPVector temp;

            FPVector.Multiply(ref body.linearVelocity, timestep, out temp);
            FPVector.Add(ref temp, ref body.position, out body.position);

            if (!(body.isParticle))
            {
                //exponential map
                FPVector axis;
                FP       angle = body.angularVelocity.magnitude;

                if (angle < FP.EN3)
                {
                    // use Taylor's expansions of sync function
                    // axis = body.angularVelocity * (FP.Half * timestep - (timestep * timestep * timestep) * (0.020833333333f) * angle * angle);
                    FPVector.Multiply(ref body.angularVelocity, (FP.Half * timestep - (timestep * timestep * timestep) * (2082 * FP.EN6) * angle * angle), out axis);
                }
                else
                {
                    // sync(fAngle) = sin(c*fAngle)/t
                    FPVector.Multiply(ref body.angularVelocity, (FP.Sin(FP.Half * angle * timestep) / angle), out axis);
                }

                FPQuaternion dorn = new FPQuaternion(axis.x, axis.y, axis.z, FP.Cos(angle * timestep * FP.Half));
                FPQuaternion ornA; FPQuaternion.CreateFromMatrix(ref body.orientation, out ornA);

                FPQuaternion.Multiply(ref dorn, ref ornA, out dorn);

                dorn.Normalize(); FPMatrix.CreateFromQuaternion(ref dorn, out body.orientation);
            }

            body.linearVelocity  *= 1 / (1 + timestep * body.linearDrag);
            body.angularVelocity *= 1 / (1 + timestep * body.angularDrag);

            /*if ((body.Damping & RigidBody.DampingType.Linear) != 0)
             *  FPVector.Multiply(ref body.linearVelocity, currentLinearDampFactor, out body.linearVelocity);
             *
             * if ((body.Damping & RigidBody.DampingType.Angular) != 0)
             *  FPVector.Multiply(ref body.angularVelocity, currentAngularDampFactor, out body.angularVelocity);*/

            body.Update();


            if (CollisionSystem.EnableSpeculativeContacts || body.EnableSpeculativeContacts)
            {
                body.SweptExpandBoundingBox(timestep);
            }
        }
Пример #13
0
        /// <summary>
        /// Called once before iteration starts.
        /// </summary>
        /// <param name="timestep">The 5simulation timestep</param>
        public override void PrepareForIteration(FP timestep)
        {
            FPVector.Transform(ref localAnchor1, ref body1.orientation, out r1);
            FPVector.Transform(ref localAnchor2, ref body2.orientation, out r2);

            FPVector p1, p2, dp;

            FPVector.Add(ref body1.position, ref r1, out p1);
            FPVector.Add(ref body2.position, ref r2, out p2);

            FPVector.Subtract(ref p2, ref p1, out dp);

            FP deltaLength = dp.magnitude;

            FPVector n = p2 - p1;

            if (n.sqrMagnitude != FP.Zero)
            {
                n.Normalize();
            }

            jacobian[0] = -FP.One * n;
            jacobian[1] = -FP.One * (r1 % n);
            jacobian[2] = FP.One * n;
            jacobian[3] = (r2 % n);

            effectiveMass = body1.inverseMass + body2.inverseMass
                            + FPVector.Transform(jacobian[1], body1.invInertiaWorld) * jacobian[1]
                            + FPVector.Transform(jacobian[3], body2.invInertiaWorld) * jacobian[3];

            softnessOverDt = softness / timestep;
            effectiveMass += softnessOverDt;

            effectiveMass = FP.One / effectiveMass;

            bias = deltaLength * biasFactor * (FP.One / timestep);

            if (!body1.isStatic)
            {
                body1.linearVelocity  += body1.inverseMass * accumulatedImpulse * jacobian[0];
                body1.angularVelocity += FPVector.Transform(accumulatedImpulse * jacobian[1], body1.invInertiaWorld);
            }

            if (!body2.isStatic)
            {
                body2.linearVelocity  += body2.inverseMass * accumulatedImpulse * jacobian[2];
                body2.angularVelocity += FPVector.Transform(accumulatedImpulse * jacobian[3], body2.invInertiaWorld);
            }
        }
Пример #14
0
        /// <summary>
        /// Applies an impulse on the specific position. Changing linear
        /// and angular velocity.
        /// </summary>
        /// <param name="impulse">Impulse direction and magnitude.</param>
        /// <param name="relativePosition">The position where the impulse gets applied
        /// in Body coordinate frame.</param>
        public void ApplyImpulse(FPVector impulse, FPVector relativePosition)
        {
            if (this.isStatic)
            {
                return;
            }

            FPVector temp;

            FPVector.Multiply(ref impulse, inverseMass, out temp);
            FPVector.Add(ref linearVelocity, ref temp, out linearVelocity);

            FPVector.Cross(ref relativePosition, ref impulse, out temp);
            FPVector.Transform(ref temp, ref invInertiaWorld, out temp);
            FPVector.Add(ref angularVelocity, ref temp, out angularVelocity);
        }
Пример #15
0
        /// <summary>
        /// Create a bounding box appropriate for a child, based on a parents AABox
        /// </summary>
        /// <param name="aabb"></param>
        /// <param name="child"></param>
        /// <param name="result"></param>
        #region  private void CreateAABox(ref JBBox aabb, EChild child,out JBBox result)
        private void CreateAABox(ref FPBBox aabb, EChild child, out FPBBox result)
        {
            FPVector dims;

            FPVector.Subtract(ref aabb.max, ref aabb.min, out dims);
            FPVector.Multiply(ref dims, FP.Half, out dims);

            FPVector offset = FPVector.zero;

            switch (child)
            {
            case EChild.PPP: offset = new FPVector(1, 1, 1); break;

            case EChild.PPM: offset = new FPVector(1, 1, 0); break;

            case EChild.PMP: offset = new FPVector(1, 0, 1); break;

            case EChild.PMM: offset = new FPVector(1, 0, 0); break;

            case EChild.MPP: offset = new FPVector(0, 1, 1); break;

            case EChild.MPM: offset = new FPVector(0, 1, 0); break;

            case EChild.MMP: offset = new FPVector(0, 0, 1); break;

            case EChild.MMM: offset = new FPVector(0, 0, 0); break;

            default:
                System.Diagnostics.Debug.WriteLine("Octree.CreateAABox  got impossible child");
                break;
            }

            result     = new FPBBox();
            result.min = new FPVector(offset.x * dims.x, offset.y * dims.y, offset.z * dims.z);
            FPVector.Add(ref result.min, ref aabb.min, out result.min);

            FPVector.Add(ref result.min, ref dims, out result.max);

            // expand it just a tiny bit just to be safe!
            FP extra = FP.EN5;

            FPVector temp; FPVector.Multiply(ref dims, extra, out temp);

            FPVector.Subtract(ref result.min, ref temp, out result.min);
            FPVector.Add(ref result.max, ref temp, out result.max);
        }
Пример #16
0
        private HingeJoint3D(IWorld world, IBody3D body1, IBody3D body2, FPVector position, FPVector hingeAxis) : base((World)world)
        {
            worldPointConstraint = new PointOnPoint[2];

            hingeAxis *= FP.Half;

            FPVector pos1 = position; FPVector.Add(ref pos1, ref hingeAxis, out pos1);
            FPVector pos2 = position; FPVector.Subtract(ref pos2, ref hingeAxis, out pos2);

            worldPointConstraint[0] = new PointOnPoint((RigidBody)body1, (RigidBody)body2, pos1);
            worldPointConstraint[1] = new PointOnPoint((RigidBody)body1, (RigidBody)body2, pos2);

            StateTracker.AddTracking(worldPointConstraint[0]);
            StateTracker.AddTracking(worldPointConstraint[1]);

            Activate();
        }
Пример #17
0
            /// <summary>
            /// Iteratively solve this constraint.
            /// </summary>
            public override void Iterate()
            {
                if (skipConstraint)
                {
                    return;
                }

                FP jv = FPVector.Dot(ref body1.linearVelocity, ref jacobian[0]);

                jv += FPVector.Dot(ref body2.linearVelocity, ref jacobian[1]);

                FP softnessScalar = accumulatedImpulse * softnessOverDt;

                FP lambda = -effectiveMass * (jv + bias + softnessScalar);

                if (behavior == DistanceBehavior.LimitMinimumDistance)
                {
                    FP previousAccumulatedImpulse = accumulatedImpulse;
                    accumulatedImpulse = FPMath.Max(accumulatedImpulse + lambda, 0);
                    lambda             = accumulatedImpulse - previousAccumulatedImpulse;
                }
                else if (behavior == DistanceBehavior.LimitMaximumDistance)
                {
                    FP previousAccumulatedImpulse = accumulatedImpulse;
                    accumulatedImpulse = FPMath.Min(accumulatedImpulse + lambda, 0);
                    lambda             = accumulatedImpulse - previousAccumulatedImpulse;
                }
                else
                {
                    accumulatedImpulse += lambda;
                }

                FPVector temp;

                if (!body1.isStatic)
                {
                    FPVector.Multiply(ref jacobian[0], lambda * body1.inverseMass, out temp);
                    FPVector.Add(ref temp, ref body1.linearVelocity, out body1.linearVelocity);
                }

                if (!body2.isStatic)
                {
                    FPVector.Multiply(ref jacobian[1], lambda * body2.inverseMass, out temp);
                    FPVector.Add(ref temp, ref body2.linearVelocity, out body2.linearVelocity);
                }
            }
Пример #18
0
        public override void MakeHull(ref List <FPVector> triangleList, int generationThreshold)
        {
            List <FPVector> triangles = new List <FPVector>();

            for (int i = 0; i < shapes.Length; i++)
            {
                shapes[i].Shape.MakeHull(ref triangles, 4);
                for (int e = 0; e < triangles.Count; e++)
                {
                    FPVector pos = triangles[e];
                    FPVector.Transform(ref pos, ref shapes[i].orientation, out pos);
                    FPVector.Add(ref pos, ref shapes[i].position, out pos);
                    triangleList.Add(pos);
                }
                triangles.Clear();
            }
        }
Пример #19
0
        private void FindSupportPoints(RigidBody body1, RigidBody body2,
                                       Shape shape1, Shape shape2, ref FPVector point, ref FPVector normal,
                                       out FPVector point1, out FPVector point2)
        {
            FPVector mn; FPVector.Negate(ref normal, out mn);

            FPVector sA; SupportMapping(body1, shape1, ref mn, out sA);
            FPVector sB; SupportMapping(body2, shape2, ref normal, out sB);

            FPVector.Subtract(ref sA, ref point, out sA);
            FPVector.Subtract(ref sB, ref point, out sB);

            FP dot1 = FPVector.Dot(ref sA, ref normal);
            FP dot2 = FPVector.Dot(ref sB, ref normal);

            FPVector.Multiply(ref normal, dot1, out sA);
            FPVector.Multiply(ref normal, dot2, out sB);

            FPVector.Add(ref point, ref sA, out point1);
            FPVector.Add(ref point, ref sB, out point2);
        }
Пример #20
0
        public void DebugDraw(IDebugDrawer drawer)
        {
            FPVector pos1, pos2, pos3;

            for (int i = 0; i < hullPoints.Count; i += 3)
            {
                pos1 = hullPoints[i + 0];
                pos2 = hullPoints[i + 1];
                pos3 = hullPoints[i + 2];

                FPVector.Transform(ref pos1, ref orientation, out pos1);
                FPVector.Add(ref pos1, ref position, out pos1);

                FPVector.Transform(ref pos2, ref orientation, out pos2);
                FPVector.Add(ref pos2, ref position, out pos2);

                FPVector.Transform(ref pos3, ref orientation, out pos3);
                FPVector.Add(ref pos3, ref position, out pos3);

                drawer.DrawTriangle(pos1, pos2, pos3);
            }
        }
Пример #21
0
        /// <summary>
        /// Sets the current shape. First <see cref="Prepare"/> has to be called.
        /// After SetCurrentShape the shape immitates another shape.
        /// </summary>
        /// <param name="index"></param>
        public override void SetCurrentShape(int index)
        {
            bool leftTriangle = false;

            if (index >= numX * numZ)
            {
                leftTriangle = true;
                index       -= numX * numZ;
            }

            int quadIndexX = index % numX;
            int quadIndexZ = index / numX;

            // each quad has two triangles, called 'leftTriangle' and !'leftTriangle'
            if (leftTriangle)
            {
                points[0].Set((minX + quadIndexX + 0) * scaleX, heights[minX + quadIndexX + 0, minZ + quadIndexZ + 0], (minZ + quadIndexZ + 0) * scaleZ);
                points[1].Set((minX + quadIndexX + 1) * scaleX, heights[minX + quadIndexX + 1, minZ + quadIndexZ + 0], (minZ + quadIndexZ + 0) * scaleZ);
                points[2].Set((minX + quadIndexX + 0) * scaleX, heights[minX + quadIndexX + 0, minZ + quadIndexZ + 1], (minZ + quadIndexZ + 1) * scaleZ);
            }
            else
            {
                points[0].Set((minX + quadIndexX + 1) * scaleX, heights[minX + quadIndexX + 1, minZ + quadIndexZ + 0], (minZ + quadIndexZ + 0) * scaleZ);
                points[1].Set((minX + quadIndexX + 1) * scaleX, heights[minX + quadIndexX + 1, minZ + quadIndexZ + 1], (minZ + quadIndexZ + 1) * scaleZ);
                points[2].Set((minX + quadIndexX + 0) * scaleX, heights[minX + quadIndexX + 0, minZ + quadIndexZ + 1], (minZ + quadIndexZ + 1) * scaleZ);
            }

            FPVector sum = points[0];

            FPVector.Add(ref sum, ref points[1], out sum);
            FPVector.Add(ref sum, ref points[2], out sum);
            FPVector.Multiply(ref sum, FP.One / (3 * FP.One), out sum);
            geomCen = sum;

            FPVector.Subtract(ref points[1], ref points[0], out sum);
            FPVector.Subtract(ref points[2], ref points[0], out normal);
            FPVector.Cross(ref sum, ref normal, out normal);
        }
Пример #22
0
        /// <summary>
        /// Transforms the bounding box into the space given by orientation and position.
        /// </summary>
        /// <param name="position"></param>
        /// <param name="orientation"></param>
        /// <param name="result"></param>
        internal void InverseTransform(ref FPVector position, ref FPMatrix orientation)
        {
            FPVector.Subtract(ref max, ref position, out max);
            FPVector.Subtract(ref min, ref position, out min);

            FPVector center;

            FPVector.Add(ref max, ref min, out center);
            center.x *= FP.Half; center.y *= FP.Half; center.z *= FP.Half;

            FPVector halfExtents;

            FPVector.Subtract(ref max, ref min, out halfExtents);
            halfExtents.x *= FP.Half; halfExtents.y *= FP.Half; halfExtents.z *= FP.Half;

            FPVector.TransposedTransform(ref center, ref orientation, out center);

            FPMatrix abs; FPMath.Absolute(ref orientation, out abs);

            FPVector.TransposedTransform(ref halfExtents, ref abs, out halfExtents);

            FPVector.Add(ref center, ref halfExtents, out max);
            FPVector.Subtract(ref center, ref halfExtents, out min);
        }
        /// <summary>
        /// Sets the current shape. First <see cref="Prepare"/> has to be called.
        /// After SetCurrentShape the shape immitates another shape.
        /// </summary>
        /// <param name="index"></param>
        public override void SetCurrentShape(int index)
        {
            vecs[0] = octree.GetVertex(octree.tris[potentialTriangles[index]].I0);
            vecs[1] = octree.GetVertex(octree.tris[potentialTriangles[index]].I1);
            vecs[2] = octree.GetVertex(octree.tris[potentialTriangles[index]].I2);

            FPVector sum = vecs[0];

            FPVector.Add(ref sum, ref vecs[1], out sum);
            FPVector.Add(ref sum, ref vecs[2], out sum);
            FPVector.Multiply(ref sum, FP.One / (3 * FP.One), out sum);


            geomCen = sum;

            FPVector.Subtract(ref vecs[1], ref vecs[0], out sum);
            FPVector.Subtract(ref vecs[2], ref vecs[0], out normal);
            FPVector.Cross(ref sum, ref normal, out normal);

            if (flipNormal)
            {
                normal.Negate();
            }
        }
Пример #24
0
 /// <summary>
 /// Adds torque to the body. The torque gets applied
 /// the next time <see cref="World.Step"/> is called. The 'impact'
 /// of the torque depends on the time it is applied to a body - so
 /// the timestep influences the energy added to the body.
 /// </summary>
 /// <param name="torque">The torque to add next <see cref="World.Step"/>.</param>
 public void AddRelativeTorque(FPVector torque)
 {
     torque = FPVector.Transform(torque, this.FPOrientation);
     FPVector.Add(ref torque, ref this.torque, out this.torque);
 }
Пример #25
0
        //    public static bool TimeOfImpact(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1,
        //ref JMatrix orientation2, ref JVector position1, ref JVector position2, ref JVector sweptA, ref JVector sweptB,
        //out JVector p1, out JVector p2, out JVector normal)
        //    {

        //        VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew();
        //        simplexSolver.Reset();

        //        FP lambda = FP.Zero;

        //        p1 = p2 = JVector.Zero;

        //        JVector x1 = position1;
        //        JVector x2 = position2;

        //        JVector r = sweptA - sweptB;
        //        JVector w, v;

        //        JVector supVertexA;
        //        JVector rn = JVector.Negate(r);
        //        SupportMapTransformed(support1, ref orientation1, ref x1, ref rn, out supVertexA);

        //        JVector supVertexB;
        //        SupportMapTransformed(support2, ref orientation2, ref x2, ref r, out supVertexB);

        //        v = supVertexA - supVertexB;

        //        bool hasResult = false;

        //        normal = JVector.Zero;


        //        FP lastLambda = lambda;

        //        int maxIter = MaxIterations;

        //        FP distSq = v.LengthSquared();
        //        FP epsilon = FP.EN5;

        //        FP VdotR;

        //        while ((distSq > epsilon) && (maxIter-- != 0))
        //        {

        //            JVector vn = JVector.Negate(v);
        //            SupportMapTransformed(support1, ref orientation1, ref x1, ref vn, out supVertexA);
        //            SupportMapTransformed(support2, ref orientation2, ref x2, ref v, out supVertexB);
        //            w = supVertexA - supVertexB;

        //            FP VdotW = JVector.Dot(ref v, ref w);

        //            if (VdotW > FP.Zero)
        //            {
        //                VdotR = JVector.Dot(ref v, ref r);

        //                if (VdotR >= -JMath.Epsilon)
        //                {
        //                    simplexSolverPool.GiveBack(simplexSolver);
        //                    return false;
        //                }
        //                else
        //                {
        //                    lambda = lambda - VdotW / VdotR;


        //                    x1 = position1 + lambda * sweptA;
        //                    x2 = position2 + lambda * sweptB;

        //                    w = supVertexA - supVertexB;

        //                    normal = v;
        //                    hasResult = true;
        //                }
        //            }
        //            if (!simplexSolver.InSimplex(w)) simplexSolver.AddVertex(w, supVertexA, supVertexB);
        //            if (simplexSolver.Closest(out v))
        //            {
        //                distSq = v.LengthSquared();
        //                normal = v;
        //                hasResult = true;
        //            }
        //            else distSq = FP.Zero;
        //        }


        //        simplexSolver.ComputePoints(out p1, out p2);


        //        if (normal.LengthSquared() > JMath.Epsilon * JMath.Epsilon)
        //            normal.Normalize();

        //        p1 = p1 - lambda * sweptA;
        //        p2 = p2 - lambda * sweptB;

        //        simplexSolverPool.GiveBack(simplexSolver);

        //        return true;

        //    }
        #endregion

        // see: btSubSimplexConvexCast.cpp

        /// <summary>
        /// Checks if a ray definied through it's origin and direction collides
        /// with a shape.
        /// </summary>
        /// <param name="support">The supportmap implementation representing the shape.</param>
        /// <param name="orientation">The orientation of the shape.</param>
        /// <param name="invOrientation">The inverse orientation of the shape.</param>
        /// <param name="position">The position of the shape.</param>
        /// <param name="origin">The origin of the ray.</param>
        /// <param name="direction">The direction of the ray.</param>
        /// <param name="fraction">The fraction which gives information where at the
        /// ray the collision occured. The hitPoint is calculated by: origin+friction*direction.</param>
        /// <param name="normal">The normal from the ray collision.</param>
        /// <returns>Returns true if the ray hit the shape, false otherwise.</returns>
        public static bool Raycast(ISupportMappable support, ref FPMatrix orientation, ref FPMatrix invOrientation,
                                   ref FPVector position, ref FPVector origin, ref FPVector direction, out FP fraction, out FPVector normal)
        {
            VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew();

            simplexSolver.Reset();

            normal   = FPVector.zero;
            fraction = FP.MaxValue;

            FP lambda = FP.Zero;

            FPVector r = direction;
            FPVector x = origin;
            FPVector w, p, v;

            FPVector arbitraryPoint;

            SupportMapTransformed(support, ref orientation, ref position, ref r, out arbitraryPoint);
            FPVector.Subtract(ref x, ref arbitraryPoint, out v);

            int maxIter = MaxIterations;

            FP distSq  = v.sqrMagnitude;
            FP epsilon = FP.EN6;

            FP VdotR;

            while ((distSq > epsilon) && (maxIter-- != 0))
            {
                SupportMapTransformed(support, ref orientation, ref position, ref v, out p);
                FPVector.Subtract(ref x, ref p, out w);

                FP VdotW = FPVector.Dot(ref v, ref w);

                if (VdotW > FP.Zero)
                {
                    VdotR = FPVector.Dot(ref v, ref r);

                    if (VdotR >= -FPMath.Epsilon)
                    {
                        simplexSolverPool.GiveBack(simplexSolver);
                        return(false);
                    }
                    else
                    {
                        lambda = lambda - VdotW / VdotR;
                        FPVector.Multiply(ref r, lambda, out x);
                        FPVector.Add(ref origin, ref x, out x);
                        FPVector.Subtract(ref x, ref p, out w);
                        normal = v;
                    }
                }
                if (!simplexSolver.InSimplex(w))
                {
                    simplexSolver.AddVertex(w, x, p);
                }
                if (simplexSolver.Closest(out v))
                {
                    distSq = v.sqrMagnitude;
                }
                else
                {
                    distSq = FP.Zero;
                }
            }

            #region Retrieving hitPoint

            // Giving back the fraction like this *should* work
            // but is inaccurate against large objects:
            // fraction = lambda;

            FPVector p1, p2;
            simplexSolver.ComputePoints(out p1, out p2);

            p2       = p2 - origin;
            fraction = p2.magnitude / direction.magnitude;

            #endregion

            if (normal.sqrMagnitude > FPMath.Epsilon * FPMath.Epsilon)
            {
                normal.Normalize();
            }

            simplexSolverPool.GiveBack(simplexSolver);

            return(true);
        }
Пример #26
0
        /// <summary>
        /// Checks if given point is within a shape.
        /// </summary>
        /// <param name="support">The supportmap implementation representing the shape.</param>
        /// <param name="orientation">The orientation of the shape.</param>
        /// <param name="invOrientation">The inverse orientation of the shape.</param>
        /// <param name="position">The position of the shape.</param>
        /// <param name="point">The point to check.</param>
        /// <returns>Returns true if the point is within the shape, otherwise false.</returns>
        public static bool Pointcast(ISupportMappable support, ref FPMatrix orientation, ref FPVector position, ref FPVector point)
        {
            FPVector arbitraryPoint;

            SupportMapTransformed(support, ref orientation, ref position, ref point, out arbitraryPoint);
            FPVector.Subtract(ref point, ref arbitraryPoint, out arbitraryPoint);

            FPVector r; support.SupportCenter(out r);

            FPVector.Transform(ref r, ref orientation, out r);
            FPVector.Add(ref position, ref r, out r);
            FPVector.Subtract(ref point, ref r, out r);

            FPVector x = point;
            FPVector w, p;
            FP       VdotR;

            FPVector v; FPVector.Subtract(ref x, ref arbitraryPoint, out v);
            FP       dist    = v.sqrMagnitude;
            FP       epsilon = CollideEpsilon;

            int maxIter = MaxIterations;

            VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew();

            simplexSolver.Reset();

            while ((dist > epsilon) && (maxIter-- != 0))
            {
                SupportMapTransformed(support, ref orientation, ref position, ref v, out p);
                FPVector.Subtract(ref x, ref p, out w);

                FP VdotW = FPVector.Dot(ref v, ref w);

                if (VdotW > FP.Zero)
                {
                    VdotR = FPVector.Dot(ref v, ref r);

                    if (VdotR >= -(FPMath.Epsilon * FPMath.Epsilon))
                    {
                        simplexSolverPool.GiveBack(simplexSolver); return(false);
                    }
                    else
                    {
                        simplexSolver.Reset();
                    }
                }
                if (!simplexSolver.InSimplex(w))
                {
                    simplexSolver.AddVertex(w, x, p);
                }

                if (simplexSolver.Closest(out v))
                {
                    dist = v.sqrMagnitude;
                }
                else
                {
                    dist = FP.Zero;
                }
            }

            simplexSolverPool.GiveBack(simplexSolver);
            return(true);
        }
Пример #27
0
 /// <summary>
 /// Adds a force to the center of the body. The force gets applied
 /// the next time <see cref="World.Step"/> is called. The 'impact'
 /// of the force depends on the time it is applied to a body - so
 /// the timestep influences the energy added to the body.
 /// </summary>
 /// <param name="force">The force to add next <see cref="World.Step"/>.</param>
 public void AddForce(FPVector force)
 {
     FPVector.Add(ref force, ref this.force, out this.force);
 }
Пример #28
0
 /// <summary>
 /// Adds torque to the body. The torque gets applied
 /// the next time <see cref="World.Step"/> is called. The 'impact'
 /// of the torque depends on the time it is applied to a body - so
 /// the timestep influences the energy added to the body.
 /// </summary>
 /// <param name="torque">The torque to add next <see cref="World.Step"/>.</param>
 public void AddTorque(FPVector torque)
 {
     FPVector.Add(ref torque, ref this.torque, out this.torque);
 }
Пример #29
0
        /// <summary>
        /// Checks two shapes for collisions.
        /// </summary>
        /// <param name="support1">The SupportMappable implementation of the first shape to test.</param>
        /// <param name="support2">The SupportMappable implementation of the seconds shape to test.</param>
        /// <param name="orientation1">The orientation of the first shape.</param>
        /// <param name="orientation2">The orientation of the second shape.</param>
        /// <param name="position1">The position of the first shape.</param>
        /// <param name="position2">The position of the second shape</param>
        /// <param name="point">The pointin world coordinates, where collision occur.</param>
        /// <param name="normal">The normal pointing from body2 to body1.</param>
        /// <param name="penetration">Estimated penetration depth of the collision.</param>
        /// <returns>Returns true if there is a collision, false otherwise.</returns>
        public static bool Detect(ISupportMappable support1, ISupportMappable support2, ref FPMatrix orientation1,
                                  ref FPMatrix orientation2, ref FPVector position1, ref FPVector position2,
                                  out FPVector point, out FPVector normal, out FP penetration)
        {
            // Used variables
            FPVector temp1, temp2;
            FPVector v01, v02, v0;
            FPVector v11, v12, v1;
            FPVector v21, v22, v2;
            FPVector v31, v32, v3;
            FPVector v41 = FPVector.zero, v42 = FPVector.zero, v4 = FPVector.zero;
            FPVector mn;

            // Initialization of the output
            point       = normal = FPVector.zero;
            penetration = FP.Zero;

            //JVector right = JVector.Right;

            // Get the center of shape1 in world coordinates -> v01
            support1.SupportCenter(out v01);
            FPVector.Transform(ref v01, ref orientation1, out v01);
            FPVector.Add(ref position1, ref v01, out v01);

            // Get the center of shape2 in world coordinates -> v02
            support2.SupportCenter(out v02);
            FPVector.Transform(ref v02, ref orientation2, out v02);
            FPVector.Add(ref position2, ref v02, out v02);

            // v0 is the center of the minkowski difference
            FPVector.Subtract(ref v02, ref v01, out v0);

            // Avoid case where centers overlap -- any direction is fine in this case
            if (v0.IsNearlyZero())
            {
                v0 = new FPVector(FP.EN4, 0, 0);
            }

            // v1 = support in direction of origin
            mn = v0;
            FPVector.Negate(ref v0, out normal);
            //UnityEngine.Debug.Log("normal: " + normal);

            SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v11);
            SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v12);
            FPVector.Subtract(ref v12, ref v11, out v1);

            if (FPVector.Dot(ref v1, ref normal) <= FP.Zero)
            {
                return(false);
            }

            // v2 = support perpendicular to v1,v0
            FPVector.Cross(ref v1, ref v0, out normal);

            if (normal.IsNearlyZero())
            {
                FPVector.Subtract(ref v1, ref v0, out normal);
                //UnityEngine.Debug.Log("normal: " + normal);

                normal.Normalize();

                point = v11;
                FPVector.Add(ref point, ref v12, out point);
                FPVector.Multiply(ref point, FP.Half, out point);

                FPVector.Subtract(ref v12, ref v11, out temp1);
                penetration = FPVector.Dot(ref temp1, ref normal);

                //point = v11;
                //point2 = v12;
                return(true);
            }

            FPVector.Negate(ref normal, out mn);
            SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v21);
            SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v22);
            FPVector.Subtract(ref v22, ref v21, out v2);

            if (FPVector.Dot(ref v2, ref normal) <= FP.Zero)
            {
                return(false);
            }

            // Determine whether origin is on + or - side of plane (v1,v0,v2)
            FPVector.Subtract(ref v1, ref v0, out temp1);
            FPVector.Subtract(ref v2, ref v0, out temp2);
            FPVector.Cross(ref temp1, ref temp2, out normal);

            FP dist = FPVector.Dot(ref normal, ref v0);

            // If the origin is on the - side of the plane, reverse the direction of the plane
            if (dist > FP.Zero)
            {
                FPVector.Swap(ref v1, ref v2);
                FPVector.Swap(ref v11, ref v21);
                FPVector.Swap(ref v12, ref v22);
                FPVector.Negate(ref normal, out normal);
                UnityEngine.Debug.Log("normal: " + normal);
            }


            int  phase2 = 0;
            int  phase1 = 0;
            bool hit    = false;

            // Phase One: Identify a portal
            while (true)
            {
                if (phase1 > MaximumIterations)
                {
                    return(false);
                }

                phase1++;

                // Obtain the support point in a direction perpendicular to the existing plane
                // Note: This point is guaranteed to lie off the plane
                FPVector.Negate(ref normal, out mn);
                //UnityEngine.Debug.Log("mn: " + mn);
                SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v31);
                SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v32);
                FPVector.Subtract(ref v32, ref v31, out v3);


                if (FPVector.Dot(ref v3, ref normal) <= FP.Zero)
                {
                    return(false);
                }

                // If origin is outside (v1,v0,v3), then eliminate v2 and loop
                FPVector.Cross(ref v1, ref v3, out temp1);
                if (FPVector.Dot(ref temp1, ref v0) < FP.Zero)
                {
                    v2  = v3;
                    v21 = v31;
                    v22 = v32;
                    FPVector.Subtract(ref v1, ref v0, out temp1);
                    FPVector.Subtract(ref v3, ref v0, out temp2);
                    FPVector.Cross(ref temp1, ref temp2, out normal);
                    //	UnityEngine.Debug.Log("normal: " + normal);
                    continue;
                }

                // If origin is outside (v3,v0,v2), then eliminate v1 and loop
                FPVector.Cross(ref v3, ref v2, out temp1);
                if (FPVector.Dot(ref temp1, ref v0) < FP.Zero)
                {
                    v1  = v3;
                    v11 = v31;
                    v12 = v32;
                    FPVector.Subtract(ref v3, ref v0, out temp1);
                    FPVector.Subtract(ref v2, ref v0, out temp2);
                    FPVector.Cross(ref temp1, ref temp2, out normal);
                    //UnityEngine.Debug.Log("normal: " + normal);
                    continue;
                }

                // Phase Two: Refine the portal
                // We are now inside of a wedge...
                while (true)
                {
                    phase2++;

                    /*
                     * UnityEngine.Debug.LogError(" ::Start STATE");
                     * UnityEngine.Debug.Log(temp1 + " " +  temp2);
                     * UnityEngine.Debug.Log( v01 + " " + v02 + " "+ v0);
                     * UnityEngine.Debug.Log( v11+" "+ v12 +" "+ v1);
                     * UnityEngine.Debug.Log( v21 +" "+ v22 +" "+ v2);
                     * UnityEngine.Debug.Log( v31 +" "+ v32 +" "+ v3);
                     * UnityEngine.Debug.Log( v41 +" "+ v42 +" "+ v4);
                     * UnityEngine.Debug.Log( mn);
                     *
                     * UnityEngine.Debug.LogError(" ::END STATE");
                     */
                    // Compute normal of the wedge face
                    FPVector.Subtract(ref v2, ref v1, out temp1);
                    FPVector.Subtract(ref v3, ref v1, out temp2);
                    FPVector.Cross(ref temp1, ref temp2, out normal);
                    // Beginer
                    //	UnityEngine.Debug.Log("normal: " + normal);

                    // Can this happen???  Can it be handled more cleanly?
                    if (normal.IsNearlyZero())
                    {
                        return(true);
                    }

                    normal.Normalize();
                    //UnityEngine.Debug.Log("normal: " + normal);
                    // Compute distance from origin to wedge face
                    FP d = FPVector.Dot(ref normal, ref v1);


                    // If the origin is inside the wedge, we have a hit
                    if (d >= 0 && !hit)
                    {
                        // HIT!!!
                        hit = true;
                    }

                    // Find the support point in the direction of the wedge face
                    FPVector.Negate(ref normal, out mn);
                    SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v41);
                    SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v42);
                    FPVector.Subtract(ref v42, ref v41, out v4);

                    FPVector.Subtract(ref v4, ref v3, out temp1);
                    FP delta = FPVector.Dot(ref temp1, ref normal);
                    penetration = FPVector.Dot(ref v4, ref normal);

                    // If the boundary is thin enough or the origin is outside the support plane for the newly discovered vertex, then we can terminate
                    if (delta <= CollideEpsilon || penetration <= FP.Zero || phase2 > MaximumIterations)
                    {
                        if (hit)
                        {
                            FPVector.Cross(ref v1, ref v2, out temp1);
                            FP b0 = FPVector.Dot(ref temp1, ref v3);
                            FPVector.Cross(ref v3, ref v2, out temp1);
                            FP b1 = FPVector.Dot(ref temp1, ref v0);
                            FPVector.Cross(ref v0, ref v1, out temp1);
                            FP b2 = FPVector.Dot(ref temp1, ref v3);
                            FPVector.Cross(ref v2, ref v1, out temp1);
                            FP b3 = FPVector.Dot(ref temp1, ref v0);

                            FP sum = b0 + b1 + b2 + b3;

                            if (sum <= 0)
                            {
                                b0 = 0;
                                FPVector.Cross(ref v2, ref v3, out temp1);
                                b1 = FPVector.Dot(ref temp1, ref normal);
                                FPVector.Cross(ref v3, ref v1, out temp1);
                                b2 = FPVector.Dot(ref temp1, ref normal);
                                FPVector.Cross(ref v1, ref v2, out temp1);
                                b3 = FPVector.Dot(ref temp1, ref normal);

                                sum = b1 + b2 + b3;
                            }

                            FP inv = FP.One / sum;

                            FPVector.Multiply(ref v01, b0, out point);
                            FPVector.Multiply(ref v11, b1, out temp1);
                            FPVector.Add(ref point, ref temp1, out point);
                            FPVector.Multiply(ref v21, b2, out temp1);
                            FPVector.Add(ref point, ref temp1, out point);
                            FPVector.Multiply(ref v31, b3, out temp1);
                            FPVector.Add(ref point, ref temp1, out point);

                            FPVector.Multiply(ref v02, b0, out temp2);
                            FPVector.Add(ref temp2, ref point, out point);
                            FPVector.Multiply(ref v12, b1, out temp1);
                            FPVector.Add(ref point, ref temp1, out point);
                            FPVector.Multiply(ref v22, b2, out temp1);
                            FPVector.Add(ref point, ref temp1, out point);
                            FPVector.Multiply(ref v32, b3, out temp1);
                            FPVector.Add(ref point, ref temp1, out point);

                            FPVector.Multiply(ref point, inv * FP.Half, out point);
                        }

                        // Compute the barycentric coordinates of the origin
                        return(hit);
                    }

                    //// Compute the tetrahedron dividing face (v4,v0,v1)
                    //JVector.Cross(ref v4, ref v1, out temp1);
                    //FP d1 = JVector.Dot(ref temp1, ref v0);


                    //// Compute the tetrahedron dividing face (v4,v0,v2)
                    //JVector.Cross(ref v4, ref v2, out temp1);
                    //FP d2 = JVector.Dot(ref temp1, ref v0);


                    // Compute the tetrahedron dividing face (v4,v0,v3)
                    //UnityEngine.Debug.LogError("v4:" +  v4 + " v0:" + v0);
                    FPVector.Cross(ref v4, ref v0, out temp1);
                    //UnityEngine.Debug.LogError("temp1:"+ temp1);

                    //Ender
                    //	UnityEngine.Debug.Log("normal: " + normal);
                    FP dot = FPVector.Dot(ref temp1, ref v1);

                    if (dot >= FP.Zero)
                    {
                        //	UnityEngine.Debug.Log("dot >= 0 temp1:" + temp1 + "  v2:" + v2 );
                        dot = FPVector.Dot(ref temp1, ref v2);

                        if (dot >= FP.Zero)
                        {
                            //		UnityEngine.Debug.Log("dot >= 0 v1->v4");

                            // Inside d1 & inside d2 ==> eliminate v1
                            v1  = v4;
                            v11 = v41;
                            v12 = v42;
                        }
                        else
                        {
                            //		UnityEngine.Debug.Log("dot < v3->v4");

                            // Inside d1 & outside d2 ==> eliminate v3
                            v3  = v4;
                            v31 = v41;
                            v32 = v42;
                        }
                    }
                    else
                    {
                        //	UnityEngine.Debug.Log("dot < 0 temp1:" + temp1 + "  v3:" + v3 );
                        dot = FPVector.Dot(ref temp1, ref v3);

                        if (dot >= FP.Zero)
                        {
                            //	UnityEngine.Debug.Log("dot >= 0 v2 => v4");
                            // Outside d1 & inside d3 ==> eliminate v2
                            v2  = v4;
                            v21 = v41;
                            v22 = v42;
                        }
                        else
                        {
                            //		UnityEngine.Debug.Log("dot < 0 v1 => v4");
                            // Outside d1 & outside d3 ==> eliminate v1
                            v1  = v4;
                            v11 = v41;
                            v12 = v42;
                        }
                    }
                }
            }
        }