/// <summary>
        /// Initializes the constraint and creates the guid for contact reporting
        /// </summary>
        public void Init(MyRBElementInteraction interaction, MySmallCollPointInfo[] pointInfos, int numPointInfos)
        {
            this.m_Interaction = interaction;

            m_Magnitude = 0.0f;

            numPointInfos = (numPointInfos > MaxCollisionPoints) ? MaxCollisionPoints : numPointInfos;

            m_NumCollPts = 0;
            MyContactConstraintModule mod = MyPhysics.physicsSystem.GetContactConstraintModule();
            for (int i = 0; i < numPointInfos; ++i)
            {
                this.m_PointInfo[m_NumCollPts] = mod.PopCollPointInfo();
                this.m_PointInfo[m_NumCollPts++].Init(ref pointInfos[i]);
            }

            uint guid1 = (uint) interaction.RBElement1.GUID;
            uint guid2 = (uint) interaction.RBElement2.GUID;

            if (guid1 > guid2)
            {
                uint tm = guid2;
                guid2 = guid1;
                guid1 = tm;
            }

            m_Guid = guid1 + (guid2 << 16);
        }
        protected override bool Interact(bool staticCollision)
        {
            if (!staticCollision && GetRigidBody1().IsStatic() && GetRigidBody2().IsStatic())
            {
                return(false);
            }

            MyRBSphereElement sphere1 = (MyRBSphereElement)RBElement1;
            MyRBSphereElement sphere2 = (MyRBSphereElement)RBElement2;

            Matrix matrix1 = sphere1.GetGlobalTransformation();
            Matrix matrix2 = sphere2.GetGlobalTransformation();

            Vector3 p1     = matrix1.Translation;
            Vector3 p2     = matrix2.Translation;
            Vector3 d      = p2 - p1;
            float   length = d.Length();

            float contactRadius = sphere1.Radius + sphere2.Radius;

            float eps = MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon;

            if (staticCollision)
            {
                return(length < contactRadius);
            }

            // from now on we handle dynamic collision
            float dynEps = 0;

            if (!staticCollision && length > eps)
            {
                dynEps = Vector3.Dot(GetRigidBody1().LinearVelocity - GetRigidBody2().LinearVelocity, d) / length * MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep;
                if (dynEps < 0)
                {
                    dynEps = 0;
                }
            }

            if (length > MyMwcMathConstants.EPSILON && length < contactRadius + eps + dynEps)
            {
                Vector3 n     = MyMwcUtils.Normalize(d);
                Vector3 p     = p1 + n * (sphere1.Radius + (length - contactRadius) * 0.5f);
                float   error = length - (contactRadius + 0.5f * eps);

                MySmallCollPointInfo[] collInfo = MyContactInfoCache.SCPIStackAlloc();
                collInfo[0] = new MySmallCollPointInfo(p - matrix1.Translation, p - matrix2.Translation, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, n, error, p);

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

                MyContactInfoCache.FreeStackAlloc(collInfo);

                return(true);
            }
            return(false);
        }
 public void Init(ref MySmallCollPointInfo m_Info)
 {
     this.m_Info        = m_Info;
     this.m_Denominator = 0.0f;
     this.m_AccumulatedNormalImpulse    = 0.0f;
     this.m_AccumulatedNormalImpulseAux = 0.0f;
     this.m_AccumulatedFrictionImpulse  = Vector3.Zero;
     this.m_Position         = Vector3.Zero;
     this.m_MinSeparationVel = 0.0f;
 }
 public void AddContactConstraint(MyRBElementInteraction interaction, MySmallCollPointInfo[] pointInfos, int numCollPts)
 {
     lock (m_Locker)
     {             
         if (m_FreeCc.Count == 0)
         {
             m_FreeCc.Push(new MyRBContactConstraint());
         }
         MyRBContactConstraint cc = m_FreeCc.Pop();
         cc.Init(interaction, pointInfos, numCollPts);
         m_ActiveContactConstrains.Add(cc);             
     }
 }
        protected override bool Interact(bool staticCollision)
        {
            if (!staticCollision && GetRigidBody1().IsStatic() && GetRigidBody2().IsStatic()) return false;

            MyRBSphereElement sphere1 = (MyRBSphereElement)RBElement1;
            MyRBSphereElement sphere2 = (MyRBSphereElement)RBElement2;

            Matrix matrix1 = sphere1.GetGlobalTransformation();
            Matrix matrix2 = sphere2.GetGlobalTransformation();

            Vector3 p1 = matrix1.Translation;
            Vector3 p2 = matrix2.Translation;
            Vector3 d = p2 - p1;
            float length = d.Length();

            float contactRadius = sphere1.Radius + sphere2.Radius;

            float eps = MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon;

            if (staticCollision)
            {
                return length < contactRadius;
            }
            
            // from now on we handle dynamic collision
            float dynEps = 0;
            if (!staticCollision && length > eps)
            {
                dynEps = Vector3.Dot(GetRigidBody1().LinearVelocity - GetRigidBody2().LinearVelocity, d) / length * MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep;
                if (dynEps < 0)
                    dynEps = 0;
            }

            if (length > MyMwcMathConstants.EPSILON && length < contactRadius + eps + dynEps)
            {
                Vector3 n = MyMwcUtils.Normalize(d);
                Vector3 p = p1 + n * (sphere1.Radius + (length - contactRadius) * 0.5f);
                float error = length - (contactRadius + 0.5f * eps);

                MySmallCollPointInfo[] collInfo = MyContactInfoCache.SCPIStackAlloc();
                collInfo[0] = new MySmallCollPointInfo(p - matrix1.Translation, p - matrix2.Translation, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, n, error, p);

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

                MyContactInfoCache.FreeStackAlloc(collInfo);

                return true;
            }
            return false;
        }
        protected override bool Interact(bool staticCollision)
        {
            if (RBElement1.GetElementType() != MyRBElementType.ET_SPHERE)
                SwapElements();

            Matrix matrix0 = RBElement1.GetGlobalTransformation();
            Matrix matrix1 = RBElement2.GetGlobalTransformation();

            float sphereRadius = ((MyRBSphereElement)RBElement1).Radius;

            Vector3 body0Pos = matrix0.Translation; // sphere pos
            Vector3 body1Pos = matrix1.Translation;

            Matrix tempMat1 = matrix1;

            Matrix inverseMatrix1 = Matrix.Invert(tempMat1);

            MyModel model = ((RBElement1.Flags & MyElementFlag.EF_MODEL_PREFER_LOD0) > 0 ? ((MyRBTriangleMeshElement)RBElement2).ModelLOD0 : ((MyRBTriangleMeshElement)RBElement2).Model);

            if (staticCollision)
            {
                BoundingSphere bsphere = new BoundingSphere(body0Pos, sphereRadius);
                return model.GetTrianglePruningStructure().GetIntersectionWithSphere(((MinerWars.AppCode.Game.Physics.MyPhysicsBody)RBElement2.GetRigidBody().m_UserData).Entity, ref bsphere);
            }
            else
            {
                float dt = MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep;
                float epsilon = MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon;

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

                Vector3 collNormal = Vector3.Zero;

                int optimalIterationCount = (int)(GetRigidBody1().LinearVelocity.Length() * dt / (sphereRadius * 2)) + 1;
                //PZ: after consultation with petrM 1-4 iteration will be just ok
                int maxIndex = (int)MathHelper.Min(optimalIterationCount, MAX_AVAILABLE_ITERATION);
                //float speed = GetRigidBody1().LinearVelocity.Length();

                Vector3 velocityAdd = GetRigidBody1().LinearVelocity * dt / (float)maxIndex;
                float velocityAddLength = velocityAdd.Length();

                List<MyTriangle_Vertex_Normal> triangles = MyPhysics.physicsSystem.GetContactConstraintModule().GetTriangleCache().GetFreeTriangleList(this);

                //PZ: we will try to interpolate sphere position during this tick
                //we have to have at least one iteration
                for (int index = 0; index < maxIndex; index++)
                {
                    //PZ: from starting point 
                    Vector3 interpolatedPosition = body0Pos + velocityAdd * index;

                    // Deano : get the spheres centers in triangleVertexes mesh space
                    Vector3 newSphereCen = Vector3.Transform(interpolatedPosition, inverseMatrix1);

                    //  Transform sphere from world space to object space                        
                    BoundingSphere newSphereInObjectSpace = new BoundingSphere(newSphereCen, sphereRadius + velocityAddLength + epsilon);
                    BoundingBox newAABBInObjectSpace = BoundingBox.CreateFromSphere(newSphereInObjectSpace);

                    model.GetTrianglePruningStructure().GetTrianglesIntersectingAABB(ref newAABBInObjectSpace, triangles, triangles.Capacity);

                    for (int i = 0; i < triangles.Count; i++)
                    {
                        MyTriangle_Vertex_Normal triangle = triangles[i];

                        // skip too narrow triangles causing instability
                        /*    This must be done in preprocessor!
                        if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex1).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                        {
                            continue;
                        }

                        if ((triangle.Vertexes.Vertex1 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                        {
                            continue;
                        }

                        if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                        {
                            continue;
                        }        */

                        MyPlane plane = new MyPlane(ref triangle.Vertexes);

                        Vector3? pt = MyUtils.GetSphereTriangleIntersection(ref newSphereInObjectSpace, ref plane, ref triangle.Vertexes);
                        if (pt == null)
                            continue;

                        pt = Vector3.Transform(pt.Value, matrix1);

                        Vector3 collisionN = -plane.Normal;
                        collisionN = Vector3.TransformNormal(collisionN, matrix1);

                        // skip triangle in case the normal is in wrong dir (narrow walls)  
                        Vector3 tempV = (interpolatedPosition - pt.Value);
                        if (Vector3.Dot(collisionN, tempV) >= 0.8f * tempV.Length())  // equivalent to if (Vector3.Dot(collisionN, Vector3.Normalize(tempV)) > 0.8f)
                        {
                            continue;
                        }

                        float depth = Vector3.Distance(pt.Value, interpolatedPosition) - sphereRadius;

                        if (numCollPts < MyPhysicsConfig.MaxContactPoints)
                        {
                            // since impulse get applied at the old position
                            Vector3 p2 = pt.Value; // body0Pos - sphereRadius * 1.1f * collisionN;                                    

                            collPtArray[numCollPts++] = new MySmallCollPointInfo(p2 - interpolatedPosition, p2 - body1Pos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, collisionN, depth, p2);

                            /*
                            MyDebugDraw.AddDrawTriangle(
                                Vector3.Transform(triangle.Vertexes.Vertex0, matrix1),
                                Vector3.Transform(triangle.Vertexes.Vertex1, matrix1),
                                Vector3.Transform(triangle.Vertexes.Vertex2, matrix1),
                                Color.Red);
                            */
                        }

                        collNormal += collisionN;
                    }

                    if (numCollPts > 0) // break if we catch any triangles in this iteration
                        break;

                }
                if (numCollPts > 0)
                {
                    MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collPtArray, numCollPts);
                }
                MyPhysics.physicsSystem.GetContactConstraintModule().GetTriangleCache().PushBackTriangleList(triangles);
                MyContactInfoCache.FreeStackAlloc(collPtArray);
            }
            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;
        }
 public static void FreeStackAlloc(MySmallCollPointInfo[] alloced)
 {
     lock (m_Locker)
     {
         m_cache.Push(alloced);
     }
 }
 public void Init(ref MySmallCollPointInfo m_Info)
 {
     this.m_Info = m_Info;
     this.m_Denominator = 0.0f;
     this.m_AccumulatedNormalImpulse = 0.0f;
     this.m_AccumulatedNormalImpulseAux = 0.0f;
     this.m_AccumulatedFrictionImpulse = Vector3.Zero;
     this.m_Position = Vector3.Zero;
     this.m_MinSeparationVel = 0.0f;
 }
        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);
        }
        private bool DoOverlapBoxTriangleTest(MyBox box, ref MyColDetVoxelTriangle triangle)
        {
            Matrix dirs0 = box.Orientation;

            Vector3 triEdge0;
            Vector3 triEdge1;
            Vector3 triEdge2;

            triEdge0 = MyMwcUtils.Normalize(triangle.Edge0);
            triEdge1 = MyMwcUtils.Normalize(triangle.Edge1);
            triEdge2 = MyMwcUtils.Normalize(triangle.Edge2);

            Vector3 triNormal = triangle.Plane.Normal;

            // the 15 potential separating axes (comment by Marek Rosa: note says 15 but code uses 13... I don't know why, mistake in the note??)
            const int NUM_AXES = 13;
            MyVector3Array13 axes = new MyVector3Array13();

            axes[0] = triNormal;
            axes[1] = dirs0.Right;
            axes[2] = dirs0.Up;
            axes[3] = dirs0.Backward;
            axes[4] = Vector3.Cross(axes[1], triEdge0);
            axes[5] = Vector3.Cross(axes[1], triEdge1);
            axes[6] = Vector3.Cross(axes[1], triEdge2);
            axes[7] = Vector3.Cross(axes[2], triEdge0);
            axes[8] = Vector3.Cross(axes[2], triEdge1);
            axes[9] = Vector3.Cross(axes[2], triEdge2);
            axes[10] = Vector3.Cross(axes[3], triEdge0);
            axes[11] = Vector3.Cross(axes[3], triEdge1);
            axes[12] = Vector3.Cross(axes[3], triEdge2);

            // the overlap depths along each axis
            MyFloatArray13 overlapDepths = new MyFloatArray13();

            // see if the boxes are separate along any axis, and if not keep a 
            // record of the depths along each axis
            int i;
            for (i = 0; i < NUM_AXES; ++i)
            {
                overlapDepths[i] = 1.0f;

                bool b;
                overlapDepths[i] = Disjoint(out b, axes[i], box, triangle, MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon);
                if (b) return false;
            }

            // The box overlap, find the separation depth closest to 0.
            float minDepth = float.MaxValue;
            int minAxis = -1;

            for (i = 0; i < NUM_AXES; ++i)
            {
                // If we can't normalise the axis, skip it
                float l2 = axes[i].LengthSquared();
                if (l2 < MyPhysicsConfig.Epsilon)
                    continue;

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

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

            if (minAxis == -1)
                return false;

            // Make sure the axis is facing towards the 0th box.
            // if not, invert it
            Vector3 D = box.GetCentre() - triangle.Centre;
            Vector3 N = axes[minAxis];
            float depth = overlapDepths[minAxis];

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

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

            Vector3 boxOldPos = rbo0.Position;
            Vector3 boxNewPos = rbo0.Position + rbo0.LinearVelocity * dt;
            Vector3 meshPos = rbo1.Position;

            m_CPList.Clear();

            GetBoxTriangleIntersectionPoints(m_CPList, box, triangle, MyPhysicsConfig.CollisionEpsilon);

            // adjust the depth 
            #region delta
            Vector3 delta;
            Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta);
            #endregion

            // report collisions
            int numPts = m_CPList.Count;
            MySmallCollPointInfo[] collPtArray = MyContactInfoCache.SCPIStackAlloc();
            {
                if (numPts > 0)
                {
                    if (numPts >= MyPhysicsConfig.MaxContactPoints)
                    {
                        numPts = MyPhysicsConfig.MaxContactPoints - 1;
                    }

                    // adjust positions
                    for (i = 0; i < numPts; ++i)
                    {
                        collPtArray[i] = new MySmallCollPointInfo(m_CPList[i].m_Position - boxOldPos, m_CPList[i].m_Position - meshPos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, m_CPList[i].m_Normal, m_CPList[i].m_Depth, m_CPList[i].m_Position);
                    }

                    MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collPtArray, numPts);
                    MyContactInfoCache.FreeStackAlloc(collPtArray);
                    return true;
                }
                else
                {
                    MyContactInfoCache.FreeStackAlloc(collPtArray);
                    return false;
                }
            }
          
        }
Exemple #12
0
        private bool DoOverlapBoxTriangleTest(MyBox box, ref MyColDetVoxelTriangle triangle)
        {
            Matrix dirs0 = box.Orientation;

            Vector3 triEdge0;
            Vector3 triEdge1;
            Vector3 triEdge2;

            triEdge0 = MyMwcUtils.Normalize(triangle.Edge0);
            triEdge1 = MyMwcUtils.Normalize(triangle.Edge1);
            triEdge2 = MyMwcUtils.Normalize(triangle.Edge2);

            Vector3 triNormal = triangle.Plane.Normal;

            // the 15 potential separating axes (comment by Marek Rosa: note says 15 but code uses 13... I don't know why, mistake in the note??)
            const int        NUM_AXES = 13;
            MyVector3Array13 axes     = new MyVector3Array13();

            axes[0]  = triNormal;
            axes[1]  = dirs0.Right;
            axes[2]  = dirs0.Up;
            axes[3]  = dirs0.Backward;
            axes[4]  = Vector3.Cross(axes[1], triEdge0);
            axes[5]  = Vector3.Cross(axes[1], triEdge1);
            axes[6]  = Vector3.Cross(axes[1], triEdge2);
            axes[7]  = Vector3.Cross(axes[2], triEdge0);
            axes[8]  = Vector3.Cross(axes[2], triEdge1);
            axes[9]  = Vector3.Cross(axes[2], triEdge2);
            axes[10] = Vector3.Cross(axes[3], triEdge0);
            axes[11] = Vector3.Cross(axes[3], triEdge1);
            axes[12] = Vector3.Cross(axes[3], triEdge2);

            // the overlap depths along each axis
            MyFloatArray13 overlapDepths = new MyFloatArray13();

            // see if the boxes are separate along any axis, and if not keep a
            // record of the depths along each axis
            int i;

            for (i = 0; i < NUM_AXES; ++i)
            {
                overlapDepths[i] = 1.0f;

                bool b;
                overlapDepths[i] = Disjoint(out b, axes[i], box, triangle, MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon);
                if (b)
                {
                    return(false);
                }
            }

            // The box overlap, find the separation depth closest to 0.
            float minDepth = float.MaxValue;
            int   minAxis  = -1;

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

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

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

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

            // Make sure the axis is facing towards the 0th box.
            // if not, invert it
            Vector3 D     = box.GetCentre() - triangle.Centre;
            Vector3 N     = axes[minAxis];
            float   depth = overlapDepths[minAxis];

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

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

            Vector3 boxOldPos = rbo0.Position;
            Vector3 boxNewPos = rbo0.Position + rbo0.LinearVelocity * dt;
            Vector3 meshPos   = rbo1.Position;

            m_CPList.Clear();

            GetBoxTriangleIntersectionPoints(m_CPList, box, triangle, MyPhysicsConfig.CollisionEpsilon);

            // adjust the depth
            #region delta
            Vector3 delta;
            Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta);
            #endregion

            // report collisions
            int numPts = m_CPList.Count;
            MySmallCollPointInfo[] collPtArray = MyContactInfoCache.SCPIStackAlloc();
            {
                if (numPts > 0)
                {
                    if (numPts >= MyPhysicsConfig.MaxContactPoints)
                    {
                        numPts = MyPhysicsConfig.MaxContactPoints - 1;
                    }

                    // adjust positions
                    for (i = 0; i < numPts; ++i)
                    {
                        collPtArray[i] = new MySmallCollPointInfo(m_CPList[i].m_Position - boxOldPos, m_CPList[i].m_Position - meshPos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, m_CPList[i].m_Normal, m_CPList[i].m_Depth, m_CPList[i].m_Position);
                    }

                    MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collPtArray, numPts);
                    MyContactInfoCache.FreeStackAlloc(collPtArray);
                    return(true);
                }
                else
                {
                    MyContactInfoCache.FreeStackAlloc(collPtArray);
                    return(false);
                }
            }
        }
 public MyCollisionPointStruct(float oldDepth, MySmallCollPointInfo collPointInfo)
 {
     OldDepth      = oldDepth;
     CollPointInfo = collPointInfo;
 }
        protected override bool Interact(bool staticCollision)
        {
            if (staticCollision)
            {
                //MyCommonDebugUtils.AssertDebug(false, "Sphere-voxel static interaction called! And that's wrong.");
            }
            else
            {
                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("SphereVoxelInteraction");

                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("Transformations");

                if (RBElement1.GetElementType() != MyRBElementType.ET_SPHERE)
                    SwapElements();

                Matrix matrix0 = RBElement1.GetGlobalTransformation();
                Matrix matrix1 = RBElement2.GetGlobalTransformation();

                float sphereRadius = ((MyRBSphereElement)RBElement1).Radius;

                Vector3 body0Pos = matrix0.Translation; // sphere pos
                Vector3 body1Pos = matrix1.Translation;

                float dt = MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep;
                float epsylon = MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon;

                Vector3 newBody0Pos = matrix0.Translation + GetRigidBody1().LinearVelocity * dt;

                float sphereTolR = epsylon + sphereRadius;
                float sphereTolR2 = sphereTolR * sphereTolR;

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

                Vector3 collNormal = Vector3.Zero;

                //var colDetThroughVoxels = MyConstants.SPHERE_VOXELMAP_COLDET_THROUGH_VOXELS;
                var colDetThroughVoxels = !GetRigidBody1().ReadFlag(RigidBodyFlag.RBF_COLDET_THROUGH_VOXEL_TRIANGLES);

                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

                if (colDetThroughVoxels)
                {
                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("colDetThroughVoxels");

                    BoundingSphere newSphere;
                    newSphere.Center = newBody0Pos;
                    newSphere.Radius = sphereRadius;

                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("PoolList.Get");
                    using (var voxelMapsFounded = PoolList<MyVoxelMap>.Get())
                    {
                        MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartNextBlock("GetListOfVoxelMapsWhoseBoundingSphereIntersectsSphere");

                        MyVoxelMaps.GetListOfVoxelMapsWhoseBoundingSphereIntersectsSphere(ref newSphere, voxelMapsFounded, null);

                        MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartNextBlock("foreach (MyVoxelMap voxelMap in voxelMapsFounded)");
                        foreach (MyVoxelMap voxelMap in voxelMapsFounded)
                        {
                            if (voxelMap != null)
                            {
                                //  We will iterate only voxels contained in the bounding box of new sphere, so here we get min/max corned in voxel units
                                MyMwcVector3Int minCorner = voxelMap.GetVoxelCoordinateFromMeters(new Vector3(
                                    newSphere.Center.X - newSphere.Radius,
                                    newSphere.Center.Y - newSphere.Radius,
                                    newSphere.Center.Z - newSphere.Radius));
                                MyMwcVector3Int maxCorner = voxelMap.GetVoxelCoordinateFromMeters(new Vector3(
                                    newSphere.Center.X + newSphere.Radius,
                                    newSphere.Center.Y + newSphere.Radius,
                                    newSphere.Center.Z + newSphere.Radius));
                                voxelMap.FixVoxelCoord(ref minCorner);
                                voxelMap.FixVoxelCoord(ref maxCorner);

                                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("for loop");

                                MyMwcVector3Int tempVoxelCoord;
                                for (tempVoxelCoord.X = minCorner.X; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++)
                                {
                                    for (tempVoxelCoord.Y = minCorner.Y; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++)
                                    {
                                        for (tempVoxelCoord.Z = minCorner.Z; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++)
                                        {
                                            byte voxelContent = voxelMap.GetVoxelContent(ref tempVoxelCoord);

                                            //  Ignore voxels bellow the ISO value (empty, partialy empty...)
                                            if (voxelContent < MyVoxelConstants.VOXEL_ISO_LEVEL) continue;

                                            Vector3 voxelPosition = voxelMap.GetVoxelCenterPositionAbsolute(ref tempVoxelCoord);

                                            //float voxelSize = MyVoxelMaps.GetVoxelContentAsFloat(voxelContent) * MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF;
                                            float voxelSize = MyVoxelMaps.GetVoxelContentAsFloat(voxelContent) * MyVoxelConstants.VOXEL_RADIUS;

                                            //  If distance to voxel border is less than sphere radius, we have a collision
                                            //  So now we calculate normal vector and penetration depth but on OLD sphere
                                            float newDistanceToVoxel = Vector3.Distance(voxelPosition, newSphere.Center) - voxelSize;
                                            if (newDistanceToVoxel < (epsylon + newSphere.Radius))
                                            {
                                                Vector3 collisionN = MyMwcUtils.Normalize(voxelPosition - body0Pos);

                                                if (numCollPts < MyPhysicsConfig.MaxContactPoints)
                                                {
                                                    //  Calculate penetration depth, but from old sphere (not new)
                                                    float oldDistanceToVoxel = Vector3.Distance(voxelPosition, newSphere.Center) - voxelSize;
                                                    float oldPenetrationDepth = oldDistanceToVoxel - sphereRadius;

                                                    // Vector3 pt = body0Pos + sphereRadius * collisionN;
                                                    Vector3 pt = voxelPosition - collisionN * (voxelSize - epsylon);

                                                    collPtArray[numCollPts++] = new MySmallCollPointInfo(pt - body0Pos, pt - body1Pos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, collisionN, oldPenetrationDepth, pt);
                                                }

                                                collNormal -= collisionN;
                                            }
                                        }
                                    }
                                }

                                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

                            }
                        }

                        MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
                    }

                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
                }
                else //if (colDetThroughVoxels)
                {
                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("ColDet triangles");

                    int optimalIterationCount = (int)(GetRigidBody1().LinearVelocity.Length() * dt / sphereRadius);
                    int maxIndex = (int)MathHelper.Min(MathHelper.Max(optimalIterationCount, 1), 16);

                    for (int i = 0; i < maxIndex; i++)
                    {

                        float velocityAdd = GetRigidBody1().LinearVelocity.Length() * dt / (float)maxIndex;

                        Vector3 interpolatedPosition = body0Pos + GetRigidBody1().LinearVelocity * dt * i / (float)maxIndex;

                        BoundingSphere newSphere;
                        newSphere.Center = interpolatedPosition;
                        newSphere.Radius = sphereRadius;

                        int numTriangles;

                        BoundingBox bb = BoundingBox.CreateFromSphere(newSphere);
                        MyVoxelMaps.GetPotentialTrianglesForColDet(out numTriangles, ref bb);

                        for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle)
                        {
                            MyColDetVoxelTriangle meshTriangle = MyVoxelMaps.PotentialColDetTriangles[iTriangle]; // mesh.GetTriangle(potentialTriangles[iTriangle]);


                            MyTriangle_Vertex_Normal triangle = new MyTriangle_Vertex_Normal();
                            triangle.Vertexes.Vertex0 = meshTriangle.Vertex0;
                            triangle.Vertexes.Vertex1 = meshTriangle.Vertex1;
                            triangle.Vertexes.Vertex2 = meshTriangle.Vertex2;


                            // skip too narrow triangles causing instability
                            if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex1).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                            {
                                continue;
                            }

                            if ((triangle.Vertexes.Vertex1 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                            {
                                continue;
                            }

                            if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                            {
                                continue;
                            }

                            MyPlane plane = new MyPlane(ref triangle.Vertexes);

                            Vector3? pt = MyUtils.GetSphereTriangleIntersection(ref newSphere, ref plane, ref triangle.Vertexes);
                            if (pt == null)
                                continue;


                            Vector3 collisionN = plane.Normal;

                            // skip triangle in case the normal is in wrong dir (narrow walls)  
                            Vector3 tempV = (newBody0Pos - pt.Value);
                            if (Vector3.Dot(collisionN, tempV) >= 0.8f * tempV.Length())  // equivalent to dot(collisionN, normalize(tempV)) > 0.8f, but works for zero vectors
                            {
                                continue;
                            }

                            float depth = Vector3.Distance(pt.Value, body0Pos) - sphereRadius;

                            if (numCollPts < MyPhysicsConfig.MaxContactPoints)
                            {
                                // since impulse get applied at the old position
                                Vector3 p2 = pt.Value;

                                collPtArray[numCollPts++] = new MySmallCollPointInfo(p2 - body0Pos, p2 - body1Pos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, collisionN, depth, p2);
                            }

                            collNormal += collisionN;
                        }
                    }

                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
                }

                if (numCollPts > 0)
                {
                    MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collPtArray, numCollPts);
                }
                MyContactInfoCache.FreeStackAlloc(collPtArray);

                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            return 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)
            {
                //MyCommonDebugUtils.AssertDebug(false, "Sphere-voxel static interaction called! And that's wrong.");
            }
            else
            {
                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("SphereVoxelInteraction");

                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("Transformations");

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

                Matrix matrix0 = RBElement1.GetGlobalTransformation();
                Matrix matrix1 = RBElement2.GetGlobalTransformation();

                float sphereRadius = ((MyRBSphereElement)RBElement1).Radius;

                Vector3 body0Pos = matrix0.Translation; // sphere pos
                Vector3 body1Pos = matrix1.Translation;

                float dt      = MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep;
                float epsylon = MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon;

                Vector3 newBody0Pos = matrix0.Translation + GetRigidBody1().LinearVelocity *dt;

                float sphereTolR  = epsylon + sphereRadius;
                float sphereTolR2 = sphereTolR * sphereTolR;

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

                Vector3 collNormal = Vector3.Zero;

                //var colDetThroughVoxels = MyConstants.SPHERE_VOXELMAP_COLDET_THROUGH_VOXELS;
                var colDetThroughVoxels = !GetRigidBody1().ReadFlag(RigidBodyFlag.RBF_COLDET_THROUGH_VOXEL_TRIANGLES);

                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

                if (colDetThroughVoxels)
                {
                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("colDetThroughVoxels");

                    BoundingSphere newSphere;
                    newSphere.Center = newBody0Pos;
                    newSphere.Radius = sphereRadius;

                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("PoolList.Get");
                    using (var voxelMapsFounded = PoolList <MyVoxelMap> .Get())
                    {
                        MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartNextBlock("GetListOfVoxelMapsWhoseBoundingSphereIntersectsSphere");

                        MyVoxelMaps.GetListOfVoxelMapsWhoseBoundingSphereIntersectsSphere(ref newSphere, voxelMapsFounded, null);

                        MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartNextBlock("foreach (MyVoxelMap voxelMap in voxelMapsFounded)");
                        foreach (MyVoxelMap voxelMap in voxelMapsFounded)
                        {
                            if (voxelMap != null)
                            {
                                //  We will iterate only voxels contained in the bounding box of new sphere, so here we get min/max corned in voxel units
                                MyMwcVector3Int minCorner = voxelMap.GetVoxelCoordinateFromMeters(new Vector3(
                                                                                                      newSphere.Center.X - newSphere.Radius,
                                                                                                      newSphere.Center.Y - newSphere.Radius,
                                                                                                      newSphere.Center.Z - newSphere.Radius));
                                MyMwcVector3Int maxCorner = voxelMap.GetVoxelCoordinateFromMeters(new Vector3(
                                                                                                      newSphere.Center.X + newSphere.Radius,
                                                                                                      newSphere.Center.Y + newSphere.Radius,
                                                                                                      newSphere.Center.Z + newSphere.Radius));
                                voxelMap.FixVoxelCoord(ref minCorner);
                                voxelMap.FixVoxelCoord(ref maxCorner);

                                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("for loop");

                                MyMwcVector3Int tempVoxelCoord;
                                for (tempVoxelCoord.X = minCorner.X; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++)
                                {
                                    for (tempVoxelCoord.Y = minCorner.Y; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++)
                                    {
                                        for (tempVoxelCoord.Z = minCorner.Z; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++)
                                        {
                                            byte voxelContent = voxelMap.GetVoxelContent(ref tempVoxelCoord);

                                            //  Ignore voxels bellow the ISO value (empty, partialy empty...)
                                            if (voxelContent < MyVoxelConstants.VOXEL_ISO_LEVEL)
                                            {
                                                continue;
                                            }

                                            Vector3 voxelPosition = voxelMap.GetVoxelCenterPositionAbsolute(ref tempVoxelCoord);

                                            //float voxelSize = MyVoxelMaps.GetVoxelContentAsFloat(voxelContent) * MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF;
                                            float voxelSize = MyVoxelMaps.GetVoxelContentAsFloat(voxelContent) * MyVoxelConstants.VOXEL_RADIUS;

                                            //  If distance to voxel border is less than sphere radius, we have a collision
                                            //  So now we calculate normal vector and penetration depth but on OLD sphere
                                            float newDistanceToVoxel = Vector3.Distance(voxelPosition, newSphere.Center) - voxelSize;
                                            if (newDistanceToVoxel < (epsylon + newSphere.Radius))
                                            {
                                                Vector3 collisionN = MyMwcUtils.Normalize(voxelPosition - body0Pos);

                                                if (numCollPts < MyPhysicsConfig.MaxContactPoints)
                                                {
                                                    //  Calculate penetration depth, but from old sphere (not new)
                                                    float oldDistanceToVoxel  = Vector3.Distance(voxelPosition, newSphere.Center) - voxelSize;
                                                    float oldPenetrationDepth = oldDistanceToVoxel - sphereRadius;

                                                    // Vector3 pt = body0Pos + sphereRadius * collisionN;
                                                    Vector3 pt = voxelPosition - collisionN * (voxelSize - epsylon);

                                                    collPtArray[numCollPts++] = new MySmallCollPointInfo(pt - body0Pos, pt - body1Pos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, collisionN, oldPenetrationDepth, pt);
                                                }

                                                collNormal -= collisionN;
                                            }
                                        }
                                    }
                                }

                                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
                            }
                        }

                        MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
                    }

                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
                }
                else //if (colDetThroughVoxels)
                {
                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("ColDet triangles");

                    int optimalIterationCount = (int)(GetRigidBody1().LinearVelocity.Length() * dt / sphereRadius);
                    int maxIndex = (int)MathHelper.Min(MathHelper.Max(optimalIterationCount, 1), 16);

                    for (int i = 0; i < maxIndex; i++)
                    {
                        float velocityAdd = GetRigidBody1().LinearVelocity.Length() * dt / (float)maxIndex;

                        Vector3 interpolatedPosition = body0Pos + GetRigidBody1().LinearVelocity *dt *i / (float)maxIndex;

                        BoundingSphere newSphere;
                        newSphere.Center = interpolatedPosition;
                        newSphere.Radius = sphereRadius;

                        int numTriangles;

                        BoundingBox bb = BoundingBox.CreateFromSphere(newSphere);
                        MyVoxelMaps.GetPotentialTrianglesForColDet(out numTriangles, ref bb);

                        for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle)
                        {
                            MyColDetVoxelTriangle meshTriangle = MyVoxelMaps.PotentialColDetTriangles[iTriangle]; // mesh.GetTriangle(potentialTriangles[iTriangle]);


                            MyTriangle_Vertex_Normal triangle = new MyTriangle_Vertex_Normal();
                            triangle.Vertexes.Vertex0 = meshTriangle.Vertex0;
                            triangle.Vertexes.Vertex1 = meshTriangle.Vertex1;
                            triangle.Vertexes.Vertex2 = meshTriangle.Vertex2;


                            // skip too narrow triangles causing instability
                            if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex1).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                            {
                                continue;
                            }

                            if ((triangle.Vertexes.Vertex1 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                            {
                                continue;
                            }

                            if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                            {
                                continue;
                            }

                            MyPlane plane = new MyPlane(ref triangle.Vertexes);

                            Vector3?pt = MyUtils.GetSphereTriangleIntersection(ref newSphere, ref plane, ref triangle.Vertexes);
                            if (pt == null)
                            {
                                continue;
                            }


                            Vector3 collisionN = plane.Normal;

                            // skip triangle in case the normal is in wrong dir (narrow walls)
                            Vector3 tempV = (newBody0Pos - pt.Value);
                            if (Vector3.Dot(collisionN, tempV) >= 0.8f * tempV.Length())  // equivalent to dot(collisionN, normalize(tempV)) > 0.8f, but works for zero vectors
                            {
                                continue;
                            }

                            float depth = Vector3.Distance(pt.Value, body0Pos) - sphereRadius;

                            if (numCollPts < MyPhysicsConfig.MaxContactPoints)
                            {
                                // since impulse get applied at the old position
                                Vector3 p2 = pt.Value;

                                collPtArray[numCollPts++] = new MySmallCollPointInfo(p2 - body0Pos, p2 - body1Pos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, collisionN, depth, p2);
                            }

                            collNormal += collisionN;
                        }
                    }

                    MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
                }

                if (numCollPts > 0)
                {
                    MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collPtArray, numCollPts);
                }
                MyContactInfoCache.FreeStackAlloc(collPtArray);

                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            return(false);
        }
Exemple #17
0
        protected override bool Interact(bool staticCollision)
        {
            if (RBElement1.GetElementType() != MyRBElementType.ET_SPHERE)
            {
                SwapElements();
            }

            Matrix matrix0 = RBElement1.GetGlobalTransformation();
            Matrix matrix1 = RBElement2.GetGlobalTransformation();

            float sphereRadius = ((MyRBSphereElement)RBElement1).Radius;

            Vector3 body0Pos = matrix0.Translation; // sphere pos
            Vector3 body1Pos = matrix1.Translation;

            Matrix tempMat1 = matrix1;

            Matrix inverseMatrix1 = Matrix.Invert(tempMat1);

            MyModel model = ((RBElement1.Flags & MyElementFlag.EF_MODEL_PREFER_LOD0) > 0 ? ((MyRBTriangleMeshElement)RBElement2).ModelLOD0 : ((MyRBTriangleMeshElement)RBElement2).Model);

            if (staticCollision)
            {
                BoundingSphere bsphere = new BoundingSphere(body0Pos, sphereRadius);
                return(model.GetTrianglePruningStructure().GetIntersectionWithSphere(((MinerWars.AppCode.Game.Physics.MyPhysicsBody)RBElement2.GetRigidBody().m_UserData).Entity, ref bsphere));
            }
            else
            {
                float dt      = MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep;
                float epsilon = MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon;

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

                Vector3 collNormal = Vector3.Zero;

                int optimalIterationCount = (int)(GetRigidBody1().LinearVelocity.Length() * dt / (sphereRadius * 2)) + 1;
                //PZ: after consultation with petrM 1-4 iteration will be just ok
                int maxIndex = (int)MathHelper.Min(optimalIterationCount, MAX_AVAILABLE_ITERATION);
                //float speed = GetRigidBody1().LinearVelocity.Length();

                Vector3 velocityAdd       = GetRigidBody1().LinearVelocity *dt / (float)maxIndex;
                float   velocityAddLength = velocityAdd.Length();

                List <MyTriangle_Vertex_Normal> triangles = MyPhysics.physicsSystem.GetContactConstraintModule().GetTriangleCache().GetFreeTriangleList(this);

                //PZ: we will try to interpolate sphere position during this tick
                //we have to have at least one iteration
                for (int index = 0; index < maxIndex; index++)
                {
                    //PZ: from starting point
                    Vector3 interpolatedPosition = body0Pos + velocityAdd * index;

                    // Deano : get the spheres centers in triangleVertexes mesh space
                    Vector3 newSphereCen = Vector3.Transform(interpolatedPosition, inverseMatrix1);

                    //  Transform sphere from world space to object space
                    BoundingSphere newSphereInObjectSpace = new BoundingSphere(newSphereCen, sphereRadius + velocityAddLength + epsilon);
                    BoundingBox    newAABBInObjectSpace   = BoundingBox.CreateFromSphere(newSphereInObjectSpace);

                    model.GetTrianglePruningStructure().GetTrianglesIntersectingAABB(ref newAABBInObjectSpace, triangles, triangles.Capacity);

                    for (int i = 0; i < triangles.Count; i++)
                    {
                        MyTriangle_Vertex_Normal triangle = triangles[i];

                        // skip too narrow triangles causing instability

                        /*    This must be done in preprocessor!
                         * if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex1).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                         * {
                         *  continue;
                         * }
                         *
                         * if ((triangle.Vertexes.Vertex1 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                         * {
                         *  continue;
                         * }
                         *
                         * if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon)
                         * {
                         *  continue;
                         * }        */

                        MyPlane plane = new MyPlane(ref triangle.Vertexes);

                        Vector3?pt = MyUtils.GetSphereTriangleIntersection(ref newSphereInObjectSpace, ref plane, ref triangle.Vertexes);
                        if (pt == null)
                        {
                            continue;
                        }

                        pt = Vector3.Transform(pt.Value, matrix1);

                        Vector3 collisionN = -plane.Normal;
                        collisionN = Vector3.TransformNormal(collisionN, matrix1);

                        // skip triangle in case the normal is in wrong dir (narrow walls)
                        Vector3 tempV = (interpolatedPosition - pt.Value);
                        if (Vector3.Dot(collisionN, tempV) >= 0.8f * tempV.Length())  // equivalent to if (Vector3.Dot(collisionN, Vector3.Normalize(tempV)) > 0.8f)
                        {
                            continue;
                        }

                        float depth = Vector3.Distance(pt.Value, interpolatedPosition) - sphereRadius;

                        if (numCollPts < MyPhysicsConfig.MaxContactPoints)
                        {
                            // since impulse get applied at the old position
                            Vector3 p2 = pt.Value; // body0Pos - sphereRadius * 1.1f * collisionN;

                            collPtArray[numCollPts++] = new MySmallCollPointInfo(p2 - interpolatedPosition, p2 - body1Pos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, collisionN, depth, p2);

                            /*
                             * MyDebugDraw.AddDrawTriangle(
                             *  Vector3.Transform(triangle.Vertexes.Vertex0, matrix1),
                             *  Vector3.Transform(triangle.Vertexes.Vertex1, matrix1),
                             *  Vector3.Transform(triangle.Vertexes.Vertex2, matrix1),
                             *  Color.Red);
                             */
                        }

                        collNormal += collisionN;
                    }

                    if (numCollPts > 0) // break if we catch any triangles in this iteration
                    {
                        break;
                    }
                }
                if (numCollPts > 0)
                {
                    MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collPtArray, numCollPts);
                }
                MyPhysics.physicsSystem.GetContactConstraintModule().GetTriangleCache().PushBackTriangleList(triangles);
                MyContactInfoCache.FreeStackAlloc(collPtArray);
            }
            return(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;
        }