private void GetCellLineIntersectionOctree(ref MyIntersectionResultLineTriangle?result, ref Line modelSpaceLine, ref float?minDistanceUntilNow, CellData cachedDataCell, IntersectionFlags flags) { m_overlapElementCache.Clear(); if (cachedDataCell.Octree != null) { Vector3 vector; Vector3 vector2; cachedDataCell.GetPackedPosition(ref modelSpaceLine.From, out vector); cachedDataCell.GetPackedPosition(ref modelSpaceLine.To, out vector2); Ray ray = new Ray(vector, vector2 - vector); cachedDataCell.Octree.GetIntersectionWithLine(ref ray, m_overlapElementCache); } for (int i = 0; i < m_overlapElementCache.Count; i++) { int index = m_overlapElementCache[i]; if ((cachedDataCell.VoxelTriangles != null) && (index < cachedDataCell.VoxelTriangles.Length)) { MyTriangle_Vertices vertices; MyVoxelTriangle triangle = cachedDataCell.VoxelTriangles[index]; cachedDataCell.GetUnpackedPosition(triangle.V0, out vertices.Vertex0); cachedDataCell.GetUnpackedPosition(triangle.V1, out vertices.Vertex1); cachedDataCell.GetUnpackedPosition(triangle.V2, out vertices.Vertex2); Vector3 normalVectorFromTriangle = MyUtils.GetNormalVectorFromTriangle(ref vertices); if (normalVectorFromTriangle.IsValid() && (((flags & IntersectionFlags.FLIPPED_TRIANGLES) != ((IntersectionFlags)0)) || (Vector3.Dot(modelSpaceLine.Direction, normalVectorFromTriangle) <= 0f))) { float?lineTriangleIntersection = MyUtils.GetLineTriangleIntersection(ref modelSpaceLine, ref vertices); if ((lineTriangleIntersection != null) && ((result == 0) || (lineTriangleIntersection.Value < result.Value.Distance))) { minDistanceUntilNow = new float?(lineTriangleIntersection.Value); result = new MyIntersectionResultLineTriangle(0, ref vertices, ref normalVectorFromTriangle, lineTriangleIntersection.Value); } } } } }
private void GetCellLineIntersectionOctree(ref MyIntersectionResultLineTriangle?result, ref Line modelSpaceLine, ref float?minDistanceUntilNow, CellData cachedDataCell, IntersectionFlags flags) { m_overlapElementCache.Clear(); if (cachedDataCell.Octree != null) { Vector3 packedStart, packedEnd; cachedDataCell.GetPackedPosition(ref modelSpaceLine.From, out packedStart); cachedDataCell.GetPackedPosition(ref modelSpaceLine.To, out packedEnd); var ray = new Ray(packedStart, packedEnd - packedStart); cachedDataCell.Octree.GetIntersectionWithLine(ref ray, m_overlapElementCache); } for (int j = 0; j < m_overlapElementCache.Count; j++) { var i = m_overlapElementCache[j]; if (cachedDataCell.VoxelTriangles == null) //probably not calculated yet { continue; } // this should never happen if (i >= cachedDataCell.VoxelTriangles.Length) { Debug.Assert(i < cachedDataCell.VoxelTriangles.Length); continue; } MyVoxelTriangle voxelTriangle = cachedDataCell.VoxelTriangles[i]; MyTriangle_Vertexes triangleVertices; cachedDataCell.GetUnpackedPosition(voxelTriangle.VertexIndex0, out triangleVertices.Vertex0); cachedDataCell.GetUnpackedPosition(voxelTriangle.VertexIndex1, out triangleVertices.Vertex1); cachedDataCell.GetUnpackedPosition(voxelTriangle.VertexIndex2, out triangleVertices.Vertex2); Vector3 calculatedTriangleNormal = MyUtils.GetNormalVectorFromTriangle(ref triangleVertices); if (!calculatedTriangleNormal.IsValid()) { continue; } //We dont want backside intersections if (((int)(flags & IntersectionFlags.FLIPPED_TRIANGLES) == 0) && Vector3.Dot(modelSpaceLine.Direction, calculatedTriangleNormal) > 0) { continue; } // AABB intersection test removed, AABB is tested inside BVH float?distance = MyUtils.GetLineTriangleIntersection(ref modelSpaceLine, ref triangleVertices); // If intersection occured and if distance to intersection is closer to origin than any previous intersection if ((distance != null) && ((result == null) || (distance.Value < result.Value.Distance))) { minDistanceUntilNow = distance.Value; result = new MyIntersectionResultLineTriangle(ref triangleVertices, ref calculatedTriangleNormal, distance.Value); } } }
public bool Intersect(ref Line localLine, out MyIntersectionResultLineTriangle result, IntersectionFlags flags) { MyIntersectionResultLineTriangle valueOrDefault; m_sweepResultCache.Clear(); MyGridIntersection.Calculate(m_sweepResultCache, 8f, localLine.From, localLine.To, new Vector3I(0, 0, 0), this.m_cellsCount - 1); float? minDistanceUntilNow = null; MyCellCoord cell = new MyCellCoord(); MyIntersectionResultLineTriangle?nullable2 = null; for (int i = 0; i < m_sweepResultCache.Count; i++) { BoundingBox box; cell.CoordInLod = m_sweepResultCache[i]; MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref cell.CoordInLod, out box); float?lineBoundingBoxIntersection = MyUtils.GetLineBoundingBoxIntersection(ref localLine, ref box); if ((minDistanceUntilNow != null) && (lineBoundingBoxIntersection != null)) { float?nullable1; float?nullable5 = minDistanceUntilNow; float num3 = 15.58846f; if (nullable5 != null) { nullable1 = new float?(nullable5.GetValueOrDefault() + num3); } else { nullable1 = null; } float?nullable4 = nullable1; float num2 = lineBoundingBoxIntersection.Value; if ((nullable4.GetValueOrDefault() < num2) & (nullable4 != null)) { break; } } CellData cachedDataCell = this.GetCell(ref cell); if ((cachedDataCell != null) && (cachedDataCell.VoxelTrianglesCount != 0)) { this.GetCellLineIntersectionOctree(ref nullable2, ref localLine, ref minDistanceUntilNow, cachedDataCell, flags); } } MyIntersectionResultLineTriangle?nullable7 = nullable2; if (nullable7 != null) { valueOrDefault = nullable7.GetValueOrDefault(); } else { valueOrDefault = new MyIntersectionResultLineTriangle(); } result = valueOrDefault; return(nullable2 != null); }
public bool Intersect(ref Line localLine, out MyIntersectionResultLineTriangle result, IntersectionFlags flags) { MyPrecalcComponent.AssertUpdateThread(); ProfilerShort.Begin("VoxelMap.LineIntersection AABB sweep"); m_sweepResultCache.Clear(); MyGridIntersection.Calculate( m_sweepResultCache, (int)MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_METRES, localLine.From, localLine.To, new Vector3I(0, 0, 0), m_cellsCount - 1 ); ProfilerShort.End(); ProfilerShort.Begin("VoxelMap.LineIntersection test AABBs"); float? minDistanceUntilNow = null; BoundingBox cellBoundingBox; MyCellCoord cell = new MyCellCoord(); MyIntersectionResultLineTriangle?tmpResult = null; for (int index = 0; index < m_sweepResultCache.Count; index++) { cell.CoordInLod = m_sweepResultCache[index]; MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref cell.CoordInLod, out cellBoundingBox); float?distanceToBoundingBox = MyUtils.GetLineBoundingBoxIntersection(ref localLine, ref cellBoundingBox); // Sweep results are sorted; when we get far enough, make an early exit const float earlyOutDistance = 1.948557f * MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_METRES; // = sqrt(3) * 9/8 * cell_side if (minDistanceUntilNow != null && distanceToBoundingBox != null && minDistanceUntilNow + earlyOutDistance < distanceToBoundingBox.Value) { break; } // Get cell from cache. If not there, precalc it and store in the cache. // If null is returned, we know that cell doesn't contain any triangleVertexes so we don't need to do intersections. CellData cachedDataCell = GetCell(ref cell); if (cachedDataCell == null || cachedDataCell.VoxelTrianglesCount == 0) { continue; } GetCellLineIntersectionOctree(ref tmpResult, ref localLine, ref minDistanceUntilNow, cachedDataCell, flags); } ProfilerShort.End(); result = tmpResult ?? default(MyIntersectionResultLineTriangle); return(tmpResult.HasValue); }
/// <summary> /// Returns closest hit from line start position. /// </summary> public bool GetIntersectionWithLine(ref LineD line, ref MyCharacterHitInfo info, IntersectionFlags flags = IntersectionFlags.ALL_TRIANGLES) { // TODO: This now uses caspule of physics rigid body on the character, it needs to be changed to ragdoll // Currently this approach will be used to support Characters with different skeleton than humanoid if (info == null) info = new MyCharacterHitInfo(); info.Reset(); bool capsulesReady = UpdateCapsuleBones(); if (!capsulesReady) return false; double closestDistanceToHit = double.MaxValue; Vector3D hitPosition = Vector3D.Zero; Vector3D hitPosition2 = Vector3D.Zero; Vector3 hitNormal = Vector3.Zero; Vector3 hitNormal2 = Vector3.Zero; int capsuleIndex = -1; for (int i = 0; i < m_bodyCapsules.Length; i++) { CapsuleD capsule = m_bodyCapsules[i]; if (capsule.Intersect(line, ref hitPosition, ref hitPosition2, ref hitNormal, ref hitNormal2)) { double distanceToHit = Vector3.Distance(hitPosition, line.From); if (distanceToHit >= closestDistanceToHit) continue; closestDistanceToHit = distanceToHit; capsuleIndex = i; } } if (capsuleIndex != -1) { Matrix worldMatrix = PositionComp.WorldMatrix; int boneIndex = FindBestBone(capsuleIndex, ref hitPosition, ref worldMatrix); // Transform line to model static position and compute accurate collision there // 1. Transform line in local coordinates (used later) Matrix worldMatrixInv = PositionComp.WorldMatrixNormalizedInv; Vector3 fromTrans = Vector3.Transform(line.From, ref worldMatrixInv); Vector3 toTrans = Vector3.Transform(line.To, ref worldMatrixInv); LineD lineLocal = new LineD(fromTrans, toTrans); // 2. Transform line to to bone pose in binding position var bone = AnimationController.CharacterBones[boneIndex]; bone.ComputeAbsoluteTransform(); Matrix boneAbsTrans = bone.AbsoluteTransform; Matrix skinTransform = bone.SkinTransform; Matrix boneTrans = skinTransform * boneAbsTrans; Matrix invBoneTrans = Matrix.Invert(boneTrans); fromTrans = Vector3.Transform(fromTrans, ref invBoneTrans); toTrans = Vector3.Transform(toTrans, ref invBoneTrans); // 3. Move back line to world coordinates LineD lineTransWorld = new LineD(Vector3.Transform(fromTrans, ref worldMatrix), Vector3.Transform(toTrans, ref worldMatrix)); MyIntersectionResultLineTriangleEx? triangle_; bool success = base.GetIntersectionWithLine(ref lineTransWorld, out triangle_, flags); if (success) { MyIntersectionResultLineTriangleEx triangle = triangle_.Value; info.CapsuleIndex = capsuleIndex; info.BoneIndex = boneIndex; info.Capsule = m_bodyCapsules[info.CapsuleIndex]; info.HitHead = info.CapsuleIndex == 0 && m_bodyCapsules.Length > 1; info.HitPositionBindingPose = triangle.IntersectionPointInObjectSpace; info.HitNormalBindingPose = triangle.NormalInObjectSpace; // 4. Move intersection from binding to dynamic pose MyTriangle_Vertexes vertices = new MyTriangle_Vertexes(); vertices.Vertex0 = Vector3.Transform(triangle.Triangle.InputTriangle.Vertex0, ref boneTrans); vertices.Vertex1 = Vector3.Transform(triangle.Triangle.InputTriangle.Vertex1, ref boneTrans); vertices.Vertex2 = Vector3.Transform(triangle.Triangle.InputTriangle.Vertex2, ref boneTrans); Vector3 triangleNormal = Vector3.TransformNormal(triangle.Triangle.InputTriangleNormal, boneTrans); MyIntersectionResultLineTriangle triraw = new MyIntersectionResultLineTriangle(ref vertices, ref triangleNormal, triangle.Triangle.Distance); Vector3 intersectionLocal = Vector3.Transform(triangle.IntersectionPointInObjectSpace, ref boneTrans); Vector3 normalLocal = Vector3.TransformNormal(triangle.NormalInObjectSpace, boneTrans); // 5. Store results triangle = new MyIntersectionResultLineTriangleEx(); triangle.Triangle = triraw; triangle.IntersectionPointInObjectSpace = intersectionLocal; triangle.NormalInObjectSpace = normalLocal; triangle.IntersectionPointInWorldSpace = Vector3.Transform(intersectionLocal, ref worldMatrix); triangle.NormalInWorldSpace = Vector3.TransformNormal(normalLocal, worldMatrix); triangle.InputLineInObjectSpace = lineLocal; info.Triangle = triangle; if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW) { MyRenderProxy.DebugClearPersistentMessages(); MyRenderProxy.DebugDrawCapsule(info.Capsule.P0, info.Capsule.P1, info.Capsule.Radius, Color.Aqua, false, persistent: true); Vector3 p0Local = Vector3.Transform(info.Capsule.P0, ref worldMatrixInv); Vector3 p1Local = Vector3.Transform(info.Capsule.P1, ref worldMatrixInv); Vector3 p0LocalTrans = Vector3.Transform(p0Local, ref invBoneTrans); Vector3 p1LocalTrans = Vector3.Transform(p1Local, ref invBoneTrans); MyRenderProxy.DebugDrawCapsule(Vector3.Transform(p0LocalTrans, ref worldMatrix), Vector3.Transform(p1LocalTrans, ref worldMatrix), info.Capsule.Radius, Color.Brown, false, persistent: true); MyRenderProxy.DebugDrawLine3D(line.From, line.To, Color.Blue, Color.Red, false, true); MyRenderProxy.DebugDrawLine3D(lineTransWorld.From, lineTransWorld.To, Color.Green, Color.Yellow, false, true); MyRenderProxy.DebugDrawSphere(triangle.IntersectionPointInWorldSpace, 0.02f, Color.Red, 1, false, persistent: true); MyRenderProxy.DebugDrawAxis((MatrixD)boneTrans * WorldMatrix, 0.1f, false, true, true); } return true; } } return false; }
// Finds intersection between line and model, using octree for speedup the lookup. // Another speedup is, that first we check triangles that are directly in the node and then start // checking node's childs. But only if child node instersection is less than last know min distance. MyIntersectionResultLineTriangle?GetIntersectionWithLineRecursive(MyModel model, ref MyLine line, float?minDistanceUntilNow) { // Check if line intersects bounding box of this node and if distance to bounding box is less then last know min distance float?distanceToBoundingBox = MyUtils.GetLineBoundingBoxIntersection(ref line, ref m_boundingBox); if ((distanceToBoundingBox.HasValue == false) || ((minDistanceUntilNow != null) && (minDistanceUntilNow < distanceToBoundingBox.Value))) { return(null); } // Triangles that are directly in this node MyIntersectionResultLineTriangle?foundIntersection = null; // temporary variable for storing tirngle boundingbox info BoundingBox triangleBoundingBox = new BoundingBox(); MinerWars.AppCode.Game.Managers.MyPerformanceCounter.PerCameraDraw.RayCastTrianglesProcessed += m_triangleIndices.Count; for (int i = 0; i < m_triangleIndices.Count; i++) { int triangleIndex = m_triangleIndices[i]; model.GetTriangleBoundingBox(triangleIndex, ref triangleBoundingBox); // First test intersection of triangleVertexes's bounding box with line's bounding box. And only if they overlap or intersect, do further intersection tests. if (MyUtils.IsBoxIntersectingBox(triangleBoundingBox, ref line.BoundingBox) == true) { // See that we swaped vertex indices!! MyTriangle_Vertexes triangle; MyTriangleVertexIndices triangleIndices = model.Triangles[triangleIndex]; triangle.Vertex0 = model.GetVertex(triangleIndices.I0); triangle.Vertex1 = model.GetVertex(triangleIndices.I2); triangle.Vertex2 = model.GetVertex(triangleIndices.I1); float?distance = MyUtils.GetLineTriangleIntersection(ref line, ref triangle); // If intersection occured and if distance to intersection is closer to origin than any previous intersection if ((distance != null) && ((foundIntersection == null) || (distance.Value < foundIntersection.Value.Distance))) { Vector3 calculatedTriangleNormal = MyUtils.GetNormalVectorFromTriangle(ref triangle); // We need to remember original triangleVertexes coordinates (not transformed by world matrix) foundIntersection = new MyIntersectionResultLineTriangle(ref triangle, ref calculatedTriangleNormal, distance.Value); } } } // Get intersection with childs of this node if (m_childs != null) { for (int i = 0; i < m_childs.Count; i++) { MyIntersectionResultLineTriangle?childIntersection = m_childs[i].GetIntersectionWithLineRecursive(model, ref line, (foundIntersection == null) ? (float?)null : foundIntersection.Value.Distance); // If intersection occured and if distance to intersection is closer to origin than any previous intersection foundIntersection = MyIntersectionResultLineTriangle.GetCloserIntersection(ref foundIntersection, ref childIntersection); } } return(foundIntersection); }
private void GetCellLineIntersectionOctree(ref MyIntersectionResultLineTriangle? result, ref MyLine modelSpaceLine, ref float? minDistanceUntilNow, MyVoxelCacheCellData cachedDataCell, IntersectionFlags flags) { //MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("VoxelMap.ClearList Octree"); OctreeOverlapElementList.Clear(); //MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); if (cachedDataCell.Octree != null) { //MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("VoxelMap.LineIntersection Octree prun"); var ray = new Ray(modelSpaceLine.From, modelSpaceLine.Direction); cachedDataCell.Octree.GetIntersectionWithLine(ref ray, OctreeOverlapElementList); //cachedDataCell.Octree.GetAllTriangles(OctreeOverlapElementList); //MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); } //MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("VoxelMap.LineIntersection test tris Octree"); for (int j = 0; j < OctreeOverlapElementList.Count; j++) { var i = OctreeOverlapElementList[j]; if (cachedDataCell.VoxelTriangles == null) //probably not calculated yet continue; // this should never happen if (i >= cachedDataCell.VoxelTriangles.Length) { MyCommonDebugUtils.AssertDebug(i < cachedDataCell.VoxelTriangles.Length); continue; } MyVoxelTriangle voxelTriangle = cachedDataCell.VoxelTriangles[i]; MyVoxelVertex voxelVertex0 = cachedDataCell.VoxelVertices[voxelTriangle.VertexIndex0]; MyVoxelVertex voxelVertex1 = cachedDataCell.VoxelVertices[voxelTriangle.VertexIndex1]; MyVoxelVertex voxelVertex2 = cachedDataCell.VoxelVertices[voxelTriangle.VertexIndex2]; MyTriangle_Vertexes triangleVertices; triangleVertices.Vertex0 = voxelVertex0.Position; triangleVertices.Vertex1 = voxelVertex1.Position; triangleVertices.Vertex2 = voxelVertex2.Position; Vector3 calculatedTriangleNormal = MyUtils.GetNormalVectorFromTriangle(ref triangleVertices); //We dont want backside intersections if (((int)(flags & IntersectionFlags.FLIPPED_TRIANGLES) == 0) && Vector3.Dot(modelSpaceLine.Direction, calculatedTriangleNormal) > 0) continue; // draw triangles that were tested if (MyFakes.DRAW_TESTED_TRIANGLES_IN_VOXEL_LINE_INTERSECTION) { Vector3 avg02 = (voxelVertex0.Position + voxelVertex1.Position + voxelVertex2.Position) * 0.33333333333f * 0.2f; MyDebugDrawCachedLines.AddLine(PositionLeftBottomCorner + voxelVertex0.Position * 0.8f + avg02, PositionLeftBottomCorner + voxelVertex1.Position * 0.8f + avg02, Color.White, Color.White); MyDebugDrawCachedLines.AddLine(PositionLeftBottomCorner + voxelVertex1.Position * 0.8f + avg02, PositionLeftBottomCorner + voxelVertex2.Position * 0.8f + avg02, Color.White, Color.White); MyDebugDrawCachedLines.AddLine(PositionLeftBottomCorner + voxelVertex2.Position * 0.8f + avg02, PositionLeftBottomCorner + voxelVertex0.Position * 0.8f + avg02, Color.White, Color.White); } // AABB intersection test removed, AABB is tested inside BVH float? distance = MyUtils.GetLineTriangleIntersection(ref modelSpaceLine, ref triangleVertices); //if (distance != null) allIntersections.Add(distance.Value); // If intersection occured and if distance to intersection is closer to origin than any previous intersection if ((distance != null) && ((result == null) || (distance.Value < result.Value.Distance))) { minDistanceUntilNow = distance.Value; result = new MyIntersectionResultLineTriangle(ref triangleVertices, ref calculatedTriangleNormal, distance.Value); } } //MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); }
private MyIntersectionResultLineTriangle?GetIntersectionWithLineRecursive(MyModel model, ref Line line, double?minDistanceUntilNow) { double?nullable4; double?nullable1; float? lineBoundingBoxIntersection = MyUtils.GetLineBoundingBoxIntersection(ref line, ref this.m_boundingBox); if (lineBoundingBoxIntersection != null) { nullable1 = new double?((double)lineBoundingBoxIntersection.GetValueOrDefault()); } else { nullable4 = null; nullable1 = nullable4; } double?nullable = nullable1; if (nullable != null) { if (minDistanceUntilNow != null) { nullable4 = minDistanceUntilNow; double num = nullable.Value; if ((nullable4.GetValueOrDefault() < num) & (nullable4 != null)) { goto TR_0000; } } MyIntersectionResultLineTriangle?a = null; BoundingBox boundingBox = new BoundingBox(); BoundingBox box = BoundingBox.CreateInvalid().Include(line.From).Include(line.To); for (int i = 0; i < this.m_triangleIndices.Count; i++) { int triangleIndex = this.m_triangleIndices[i]; model.GetTriangleBoundingBox(triangleIndex, ref boundingBox); if (boundingBox.Intersects(ref box)) { MyTriangle_Vertices vertices; MyTriangleVertexIndices indices = model.Triangles[triangleIndex]; vertices.Vertex0 = model.GetVertex(indices.I0); vertices.Vertex1 = model.GetVertex(indices.I2); vertices.Vertex2 = model.GetVertex(indices.I1); float?lineTriangleIntersection = MyUtils.GetLineTriangleIntersection(ref line, ref vertices); if ((lineTriangleIntersection != null) && ((a == null) || (lineTriangleIntersection.Value < a.Value.Distance))) { Vector3 normalVectorFromTriangle = MyUtils.GetNormalVectorFromTriangle(ref vertices); a = new MyIntersectionResultLineTriangle(triangleIndex, ref vertices, ref normalVectorFromTriangle, lineTriangleIntersection.Value); } } } if (this.m_childs != null) { for (int j = 0; j < this.m_childs.Count; j++) { double?nullable8; if (a != null) { nullable8 = new double?((double)a.Value.Distance); } else { nullable4 = null; nullable8 = nullable4; } MyIntersectionResultLineTriangle?b = this.m_childs[j].GetIntersectionWithLineRecursive(model, ref line, nullable8); a = MyIntersectionResultLineTriangle.GetCloserIntersection(ref a, ref b); } } return(a); } TR_0000: return(null); }