Esempio n. 1
0
        public override void DoWork()
        {
            MyRBBoxElement     rbBoxElement = (MyRBBoxElement)m_RBElement;
            MyBoxSensorElement seBoxElement = (MyBoxSensorElement)m_SensorElement;

            Matrix rbBoxMatrix = rbBoxElement.GetGlobalTransformation();
            Matrix seBoxMatrix = seBoxElement.GetGlobalTransformation();

            BoundingBox rbBB = new BoundingBox(-rbBoxElement.Size / 2f, rbBoxElement.Size / 2f);
            BoundingBox seBB = new BoundingBox(-seBoxElement.Extent, seBoxElement.Extent);

            MyOrientedBoundingBox rbBoxOriented = MyOrientedBoundingBox.CreateFromBoundingBox(rbBB).Transform(rbBoxMatrix);
            MyOrientedBoundingBox seBoxOriented = MyOrientedBoundingBox.CreateFromBoundingBox(seBB).Transform(seBoxMatrix);

            m_IsInside = rbBoxOriented.Intersects(ref seBoxOriented);
        }
        public override void DoWork()
        {
            MyRBBoxElement        box    = (MyRBBoxElement)m_RBElement;
            MySphereSensorElement sphere = (MySphereSensorElement)m_SensorElement;

            Matrix  boxMatrix    = box.GetGlobalTransformation();
            Vector3 sphereCenter = sphere.GetGlobalTransformation().Translation;

            Matrix invBoxMatrix = Matrix.Invert(boxMatrix);

            Vector3 boxLocalsphereCenter = Vector3.Transform(sphereCenter, invBoxMatrix);

            bool    penetration = false;
            Vector3 normal      = new Vector3();
            Vector3 closestPos  = new Vector3();
            uint    customData  = 0;

            box.GetClosestPoint(boxLocalsphereCenter, ref closestPos, ref normal, ref penetration, ref customData);

            if (penetration)
            {
                m_IsInside = true;
                return;
            }

            closestPos = Vector3.Transform(closestPos, boxMatrix);

            float vLength = (sphereCenter - closestPos).LengthSquared();

            if (vLength <= sphere.Radius * sphere.Radius)
            {
                if (vLength <= (sphere.Radius / 2f) * (sphere.Radius / 2f) || sphere.SpecialDetectingAngle == null)
                {
                    m_IsInside = true;
                }
                else if (sphere.SpecialDetectingAngle != null)
                {
                    Vector3 normalizeDirectionToRBElement = Vector3.Normalize(boxMatrix.Translation - sphereCenter);
                    float   cosAngle = Vector3.Dot(normalizeDirectionToRBElement, sphere.GetGlobalTransformation().Forward);
                    m_IsInside = Math.Abs(cosAngle) >= sphere.SpecialDetectingAngle.Value;
                }
            }
            else
            {
                m_IsInside = false;
            }
        }
        protected override bool Interact(bool staticCollision)
        {
            if (!staticCollision && GetRigidBody1().IsStatic() && GetRigidBody2().IsStatic())
            {
                return(false);
            }

            MyRBBoxElement    box    = null;
            MyRBSphereElement sphere = null;

            if (RBElement1.GetElementType() == MyRBElementType.ET_BOX)
            {
                SwapElements();
            }

            box    = (MyRBBoxElement)RBElement2;
            sphere = (MyRBSphereElement)RBElement1;

            Matrix  boxMatrix    = box.GetGlobalTransformation();
            Vector3 sphereCenter = sphere.GetGlobalTransformation().Translation;

            Matrix invBoxMatrix = Matrix.Invert(boxMatrix);

            Vector3 boxLocalsphereCenter = Vector3.Transform(sphereCenter, invBoxMatrix);

            bool    penetration = false;
            Vector3 normal      = new Vector3();
            Vector3 closestPos  = new Vector3();
            uint    customData  = 0;

            box.GetClosestPoint(boxLocalsphereCenter, ref closestPos, ref normal, ref penetration, ref customData);

            closestPos = Vector3.Transform(closestPos, boxMatrix);

            normal = -Vector3.TransformNormal(normal, boxMatrix);
            normal = MyMwcUtils.Normalize(normal);

            float vLength = (sphereCenter - closestPos).Length();

            if (staticCollision)
            {
                return(vLength > 0 && vLength < sphere.Radius);
            }
            else
            {
                float eps = MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon;
                float dt  = MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep;

                Vector3 pointVelocity1 = new Vector3();
                Vector3 pointVelocity2 = new Vector3();

                GetRigidBody1().GetGlobalPointVelocity(ref closestPos, out pointVelocity1);
                GetRigidBody2().GetGlobalPointVelocity(ref closestPos, out pointVelocity2);

                float dynEps = 0;
                if (vLength >= eps)
                {
                    float dot = Vector3.Dot(pointVelocity1 - pointVelocity2, normal) * dt;
                    if (dot >= 0)
                    {
                        dynEps = dot;
                    }
                }

                float radius = sphere.Radius;

                //Second part of condition commented due to 5968: Bug B - rocket passing through prefab
                //Does not seem to have any reason to be there
                if (vLength > 0 /*&& vLength < (radius + eps + dynEps)*/)
                {
                    float error = vLength - (radius + 0.5f * eps);
                    //error = System.Math.Min(error, eps);

                    MySmallCollPointInfo[] collInfo = MyContactInfoCache.SCPIStackAlloc();

                    collInfo[0] = new MySmallCollPointInfo(closestPos - sphereCenter, closestPos - boxMatrix.Translation, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, normal, error, closestPos);

                    MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collInfo, 1);

                    MyContactInfoCache.FreeStackAlloc(collInfo);
                }
            }
            return(false);
        }
        protected override bool Interact(bool staticCollision)
        {
            if (!staticCollision)
            {
                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("BoxBoxInteraction");
            }

            try
            {
                MyRBBoxElement rbbox0 = (MyRBBoxElement)RBElement1;
                MyRBBoxElement rbbox1 = (MyRBBoxElement)RBElement2;

                MyBox box0 = m_TempBox1;
                MyBox box1 = m_TempBox2;

                Matrix matrix0 = rbbox0.GetGlobalTransformation();
                Matrix matrix1 = rbbox1.GetGlobalTransformation();

                box0.Transform.Orientation             = matrix0;
                box0.Transform.Orientation.Translation = Vector3.Zero;
                box0.Transform.Position = matrix0.Translation - Vector3.TransformNormal(rbbox0.Size * 0.5f, matrix0);

                box1.Transform.Orientation             = matrix1;
                box1.Transform.Orientation.Translation = Vector3.Zero;
                box1.Transform.Position = matrix1.Translation - Vector3.TransformNormal(rbbox1.Size * 0.5f, matrix1);

                box0.SideLengths = rbbox0.Size;
                box1.SideLengths = rbbox1.Size;

                // see if the boxes are separate along any axis, and if not keep a
                // record of the depths along each axis
                for (int i = 0; i < 15; ++i)
                {
                    switch (i)
                    {
                    case 0: seperatingAxes[0] = box0.Orientation.Right; break;

                    case 1: seperatingAxes[1] = box0.Orientation.Up; break;

                    case 2: seperatingAxes[2] = box0.Orientation.Backward; break;

                    case 3: seperatingAxes[3] = box1.Orientation.Right; break;

                    case 4: seperatingAxes[4] = box1.Orientation.Up; break;

                    case 5: seperatingAxes[5] = box1.Orientation.Backward; break;

                    case 6: Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[3], out seperatingAxes[6]); break;

                    case 7: Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[4], out seperatingAxes[7]); break;

                    case 8: Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[5], out seperatingAxes[8]); break;

                    case 9: Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[3], out seperatingAxes[9]); break;

                    case 10: Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[4], out seperatingAxes[10]); break;

                    case 11: Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[5], out seperatingAxes[11]); break;

                    case 12: Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[3], out seperatingAxes[12]); break;

                    case 13: Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[4], out seperatingAxes[13]); break;

                    case 14: Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[5], out seperatingAxes[14]); break;
                    }

                    // If we can't normalise the axis, skip it
                    if (seperatingAxes[i].LengthSquared() < MyPhysicsConfig.CollisionEpsilon)
                    {
                        continue;
                    }

                    overlapDepth[i] = float.MaxValue;

                    if (Disjoint(out overlapDepth[i], ref seperatingAxes[i], box0, box1, MyPhysicsConfig.CollisionEpsilon))
                    {
                        return(false);
                    }
                }

                if (staticCollision)
                {
                    return(true);  // Static collision: we're done.
                }

                // Dynamic collision.
                // The boxes overlap, find the seperation depth closest to 0.
                float minDepth = float.MaxValue;
                int   minAxis  = -1;

                for (int i = 0; i < 15; ++i)
                {
                    // If we can't normalise the axis, skip it
                    float l2 = seperatingAxes[i].LengthSquared();
                    if (l2 < MyPhysicsConfig.CollisionEpsilon)
                    {
                        continue;
                    }

                    // Normalise the separation axis and depth
                    float invl = 1.0f / (float)System.Math.Sqrt(l2);
                    seperatingAxes[i] *= invl;
                    overlapDepth[i]   *= invl;

                    // If this axis is the minmum, select it
                    if (overlapDepth[i] < minDepth)
                    {
                        minDepth = overlapDepth[i];
                        minAxis  = i;
                    }
                }

                if (minAxis == -1)
                {
                    return(false);
                }

                // Make sure the axis is facing towards the 0th box.
                // if not, invert it
                Vector3 D     = box1.GetCentre() - box0.GetCentre();
                Vector3 N     = seperatingAxes[minAxis];
                float   depth = overlapDepth[minAxis];

                if (Vector3.Dot(D, N) < 0.0f)
                {
                    N *= -1.0f;
                }

                float minA = MathHelper.Min(box0.SideLengths.X, MathHelper.Min(box0.SideLengths.Y, box0.SideLengths.Z));
                float minB = MathHelper.Min(box1.SideLengths.X, MathHelper.Min(box1.SideLengths.Y, box1.SideLengths.Z));

                float combinationDist = 0.05f * MathHelper.Min(minA, minB);

                // the contact points
                contactPts.Clear();

                int numPts = contactPts.Count;
                GetBoxBoxIntersectionPoints(contactPts, box0, box1, combinationDist, MyPhysicsConfig.CollisionEpsilon);
                numPts = contactPts.Count;

                MyRigidBody rbo0 = GetRigidBody1();
                MyRigidBody rbo1 = GetRigidBody2();
                float       dt   = MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep;

                Vector3 body0OldPos = rbo0.Position;
                Vector3 body1OldPos = rbo1.Position;
                Vector3 body0NewPos = (rbo0.Position + rbo0.LinearVelocity * dt);
                Vector3 body1NewPos = (rbo1.Position + rbo1.LinearVelocity * dt);

                #region REFERENCE: Vector3 bodyDelta = body0NewPos - body0OldPos - body1NewPos + body1OldPos;
                Vector3 bodyDelta;
                Vector3.Subtract(ref body0NewPos, ref body0OldPos, out bodyDelta);
                Vector3.Subtract(ref bodyDelta, ref body1NewPos, out bodyDelta);
                Vector3.Add(ref bodyDelta, ref body1OldPos, out bodyDelta);
                #endregion

                #region REFERENCE: float bodyDeltaLen = Vector3.Dot(bodyDelta,N);
                float bodyDeltaLen;
                Vector3.Dot(ref bodyDelta, ref N, out bodyDeltaLen);
                #endregion

                float oldDepth = depth + bodyDeltaLen;

                MySmallCollPointInfo[] collPtArray = MyContactInfoCache.SCPIStackAlloc();
                {
                    int numCollPts = 0;

                    Vector3 SATPoint;

                    switch (minAxis)
                    {
                    // Box0 face, Box1 corner collision
                    case 0:
                    case 1:
                    case 2:
                    {
                        // Get the lowest point on the box1 along box1 normal
                        GetSupportPoint(out SATPoint, box1, -N);
                        break;
                    }

                    // We have a Box2 corner/Box1 face collision
                    case 3:
                    case 4:
                    case 5:
                    {
                        // Find with vertex on the triangleVertexes collided
                        GetSupportPoint(out SATPoint, box0, N);
                        break;
                    }

                    // We have an edge/edge collision
                    case 6:
                    case 7:
                    case 8:
                    case 9:
                    case 10:
                    case 11:
                    case 12:
                    case 13:
                    case 14:
                    {
                        {
                            // Retrieve which edges collided.
                            int i  = minAxis - 6;
                            int ia = i / 3;
                            int ib = i - ia * 3;
                            // find two P0, P1 point on both edges.
                            Vector3 P0, P1;
                            GetSupportPoint(out P0, box0, N);
                            GetSupportPoint(out P1, box1, -N);
                            // Find the edge intersection.
                            // plane along N and F, and passing through PB
                            Vector3 box0Orient, box1Orient;
                            MyPhysicsUtils.MyPhysicsUnsafe.Get(ref box0.Transform.Orientation, ia, out box0Orient);
                            MyPhysicsUtils.MyPhysicsUnsafe.Get(ref box1.Transform.Orientation, ib, out box1Orient);

                            #region REFERENCE: Vector3 planeNormal = Vector3.Cross(N, box1Orient[ib]);
                            Vector3 planeNormal;
                            Vector3.Cross(ref N, ref box1Orient, out planeNormal);
                            #endregion

                            #region REFERENCE: float planeD = Vector3.Dot(planeNormal, P1);
                            float planeD;
                            Vector3.Dot(ref planeNormal, ref P1, out planeD);
                            #endregion

                            // find the intersection t, where Pintersection = P0 + t*box edge dir
                            #region REFERENCE: float div = Vector3.Dot(box0Orient, planeNormal);
                            float div;
                            Vector3.Dot(ref box0Orient, ref planeNormal, out div);
                            #endregion

                            // plane and ray colinear, skip the intersection.
                            if (System.Math.Abs(div) < MyPhysicsConfig.CollisionEpsilon)
                            {
                                return(false);
                            }

                            float t = (planeD - Vector3.Dot(P0, planeNormal)) / div;

                            // point on edge of box0
                            #region REFERENCE: P0 += box0Orient * t;
                            P0 = Vector3.Add(Vector3.Multiply(box0Orient, t), P0);
                            #endregion

                            #region REFERENCE: SATPoint = (P0 + (0.5f * depth) * N);
                            Vector3.Multiply(ref N, 0.5f * depth, out SATPoint);
                            Vector3.Add(ref SATPoint, ref P0, out SATPoint);
                            #endregion
                        }
                        break;
                    }

                    default:
                    {
                        SATPoint = Vector3.Zero;
                        Debug.Assert(false);
                        break;
                    }
                    }

                    // distribute the depth according to the distance to the SAT point
                    if (numPts > 0)
                    {
                        float minDist = float.MaxValue;
                        float maxDist = float.MinValue;
                        for (int i = 0; i < numPts; ++i)
                        {
                            float dist = MyPhysicsUtils.PointPointDistance(contactPts[i].Pos, SATPoint);
                            if (dist < minDist)
                            {
                                minDist = dist;
                            }
                            if (dist > maxDist)
                            {
                                maxDist = dist;
                            }
                        }

                        // got some intersection points
                        for (int i = 0; i < numPts; ++i)
                        {
                            float minDepthScale = 0.0f;
                            float dist          = MyPhysicsUtils.PointPointDistance(contactPts[i].Pos, SATPoint);

                            float safeDivisionDist = (maxDist - minDist);
                            if ((maxDist - minDist) == 0.0f)
                            {
                                safeDivisionDist = MyPhysicsConfig.CollisionEpsilon;
                            }
                            float depthScale = (dist - minDist) / safeDivisionDist;

                            depth = (1.0f - depthScale) * oldDepth + minDepthScale * depthScale * oldDepth;

                            if (numCollPts < MyPhysicsConfig.MaxContactPoints)
                            {
                                collPtArray[numCollPts++] = new MySmallCollPointInfo(contactPts[i].Pos - body0OldPos, contactPts[i].Pos - body1OldPos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, N, depth, contactPts[i].Pos);
                            }
                        }
                    }
                    else
                    {
                        #region REFERENCE: collPts.Add(new CollPointInfo(SATPoint - body0NewPos, SATPoint - body1NewPos, oldDepth));
                        //collPts.Add(new CollPointInfo(SATPoint - body0NewPos, SATPoint - body1NewPos, oldDepth));
                        Vector3 cp0;
                        Vector3.Subtract(ref SATPoint, ref body0NewPos, out cp0);

                        Vector3 cp1;
                        Vector3.Subtract(ref SATPoint, ref body1NewPos, out cp1);

                        if (numCollPts < MyPhysicsConfig.MaxContactPoints)
                        {
                            collPtArray[numCollPts++] = new MySmallCollPointInfo(cp0, cp1, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, N, oldDepth, SATPoint);
                        }
                        #endregion
                    }

                    // report Collisions
                    MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collPtArray, numCollPts);
                }
                MyContactInfoCache.FreeStackAlloc(collPtArray);
            }
            catch
            {
                throw;
            }
            finally
            {
                if (!staticCollision)
                {
                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
                }
            }
            return(false);
        }