/// <summary> /// CollDetectBoxStaticMeshOverlap /// </summary> /// <param name="oldBox"></param> /// <param name="newBox"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> /// <returns>bool</returns> private static bool CollDetectBoxStaticMeshOverlap(Box oldBox, Box newBox, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { 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 = mesh.InverseTransformMatrix; Vector3.Transform(ref boxCentre, ref invTransformMatrix, out boxCentre); #endregion BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddBox(newBox, ref bb); bool collision = false; int[] potTriArray = IntStackAlloc(); // aabox is done in mesh space and handles the mesh transform correctly int numTriangles = mesh.GetTrianglesIntersectingtAABox(potTriArray, MaxLocalStackTris, ref bb); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { IndexedTriangle meshTriangle = mesh.GetTriangle(potTriArray[iTriangle]); // quick early test is done in mesh space float dist = meshTriangle.Plane.DotCoordinate(boxCentre); // BEN-BUG-FIX: Fixed by chaning 0.0F to -boxRadius. if (dist > boxRadius || dist < -boxRadius) { continue; } if (DoOverlapBoxTriangleTest( oldBox, newBox, ref meshTriangle, mesh, ref info, collTolerance, collisionFunctor)) { collision = true; } } FreeStackAlloc(potTriArray); return(collision); }
private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox, ref IndexedTriangle triangle, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Matrix dirs0 = newBox.Orientation; #region REFERENCE: Triangle tri = new Triangle(mesh.GetVertex(triangle.GetVertexIndex(0)),mesh.GetVertex(triangle.GetVertexIndex(1)),mesh.GetVertex(triangle.GetVertexIndex(2))); Vector3 triVec0; Vector3 triVec1; Vector3 triVec2; 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); Triangle tri = new Triangle(ref triVec0, ref triVec1, ref triVec2); #endregion #region qqfx 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 pt1, out triEdge0); #endregion #region qqfx 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 qqfx Vector3 triEdge2 = (tri.GetPoint(0) - tri.GetPoint(2)); Vector3 triEdge2; Vector3.Subtract(ref pt0, ref pt2, out triEdge2); #endregion triEdge0.Normalize(); triEdge1.Normalize(); triEdge2.Normalize(); Vector3 triNormal = triangle.Plane.Normal; // 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 < JiggleMath.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 = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 boxNewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero; Vector3 meshPos = (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 REFERENCE: Vector3 delta = boxNewPos - boxOldPos; Vector3 delta; Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta); #endregion #region REFERENCE: float oldDepth = depth + Vector3.Dot(delta, N); float oldDepth; Vector3.Dot(ref delta, ref N, out oldDepth); oldDepth += depth; #endregion unsafe { // report collisions int numPts = pts.Count; #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) #endif { if (numPts > 0) { if (numPts >= MaxLocalStackSCPI) { numPts = MaxLocalStackSCPI - 1; } // adjust positions for (i = 0; i < numPts; ++i) { collPts[i] = new SmallCollPointInfo(pts[i] - boxNewPos, pts[i] - meshPos, oldDepth); } collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts); #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return(true); } else { #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return(false); } } } }
/// <summary> /// CollDetectCapsuleStaticMeshOverlap /// </summary> /// <param name="oldCapsule"></param> /// <param name="newCapsule"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> private void CollDetectCapsuleStaticMeshOverlap(Capsule oldCapsule, Capsule newCapsule, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; float capsuleTolR = collTolerance + newCapsule.Radius; float capsuleTolR2 = capsuleTolR * capsuleTolR; Vector3 collNormal = Vector3.Zero; BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddCapsule(newCapsule, ref bb); unsafe { #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; int *potentialTriangles = stackalloc int[MaxLocalStackTris]; { { #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) { int[] potTriArray = IntStackAlloc(); fixed(int *potentialTriangles = potTriArray) { #endif int numCollPts = 0; int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); Vector3 capsuleStart = newCapsule.Position; Vector3 capsuleEnd = newCapsule.GetEnd(); Matrix meshInvTransform = mesh.InverseTransformMatrix; Vector3 meshSpaceCapsuleStart = Vector3.Transform(capsuleStart, meshInvTransform); Vector3 meshSpaceCapsuleEnd = Vector3.Transform(capsuleEnd, meshInvTransform); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]); // we do the plane test using the capsule in mesh space float distToStart = meshTriangle.Plane.DotCoordinate(meshSpaceCapsuleStart); float distToEnd = meshTriangle.Plane.DotCoordinate(meshSpaceCapsuleEnd); // BEN-BUG-FIX: Fixed by replacing 0.0F with -capsuleTolR. if ((distToStart > capsuleTolR && distToEnd > capsuleTolR) || (distToStart < -capsuleTolR && distToEnd < -capsuleTolR)) { continue; } // we now transform the triangle into world space (we could keep leave the mesh alone // but at this point 3 vector transforms is probably not a major slow down) int i0, i1, i2; meshTriangle.GetVertexIndices(out i0, out i1, out i2); Vector3 triVec0; Vector3 triVec1; Vector3 triVec2; mesh.GetVertex(i0, out triVec0); mesh.GetVertex(i1, out triVec1); mesh.GetVertex(i2, 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); Triangle triangle = new Triangle(ref triVec0, ref triVec1, ref triVec2); Segment seg = new Segment(capsuleStart, capsuleEnd - capsuleStart); float tS, tT0, tT1; float d2 = Distance.SegmentTriangleDistanceSq(out tS, out tT0, out tT1, seg, triangle); if (d2 < capsuleTolR2) { Vector3 oldCapsuleStart = oldCapsule.Position; Vector3 oldCapsuleEnd = oldCapsule.GetEnd(); Segment oldSeg = new Segment(oldCapsuleStart, oldCapsuleEnd - oldCapsuleStart); d2 = Distance.SegmentTriangleDistanceSq(out tS, out tT0, out tT1, oldSeg, triangle); // report result from old position float dist = (float)System.Math.Sqrt(d2); float depth = oldCapsule.Radius - dist; Vector3 pt = triangle.GetPoint(tT0, tT1); Vector3 collisionN = (d2 > JiggleMath.Epsilon) ? JiggleMath.NormalizeSafe(oldSeg.GetPoint(tS) - pt) : meshTriangle.Plane.Normal; if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Reused existing collPts. collPts[numCollPts].R0 = pt - body0Pos; collPts[numCollPts].R1 = pt - body1Pos; collPts[numCollPts++].InitialPenetration = depth; } collNormal += collisionN; } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref collNormal); collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts); } #if USE_STACKALLOC } } #else } FreeStackAlloc(potTriArray); } FreeStackAlloc(collPtArray); #endif } }
/// <summary> /// CollDetectSphereStaticMeshSweep /// </summary> /// <param name="oldSphere"></param> /// <param name="newSphere"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> internal static void CollDetectSphereStaticMeshSweep(BoundingSphere oldSphere, BoundingSphere newSphere, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // really use a swept test - or overlap? Vector3 delta = newSphere.Center - oldSphere.Center; if (delta.LengthSquared() < (0.25f * newSphere.Radius * newSphere.Radius)) { CollDetectSphereStaticMeshOverlap(oldSphere, newSphere, mesh, info, collTolerance, collisionFunctor); } else { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; float sphereTolR = collTolerance + oldSphere.Radius; float sphereToR2 = sphereTolR * sphereTolR; Vector3 collNormal = Vector3.Zero; BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddSphere(oldSphere, ref bb); BoundingBoxHelper.AddSphere(newSphere, ref bb); // get the spheres centers in triangle mesh space Vector3 newSphereCen = Vector3.Transform(newSphere.Center, mesh.InverseTransformMatrix); Vector3 oldSphereCen = Vector3.Transform(oldSphere.Center, mesh.InverseTransformMatrix); unsafe { #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; int *potentialTriangles = stackalloc int[MaxLocalStackTris]; { { #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) { int[] potTriArray = IntStackAlloc(); fixed(int *potentialTriangles = potTriArray) { #endif int numCollPts = 0; int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { // first test the old sphere for being on the wrong side IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]); float distToCentreOld = meshTriangle.Plane.DotCoordinate(oldSphereCen); if (distToCentreOld <= 0.0f) { continue; } // now test the new sphere for being clear float distToCentreNew = meshTriangle.Plane.DotCoordinate(newSphereCen); if (distToCentreNew > sphereTolR) { continue; } int i0, i1, i2; meshTriangle.GetVertexIndices(out i0, out i1, out i2); Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2)); // If the old sphere is intersecting, just use that result float s, t; float d2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle); if (d2 < sphereToR2) { float dist = (float)System.Math.Sqrt(d2); float depth = oldSphere.Radius - dist; Vector3 triangleN = triangle.Normal; Vector3 normSafe = oldSphereCen - triangle.GetPoint(s, t); JiggleMath.NormalizeSafe(ref normSafe); Vector3 collisionN = (dist > float.Epsilon) ? normSafe : triangleN; // since impulse gets applied at the old position Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN; if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Reuse existing collPts. collPts[numCollPts].R0 = pt - body0Pos; collPts[numCollPts].R1 = pt - body1Pos; collPts[numCollPts++].InitialPenetration = depth; } collNormal += collisionN; } else if (distToCentreNew < distToCentreOld) { // old sphere is not intersecting - do a sweep, but only if the sphere is moving into the // triangle Vector3 pt, N; // CHECK THIS float depth; if (Intersection.SweptSphereTriangleIntersection(out pt, out N, out depth, oldSphere, newSphere, triangle, distToCentreOld, distToCentreNew, Intersection.EdgesToTest.EdgeAll, Intersection.CornersToTest.CornerAll)) { // collision point etc must be relative to the old position because that's //where the impulses are applied float dist = (float)System.Math.Sqrt(d2); float depth2 = oldSphere.Radius - dist; Vector3 triangleN = triangle.Normal; Vector3 normSafe = oldSphereCen - triangle.GetPoint(s, t); JiggleMath.NormalizeSafe(ref normSafe); Vector3 collisionN = (dist > JiggleMath.Epsilon) ? normSafe : triangleN; // since impulse gets applied at the old position Vector3 pt2 = oldSphere.Center - oldSphere.Radius * collisionN; if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Reuse existing collPts. collPts[numCollPts].R0 = pt2 - body0Pos; collPts[numCollPts].R1 = pt2 - body1Pos; collPts[numCollPts++].InitialPenetration = depth; } collNormal += collisionN; } } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref collNormal); collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts); } } #if USE_STACKALLOC } } #else FreeStackAlloc(potTriArray); } FreeStackAlloc(collPtArray); } #endif } }
/// <summary> /// CollDetectSphereStaticMeshOverlap /// </summary> /// <param name="oldSphere"></param> /// <param name="newSphere"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public static void CollDetectSphereStaticMeshOverlap(BoundingSphere oldSphere, BoundingSphere newSphere, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; float sphereTolR = collTolerance + newSphere.Radius; float sphereTolR2 = sphereTolR * sphereTolR; SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); int[] potTriArray = IntStackAlloc(); int numCollPts = 0; Vector3 collNormal = Vector3.Zero; BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddSphere(newSphere, ref bb); int numTriangles = mesh.GetTrianglesIntersectingtAABox(potTriArray, MaxLocalStackTris, ref bb); // Deano : get the spheres centers in triangle mesh space Vector3 newSphereCen = Vector3.Transform(newSphere.Center, mesh.InverseTransformMatrix); Vector3 oldSphereCen = Vector3.Transform(oldSphere.Center, mesh.InverseTransformMatrix); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { IndexedTriangle meshTriangle = mesh.GetTriangle(potTriArray[iTriangle]); float distToCentre = meshTriangle.Plane.DotCoordinate(newSphereCen); // BEN-BUG-FIX: Replaced 0.0f with -sphereTolR. if (distToCentre < -sphereTolR || distToCentre > sphereTolR) { continue; } int i0, i1, i2; meshTriangle.GetVertexIndices(out i0, out i1, out i2); Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2)); float s, t; float newD2 = Distance.PointTriangleDistanceSq(out s, out t, newSphereCen, triangle); if (newD2 < sphereTolR2) { // have overlap - but actually report the old intersection float oldD2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle); float dist = (float)System.Math.Sqrt((float)oldD2); float depth = oldSphere.Radius - dist; Vector3 triPointSTNorm = oldSphereCen - triangle.GetPoint(s, t); JiggleMath.NormalizeSafe(ref triPointSTNorm); Vector3 collisionN = (dist > float.Epsilon) ? triPointSTNorm : triangle.Normal; // since impulse get applied at the old position Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN; if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Reuse existing collPts. collPtArray[numCollPts].R0 = pt - body0Pos; collPtArray[numCollPts].R1 = pt - body1Pos; collPtArray[numCollPts++].InitialPenetration = depth; } collNormal += collisionN; } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref collNormal); collisionFunctor.CollisionNotify(ref info, ref collNormal, collPtArray, numCollPts); } FreeStackAlloc(potTriArray); FreeStackAlloc(collPtArray); }
/// <summary> /// DoOverlapBoxTriangleTest /// </summary> /// <param name="oldBox"></param> /// <param name="newBox"></param> /// <param name="triangle"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> /// <returns>bool</returns> private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox, ref IndexedTriangle triangle, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Matrix4 dirs0 = newBox.Orientation; #region REFERENCE: Triangle tri = new Triangle(mesh.GetVertex(triangle.GetVertexIndex(0)),mesh.GetVertex(triangle.GetVertexIndex(1)),mesh.GetVertex(triangle.GetVertexIndex(2))); Vector3 triVec0; Vector3 triVec1; Vector3 triVec2; 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 Matrix4 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); Triangle tri = new Triangle(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 triEdge0.Normalize(); triEdge1.Normalize(); triEdge2.Normalize(); // BEN-OPTIMISATION: Replaced loops with code that requires no looping. // The new code is faster, has less allocations and math especially // since the method returns as soon as it finds a non-overlapping axis, // i.e. Before irreleveat allocations occur. #region "Old (less efficient) code" /*Vector3 triNormal = triangle.Plane.Normal; * * // 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 < JiggleMath.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];*/ #endregion #region "Optimised code" Vector3 triNormal = triangle.Plane.Normal; Vector3 right = dirs0.Right(); Vector3 up = dirs0.Up(); Vector3 backward = dirs0.Backward(); float testDepth; if (Disjoint(out testDepth, ref triNormal, newBox, ref tri, collTolerance)) { return(false); } float depth = testDepth; Vector3 N = triNormal; if (Disjoint(out testDepth, ref right, newBox, ref tri, collTolerance)) { return(false); } if (testDepth < depth) { depth = testDepth; N = right; } if (Disjoint(out testDepth, ref up, newBox, ref tri, collTolerance)) { return(false); } if (testDepth < depth) { depth = testDepth; N = up; } if (Disjoint(out testDepth, ref backward, newBox, ref tri, collTolerance)) { return(false); } if (testDepth < depth) { depth = testDepth; N = backward; } Vector3 axis; Vector3.Cross(ref right, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref right, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref right, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } /*if (N == Vector3.Zero) * return (false);*/ Vector3 D = newBox.GetCentre() - tri.Centre; N.Normalize(); int i; #endregion if (Vector3.Dot(D, N) < 0.0f) { N *= -1; } Vector3 boxOldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 boxNewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero; Vector3 meshPos = (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 REFERENCE: Vector3 delta = boxNewPos - boxOldPos; Vector3 delta; Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta); #endregion #region REFERENCE: float oldDepth = depth + Vector3.Dot(delta, N); float oldDepth; Vector3.Dot(ref delta, ref N, out oldDepth); oldDepth += depth; #endregion unsafe { // report collisions int numPts = pts.Count; #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) #endif { if (numPts > 0) { if (numPts >= MaxLocalStackSCPI) { numPts = MaxLocalStackSCPI - 1; } // adjust positions for (i = 0; i < numPts; ++i) { // BEN-OPTIMISATION: Reused existing SmallCollPointInfo and inlined vector substraction. collPts[i].R0.X = pts[i].X - boxNewPos.X; collPts[i].R0.Y = pts[i].Y - boxNewPos.Y; collPts[i].R0.Z = pts[i].Z - boxNewPos.Z; collPts[i].R1.X = pts[i].X - meshPos.X; collPts[i].R1.Y = pts[i].Y - meshPos.Y; collPts[i].R1.Z = pts[i].Z - meshPos.Z; collPts[i].InitialPenetration = oldDepth; } collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts); #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return(true); } else { #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return(false); } } } }
/// <summary> /// GetLocalSkinWireframe /// </summary> /// <param name="skin"></param> /// <returns>VertexPositionColor[]</returns> public static VertexPositionColor[] GetLocalSkinWireframe(this CollisionSkin skin) { List <VertexPositionColor> wireframe = new List <VertexPositionColor>(); // skip if there is no collision skin if (skin == null) { return(wireframe.ToArray()); } for (int i = 0; i < skin.NumPrimitives; i++) { Primitive p = skin.GetPrimitiveLocal(i); Matrix trans = p.TransformMatrix; if (p is Sphere) { Sphere np = (Sphere)p; List <Vector3> SpherePoints = calcCirclePoints(np.Radius); AddShapeToWireframe(SpherePoints, wireframe, trans, Color.Blue); AddShapeToWireframe(SpherePoints, wireframe, Matrix.CreateRotationY(MathHelper.PiOver2) * trans, Color.Red); AddShapeToWireframe(SpherePoints, wireframe, Matrix.CreateRotationX(MathHelper.PiOver2) * trans, Color.Green); } else if (p is Capsule) { Capsule np = (Capsule)p; List <Vector3> Ball = calcCirclePoints(np.Radius); List <Vector3> CylPoints = new List <Vector3>(); List <Vector3> CirclePoints = new List <Vector3>(); List <Vector3> SidePoints = new List <Vector3>(); // Create LongWays profile slice foreach (Vector3 v in Ball) { Vector3 t = Vector3.Transform(v, Matrix.CreateRotationX(MathHelper.PiOver2)); CylPoints.Add(t); } float len = np.Length; SidePoints.Add(Vector3.Transform(new Vector3(np.Radius, len, 0), Matrix.CreateRotationX(MathHelper.PiOver2))); SidePoints.Add(Vector3.Transform(new Vector3(np.Radius, 0, 0), Matrix.CreateRotationX(MathHelper.PiOver2))); SidePoints.Add(Vector3.Transform(new Vector3(-np.Radius, 0, 0), Matrix.CreateRotationX(MathHelper.PiOver2))); SidePoints.Add(Vector3.Transform(new Vector3(-np.Radius, len, 0), Matrix.CreateRotationX(MathHelper.PiOver2))); // Create Y Rungs AddShapeToWireframe(Ball, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 0.0f * len)) * trans, Color.Green); AddShapeToWireframe(Ball, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 0.5f * np.Length)) * trans, Color.Green); AddShapeToWireframe(Ball, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 1.0f * np.Length)) * trans, Color.Green); // Create Z Profile Matrix Zmat = Matrix.CreateRotationZ(MathHelper.PiOver2); AddShapeToWireframe(CylPoints, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, np.Length)) * Zmat * trans, Color.Blue); AddShapeToWireframe(CylPoints, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 0)) * Zmat * trans, Color.Blue); AddLineToWireframe(SidePoints[0], SidePoints[1], wireframe, Zmat * trans, Color.Blue); AddLineToWireframe(SidePoints[2], SidePoints[3], wireframe, Zmat * trans, Color.Blue); //// Create X Profile Matrix Xmat = Matrix.Identity; AddShapeToWireframe(CylPoints, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, np.Length)) * Xmat * trans, Color.Red); AddShapeToWireframe(CylPoints, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 0)) * Xmat * trans, Color.Red); AddLineToWireframe(SidePoints[0], SidePoints[1], wireframe, Xmat * trans, Color.Red); AddLineToWireframe(SidePoints[2], SidePoints[3], wireframe, Xmat * trans, Color.Red); } else if (p is Box) { Box np = (Box)p; List <Vector3> xPoints = new List <Vector3>(); List <Vector3> yPoints = new List <Vector3>(); List <Vector3> zPoints = new List <Vector3>(); Vector3 slen = np.SideLengths; xPoints.Add(new Vector3(slen.X, slen.Y, slen.Z)); xPoints.Add(new Vector3(0, slen.Y, slen.Z)); xPoints.Add(new Vector3(slen.X, 0, slen.Z)); xPoints.Add(new Vector3(0, 0, slen.Z)); xPoints.Add(new Vector3(slen.X, slen.Y, 0)); xPoints.Add(new Vector3(0, slen.Y, 0)); xPoints.Add(new Vector3(slen.X, 0, 0)); xPoints.Add(new Vector3(0, 0, 0)); yPoints.Add(new Vector3(slen.X, slen.Y, slen.Z)); yPoints.Add(new Vector3(slen.X, 0, slen.Z)); yPoints.Add(new Vector3(0, slen.Y, slen.Z)); yPoints.Add(new Vector3(0, 0, slen.Z)); yPoints.Add(new Vector3(slen.X, slen.Y, 0)); yPoints.Add(new Vector3(slen.X, 0, 0)); yPoints.Add(new Vector3(0, slen.Y, 0)); yPoints.Add(new Vector3(0, 0, 0)); zPoints.Add(new Vector3(slen.X, slen.Y, slen.Z)); zPoints.Add(new Vector3(slen.X, slen.Y, 0)); zPoints.Add(new Vector3(0, slen.Y, slen.Z)); zPoints.Add(new Vector3(0, slen.Y, 0)); zPoints.Add(new Vector3(slen.X, 0, slen.Z)); zPoints.Add(new Vector3(slen.X, 0, 0)); zPoints.Add(new Vector3(0, 0, slen.Z)); zPoints.Add(new Vector3(0, 0, 0)); AddLinesToWireframe(xPoints, wireframe, trans, Color.Red); AddLinesToWireframe(yPoints, wireframe, trans, Color.Green); AddLinesToWireframe(zPoints, wireframe, trans, Color.Blue); } else if (p is AABox) { } else if (p is Heightmap) { Heightmap hm = (Heightmap)p; Vector3 point, normal; for (int e = 0; e < hm.Heights.Nx; e += 5) { for (int j = 0; j < hm.Heights.Nz; j += 5) { hm.GetSurfacePosAndNormal(out point, out normal, e, j); AddLineToWireframe(point, point - 0.5f * normal, wireframe, trans, Color.GreenYellow); } } } else if (p is JigLibX.Geometry.Plane) { } else if (p is TriangleMesh) { TriangleMesh np = (TriangleMesh)p; for (int j = 0; j < np.GetNumTriangles(); j++) { IndexedTriangle t = np.GetTriangle(j); Vector3 p1 = np.GetVertex(t.GetVertexIndex(0)); Vector3 p2 = np.GetVertex(t.GetVertexIndex(1)); Vector3 p3 = np.GetVertex(t.GetVertexIndex(2)); List <Vector3> tPoints = new List <Vector3>(); tPoints.Add(p1); tPoints.Add(p2); tPoints.Add(p3); tPoints.Add(p1); AddShapeToWireframe(tPoints, wireframe, trans, Color.Red); } } } return(wireframe.ToArray()); }
public static void WriteInAllocatedMemoryImpl(BinaryWriter writer, MemoryPool memory, IndexedTriangle t) { writer.Write((UInt16)t.IDX0); writer.Write((UInt16)t.IDX1); writer.Write((UInt16)t.IDX2); }
public static uint GetElementSizeImpl(IndexedTriangle t) => 2 * 3;
private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox, ref IndexedTriangle triangle, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { var dirs0 = newBox.Orientation; mesh.GetVertex(triangle.GetVertexIndex(0), out var triVec0); mesh.GetVertex(triangle.GetVertexIndex(1), out var triVec1); mesh.GetVertex(triangle.GetVertexIndex(2), out var triVec2); var 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); var tri = new Triangle(ref triVec0, ref triVec1, ref triVec2); tri.GetPoint(0, out var pt0); tri.GetPoint(1, out var pt1); Vector3.Subtract(ref pt1, ref pt0, out var triEdge0); tri.GetPoint(2, out var pt2); Vector3.Subtract(ref pt2, ref pt1, out var triEdge1); Vector3.Subtract(ref pt0, ref pt2, out var triEdge2); triEdge0.Normalize(); triEdge1.Normalize(); triEdge2.Normalize(); var triNormal = triangle.Plane.Normal; var right = dirs0.Right; var up = dirs0.Up; var backward = dirs0.Backward; if (Disjoint(out var testDepth, ref triNormal, newBox, ref tri, collTolerance)) { return(false); } var depth = testDepth; var N = triNormal; if (Disjoint(out testDepth, ref right, newBox, ref tri, collTolerance)) { return(false); } if (testDepth < depth) { depth = testDepth; N = right; } if (Disjoint(out testDepth, ref up, newBox, ref tri, collTolerance)) { return(false); } if (testDepth < depth) { depth = testDepth; N = up; } if (Disjoint(out testDepth, ref backward, newBox, ref tri, collTolerance)) { return(false); } if (testDepth < depth) { depth = testDepth; N = backward; } Vector3.Cross(ref right, ref triEdge0, out var axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref right, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref right, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } var D = newBox.GetCentre() - tri.Centre; N.Normalize(); int i; if (Vector3.Dot(D, N) < 0.0f) { N *= -1; } var boxOldPos = info.Skin0.Owner?.OldPosition ?? Vector3.Zero; var boxNewPos = info.Skin0.Owner?.Position ?? Vector3.Zero; var meshPos = info.Skin1.Owner?.OldPosition ?? Vector3.Zero; var pts = new List <Vector3>(); const float combinationDist = 0.05f; GetBoxTriangleIntersectionPoints(pts, newBox, tri, depth + combinationDist); Vector3.Subtract(ref boxNewPos, ref boxOldPos, out var delta); Vector3.Dot(ref delta, ref N, out var oldDepth); oldDepth += depth; unsafe { var numPts = pts.Count; var collPts = stackalloc SmallCollPointInfo[MaxLocalStackScpi]; { if (numPts > 0) { if (numPts >= MaxLocalStackScpi) { numPts = MaxLocalStackScpi - 1; } for (i = 0; i < numPts; ++i) { collPts[i].R0.X = pts[i].X - boxNewPos.X; collPts[i].R0.Y = pts[i].Y - boxNewPos.Y; collPts[i].R0.Z = pts[i].Z - boxNewPos.Z; collPts[i].R1.X = pts[i].X - meshPos.X; collPts[i].R1.Y = pts[i].Y - meshPos.Y; collPts[i].R1.Z = pts[i].Z - meshPos.Z; collPts[i].InitialPenetration = oldDepth; } collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts); return(true); } return(false); } } }
public MeshData Convert(PlyReader reader, PlyHeader header) { var normalizedHeader = new PlyHeaderNormalizer(header); var elements = normalizedHeader.BaseHeader.Elements; var faces = new List <IndexedTriangle>(elements[normalizedHeader.FacesId].InstanceCount); var meshData = new MeshData { Vertices = new Vector3[elements[normalizedHeader.VerticesId].InstanceCount], Faces = null, Normals = new Vector3[normalizedHeader.NormalsId == -1 ? 0 : elements[normalizedHeader.NormalsId].InstanceCount] }; int currVertex = 0; int currVertexPropWritten = 0; int currNormal = 0; int currNormalPropWritten = 0; int currFace = 0; // calling progressReporter.Report is expensive, limit it. long totalLoad = meshData.Vertices.Length + faces.Capacity + meshData.Normals.Length; int lastProgressReported = 10; // since the structure of the file is not known // and will be determined at the runtime // we don't know what elements and properties come first. // not the prettiest but definitely the fastest way to do this. for (int i = 0; i < elements.Count; ++i) { for (int j = 0; j < elements[i].InstanceCount; ++j) { // call the progressReporter function on every 10% progress int progress = (int)((currVertex + currNormal + currFace) * 100 / totalLoad); if (progress > lastProgressReported + 10 && ProgressReporter != null) { ProgressReporter.Report(progress); lastProgressReported = progress; } // go through every property of the current element for (int k = 0; k < elements[i].Properties.Count; ++k) { bool ignored = true; // if the current element was found by the normalizedHeader // to be a vertex element, parse the vertices if (i == normalizedHeader.VerticesId) { if (k == normalizedHeader.VertexX) { meshData.Vertices[currVertex].X = reader.ReadProperty <float>(); currVertexPropWritten++; ignored = false; } else if (k == normalizedHeader.VertexY) { meshData.Vertices[currVertex].Y = reader.ReadProperty <float>(); currVertexPropWritten++; ignored = false; } else if (k == normalizedHeader.VertexZ) { meshData.Vertices[currVertex].Z = reader.ReadProperty <float>(); currVertexPropWritten++; ignored = false; } if (currVertexPropWritten == 3) { currVertexPropWritten = 0; currVertex++; } } // if it is a normal element.. if (i == normalizedHeader.NormalsId) { if (k == normalizedHeader.NormalX) { meshData.Normals[currNormal].X = reader.ReadProperty <float>(); currNormalPropWritten++; ignored = false; } else if (k == normalizedHeader.NormalY) { meshData.Normals[currNormal].X = reader.ReadProperty <float>(); currNormalPropWritten++; ignored = false; } else if (k == normalizedHeader.NormalZ) { meshData.Normals[currNormal].X = reader.ReadProperty <float>(); currNormalPropWritten++; ignored = false; } if (currNormalPropWritten == 3) { currNormal++; currNormalPropWritten = 0; } } // if it is a face element.. if (i == normalizedHeader.FacesId) { if (k == normalizedHeader.VerticesId) { // read the vertices of a face List <int> verts = new List <int>(3); foreach (int index in reader.ReadArray <int>()) { verts.Add(index); } // if we got 3 vertices, its a normal triangle // and the triangle to the list if (verts.Count == 3) { var t = new IndexedTriangle { Vertex1 = verts[0], Vertex2 = verts[1], Vertex3 = verts[2] }; faces.Add(t); } else if (verts.Count == 4) { faces.Add(new IndexedTriangle(verts[0], verts[1], verts[3])); faces.Add(new IndexedTriangle(verts[1], verts[2], verts[3])); } else { throw new NotSupportedException("Only triangular faces are currently supported."); } currFace++; ignored = false; } } if (ignored) { reader.SkipProperty(); } } } } meshData.Faces = faces.ToArray(); if (meshData.Normals.Length == 0) { meshData.Normals = null; } ProgressReporter?.Report(100); return(meshData); }