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) { //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) { try { if (!staticCollision) { TestsCount++; MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("BoxTriangleIntersection"); } if (RBElement1.GetElementType() != MyRBElementType.ET_BOX) { SwapElements(); } var boxElement = (MyRBBoxElement)RBElement1; var triangleMeshElem = (MyRBTriangleMeshElement)RBElement2; MyModel model = ((boxElement.Flags & MyElementFlag.EF_MODEL_PREFER_LOD0) > 0 ? triangleMeshElem.ModelLOD0 : triangleMeshElem.Model); Matrix boxMatrix = boxElement.GetGlobalTransformation(); Matrix triangleMeshMatrix = triangleMeshElem.GetGlobalTransformation(); Matrix newMatrix = boxMatrix; if (!staticCollision) { // MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep newMatrix.Translation = newMatrix.Translation + boxElement.GetRigidBody().LinearVelocity *MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep; } MyBox oldBox = m_tempBox1; MyBox newBox = m_tempBox2; oldBox.Transform.Orientation = boxMatrix; oldBox.Transform.Orientation.Translation = Vector3.Zero; oldBox.Transform.Position = boxMatrix.Translation - Vector3.TransformNormal(boxElement.Size * 0.5f, boxMatrix); newBox.Transform.Orientation = newMatrix; newBox.Transform.Orientation.Translation = Vector3.Zero; newBox.Transform.Position = newMatrix.Translation - Vector3.TransformNormal(boxElement.Size * 0.5f, newMatrix); oldBox.SideLengths = boxElement.Size; newBox.SideLengths = boxElement.Size; float boxRadius = newBox.GetBoundingRadiusAroundCentre(); #region REFERENCE: Vector3 boxCentre = newBox.GetCentre(); Vector3 boxCentre; newBox.GetCentre(out boxCentre); // Deano need to trasnform the box center into mesh space Matrix invTransformMatrix = Matrix.Invert(triangleMeshMatrix); Vector3.Transform(ref boxCentre, ref invTransformMatrix, out boxCentre); #endregion BoundingBox bb = boxElement.GetWorldSpaceAABB(); if (staticCollision) { Vector3 bbMin = Vector3.Transform(bb.Min, invTransformMatrix); Vector3 bbMax = Vector3.Transform(bb.Max, invTransformMatrix); BoundingSphere bs = new BoundingSphere((bbMax + bbMin) / 2, Vector3.Distance(bbMin, bbMax)); List <MyTriangle_Vertex_Normal> triangles = MyPhysics.physicsSystem.GetContactConstraintModule().GetTriangleCache().GetFreeTriangleList(this); model.GetTrianglePruningStructure().GetTrianglesIntersectingSphere(ref bs, triangles, triangles.Capacity); for (int iTriangle = 0; iTriangle < triangles.Count; iTriangle++) { MyTriangle_Vertex_Normal triangle = triangles[iTriangle]; MyPlane plane = new MyPlane(ref triangle.Vertexes); // quick early test is done in mesh space float dist = MyUtils.GetDistanceFromPointToPlane(ref boxCentre, ref plane); if (dist > boxRadius || dist < -boxRadius) { continue; } Vector3 oldPos = boxMatrix.Translation; Vector3 newPos = newMatrix.Translation; float collisionEpsilon = 0;//pz to test not sure about value if (DoOverlapBoxTriangleStaticTest( oldBox, newBox, triangle, plane, collisionEpsilon, ref triangleMeshMatrix, ref oldPos, ref newPos)) { return(true); } } return(false); } else { bb.Min += boxElement.GetRigidBody().LinearVelocity *MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep; bb.Max += boxElement.GetRigidBody().LinearVelocity *MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep; var boxCenter = bb.GetCenter(); // aabox is done in mesh space and handles the mesh transform correctly //int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); //boxElement.GetRigidBody().Position = Vector3.Zero; //triangleMeshElem.GetRigidBody().Position = Vector3.Zero; //BoundingSphere bs = new BoundingSphere((bbMax + bbMin) / 2, Vector3.Distance(bbMin, bbMax)); var halfSize = bb.Size() / 2; BoundingBox bb2 = new BoundingBox(boxCentre - halfSize, boxCentre + halfSize); List <MyTriangle_Vertex_Normal> triangles = MyPhysics.physicsSystem.GetContactConstraintModule().GetTriangleCache().GetFreeTriangleList(this); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("PruningStructure"); model.GetTrianglePruningStructure().GetTrianglesIntersectingAABB(ref bb2, triangles, triangles.Capacity); //model.GetTrianglePruningStructure().GetTrianglesIntersectingSphere(ref bs, triangles, triangles.Capacity); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().ProfileCustomValue("Tests count ", TestsCount); MySmallCollPointInfo[] collPtArray = MyContactInfoCache.SCPIStackAlloc(); int refPointer = 0; m_collPoints.Clear(); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("Triangles"); for (int iTriangle = 0; iTriangle < triangles.Count; iTriangle++) { MyTriangle_Vertex_Normal triangle = triangles[iTriangle]; //IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]); MyPlane plane = new MyPlane(ref triangle.Vertexes); // quick early test is done in mesh space //float dist = meshTriangle.Plane.DotCoordinate(boxCentre); float dist = MyUtils.GetDistanceFromPointToPlane(ref boxCentre, ref plane); if (dist > boxRadius || dist < -boxRadius) { continue; } Vector3 oldPos = boxMatrix.Translation; Vector3 newPos = newMatrix.Translation; DoOverlapBoxTriangleTest( oldBox, newBox, triangle, plane, MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon, ref triangleMeshMatrix, ref oldPos, ref newPos, m_collPoints); } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); TrianglesTested += triangles.Count; MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().ProfileCustomValue("Triangles tested ", TrianglesTested); m_collPoints.Sort(m_colPointComparer); refPointer = 0; foreach (MyCollisionPointStruct collPoint in m_collPoints) { collPtArray[refPointer] = collPoint.CollPointInfo; refPointer++; if (refPointer >= MyPhysicsConfig.MaxContactPoints) { break; } } if (refPointer > 0) { MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collPtArray, refPointer); } MyContactInfoCache.FreeStackAlloc(collPtArray); MyPhysics.physicsSystem.GetContactConstraintModule().GetTriangleCache().PushBackTriangleList(triangles); } } catch { throw; } finally { if (!staticCollision) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); } } return(false); }
private bool DoOverlapBoxTriangleTest(MyBox oldBox, MyBox newBox, MyTriangle_Vertex_Normal triangle, MyPlane plane, float collTolerance, ref Matrix transformMatrix, ref Vector3 oldBoxPos, ref Vector3 newBoxPos, List <MyCollisionPointStruct> collPoints) { Matrix dirs0 = newBox.Orientation; dirs0.Translation = Vector3.Zero; #region Triangle Vector3 triVec0 = triangle.Vertexes.Vertex0; Vector3 triVec1 = triangle.Vertexes.Vertex1; Vector3 triVec2 = triangle.Vertexes.Vertex2; //mesh.GetVertex(triangle.GetVertexIndex(0), out triVec0); //mesh.GetVertex(triangle.GetVertexIndex(1), out triVec1); //mesh.GetVertex(triangle.GetVertexIndex(2), out triVec2); // Deano move tri into world space //Matrix transformMatrix = mesh.TransformMatrix; Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0); Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1); Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2); MyTriangle tri = new MyTriangle(ref triVec0, ref triVec1, ref triVec2); #endregion #region triEdge0 Vector3 pt0; Vector3 pt1; tri.GetPoint(0, out pt0); tri.GetPoint(1, out pt1); Vector3 triEdge0; Vector3.Subtract(ref pt1, ref pt0, out triEdge0); #endregion #region triEdge1 Vector3 pt2; tri.GetPoint(2, out pt2); Vector3 triEdge1; Vector3.Subtract(ref pt2, ref pt1, out triEdge1); #endregion #region triEdge2 Vector3 triEdge2; Vector3.Subtract(ref pt0, ref pt2, out triEdge2); #endregion if (triEdge0.LengthSquared() < MyMwcMathConstants.EPSILON) { return(false); } if (triEdge1.LengthSquared() < MyMwcMathConstants.EPSILON) { return(false); } if (triEdge2.LengthSquared() < MyMwcMathConstants.EPSILON) { return(false); } /* * triEdge0 = MyMwcUtils.Normalize(triEdge0); * triEdge1 = MyMwcUtils.Normalize(triEdge1); * triEdge2 = MyMwcUtils.Normalize(triEdge2); */ triEdge0.Normalize(); triEdge1.Normalize(); triEdge2.Normalize(); //Vector3 triNormal = triangle.Plane.Normal; Vector3 triNormal = plane.Normal; Vector3.TransformNormal(ref triNormal, ref transformMatrix, out triNormal); // 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], newBox, tri, collTolerance); 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 = newBox.GetCentre() - tri.Centre; Vector3 N = axes[minAxis]; float depth = overlapDepths[minAxis]; if (Vector3.Dot(D, N) > 0.0f) { N *= -1; } Vector3 boxOldPos = oldBoxPos; //(info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 boxNewPos = newBoxPos; // (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero; Vector3 meshPos = transformMatrix.Translation; // (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; m_pts.Clear(); const float combinationDist = 0.05f; GetBoxTriangleIntersectionPoints(m_pts, newBox, tri, depth + combinationDist); // adjust the depth #region delta Vector3 delta; Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta); #endregion #region oldDepth float oldDepth; Vector3.Dot(ref delta, ref N, out oldDepth); oldDepth += depth; #endregion // report collisions int numPts = m_pts.Count; if (numPts > 0) { for (i = 0; i < numPts; ++i) { collPoints.Add(new MyCollisionPointStruct(-oldDepth, new MySmallCollPointInfo(m_pts[i] - boxNewPos, m_pts[i] - meshPos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, N, -oldDepth, m_pts[i]))); } return(true); } else { return(false); } }
private bool DoOverlapBoxTriangleStaticTest(MyBox oldBox, MyBox newBox, MyTriangle_Vertex_Normal triangle, MyPlane plane, float collTolerance, ref Matrix transformMatrix, ref Vector3 oldBoxPos, ref Vector3 newBoxPos) { Matrix dirs0 = newBox.Orientation; dirs0.Translation = Vector3.Zero; #region REFERENCE: Triangle tri = new Triangle(mesh.GetVertex(triangleVertexes.GetVertexIndex(0)),mesh.GetVertex(triangleVertexes.GetVertexIndex(1)),mesh.GetVertex(triangleVertexes.GetVertexIndex(2))); Vector3 triVec0 = triangle.Vertexes.Vertex0; Vector3 triVec1 = triangle.Vertexes.Vertex1; Vector3 triVec2 = triangle.Vertexes.Vertex2; // Deano move tri into world space //Matrix transformMatrix = mesh.TransformMatrix; Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0); Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1); Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2); MyTriangle tri = new MyTriangle(ref triVec0, ref triVec1, ref triVec2); #endregion #region REFERENCE Vector3 triEdge0 = (tri.GetPoint(1) - tri.GetPoint(0)); Vector3 pt0; Vector3 pt1; tri.GetPoint(0, out pt0); tri.GetPoint(1, out pt1); Vector3 triEdge0; Vector3.Subtract(ref pt1, ref pt0, out triEdge0); #endregion #region REFERENCE Vector3 triEdge1 = (tri.GetPoint(2) - tri.GetPoint(1)); Vector3 pt2; tri.GetPoint(2, out pt2); Vector3 triEdge1; Vector3.Subtract(ref pt2, ref pt1, out triEdge1); #endregion #region REFERENCE Vector3 triEdge2 = (tri.GetPoint(0) - tri.GetPoint(2)); Vector3 triEdge2; Vector3.Subtract(ref pt0, ref pt2, out triEdge2); #endregion if (triEdge0.LengthSquared() < MyMwcMathConstants.EPSILON) { return(false); } if (triEdge1.LengthSquared() < MyMwcMathConstants.EPSILON) { return(false); } if (triEdge2.LengthSquared() < MyMwcMathConstants.EPSILON) { return(false); } triEdge0.Normalize(); triEdge1.Normalize(); triEdge2.Normalize(); //Vector3 triNormal = triangle.Plane.Normal; Vector3 triNormal = plane.Normal; Vector3.TransformNormal(ref triNormal, ref transformMatrix, out triNormal); // the 15 potential separating axes const int numAxes = 13; Vector3[] axes = new Vector3[numAxes]; axes[0] = triNormal; axes[1] = dirs0.Right; axes[2] = dirs0.Up; axes[3] = dirs0.Backward; Vector3.Cross(ref axes[1], ref triEdge0, out axes[4]); Vector3.Cross(ref axes[1], ref triEdge1, out axes[5]); Vector3.Cross(ref axes[1], ref triEdge2, out axes[6]); Vector3.Cross(ref axes[2], ref triEdge0, out axes[7]); Vector3.Cross(ref axes[2], ref triEdge1, out axes[8]); Vector3.Cross(ref axes[2], ref triEdge2, out axes[9]); Vector3.Cross(ref axes[3], ref triEdge0, out axes[10]); Vector3.Cross(ref axes[3], ref triEdge1, out axes[11]); Vector3.Cross(ref axes[3], ref triEdge2, out axes[12]); // the overlap depths along each axis float[] overlapDepths = new float[numAxes]; // 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 < numAxes; ++i) { overlapDepths[i] = 1.0f; if (Disjoint(out overlapDepths[i], axes[i], newBox, tri, collTolerance)) { return(false); } } // The box overlap, find the separation depth closest to 0. float minDepth = float.MaxValue; int minAxis = -1; for (i = 0; i < numAxes; ++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 = newBox.GetCentre() - tri.Centre; Vector3 N = axes[minAxis]; float depth = overlapDepths[minAxis]; if (Vector3.Dot(D, N) > 0.0f) { N *= -1; } Vector3 boxOldPos = oldBoxPos; //(info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 boxNewPos = newBoxPos; // (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero; Vector3 meshPos = transformMatrix.Translation; // (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; List <Vector3> pts = new List <Vector3>(); //pts.Clear(); const float combinationDist = 0.05f; GetBoxTriangleIntersectionPoints(pts, newBox, tri, depth + combinationDist); // adjust the depth #region delta Vector3 delta; Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta); #endregion #region oldDepth float oldDepth; Vector3.Dot(ref delta, ref N, out oldDepth); oldDepth += depth; #endregion // report collisions int numPts = pts.Count; if (numPts > 0) { return(true); } else { 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; }