private float?ProcessTriangle(int triangleIndex) { System.Diagnostics.Debug.Assert((int)m_flags != 0); MyTriangle_Vertexes triangle; MyTriangleVertexIndices triangleIndices = m_model.Triangles[triangleIndex]; m_model.GetVertex(triangleIndices.I0, triangleIndices.I2, triangleIndices.I1, out triangle.Vertex0, out triangle.Vertex1, out triangle.Vertex2); Vector3 calculatedTriangleNormal = MyUtils.GetNormalVectorFromTriangle(ref triangle); //We dont want backside intersections if (((int)(m_flags & IntersectionFlags.FLIPPED_TRIANGLES) == 0) && Vector3.Dot(m_line.Direction, calculatedTriangleNormal) > 0) { return(null); } Line lineF = (Line)m_line; float?distance = MyUtils.GetLineTriangleIntersection(ref lineF, ref triangle); if (distance.HasValue) { var result = new MyIntersectionResultLineTriangle(ref triangle, ref calculatedTriangleNormal, distance.Value); m_result.Add(result); } return(distance); }
public MyIntersectionResultLineTriangleEx(MyIntersectionResultLineTriangle triangle, IMyEntity entity, ref LineD line, Vector3D intersectionPointInWorldSpace, Vector3 normalInWorldSpace) { Triangle = triangle; Entity = entity; InputLineInObjectSpace = line; NormalInObjectSpace = NormalInWorldSpace = normalInWorldSpace; IntersectionPointInWorldSpace = intersectionPointInWorldSpace; IntersectionPointInObjectSpace = (Vector3)IntersectionPointInWorldSpace; }
// Find and return closer intersection of these two. If intersection is null then it's not really an intersection. public static MyIntersectionResultLineTriangle? GetCloserIntersection(ref MyIntersectionResultLineTriangle? a, ref MyIntersectionResultLineTriangle? b) { if (((a == null) && (b != null)) || ((a != null) && (b != null) && (b.Value.Distance < a.Value.Distance))) { // If only "b" contains valid intersection, or when it's closer than "a" return b; } else { // This will be returned also when ((a == null) && (b == null)) return a; } }
public MyIntersectionResultLineTriangleEx(MyIntersectionResultLineTriangle triangle, IMyEntity entity, ref LineD line) { Triangle = triangle; Entity = entity; InputLineInObjectSpace = line; NormalInObjectSpace = MyUtils.GetNormalVectorFromTriangle(ref Triangle.InputTriangle); IntersectionPointInObjectSpace = line.From + line.Direction * Triangle.Distance; if (Entity is IMyVoxelBase) { IntersectionPointInWorldSpace = (Vector3D)IntersectionPointInObjectSpace; NormalInWorldSpace = NormalInObjectSpace; // This will move intersection point from world space into voxel map's object space IntersectionPointInObjectSpace = IntersectionPointInObjectSpace - ((IMyVoxelBase)Entity).PositionLeftBottomCorner; } else { var worldMatrix = Entity.WorldMatrix; NormalInWorldSpace = (Vector3)MyUtils.GetTransformNormalNormalized((Vector3D)NormalInObjectSpace, ref worldMatrix); IntersectionPointInWorldSpace = Vector3D.Transform((Vector3D)IntersectionPointInObjectSpace, ref worldMatrix); } }
// 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 LineD line, double? minDistanceUntilNow) { // Check if line intersects bounding box of this node and if distance to bounding box is less then last know min distance Line lineF = (Line)line; double? distanceToBoundingBox = MyUtils.GetLineBoundingBoxIntersection(ref lineF, 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(); BoundingBox lineBB = BoundingBox.CreateInvalid(); lineBB = lineBB.Include(line.From); lineBB = lineBB.Include(line.To); 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 (triangleBoundingBox.Intersects(ref lineBB)) { // 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); double? distance = MyUtils.GetLineTriangleIntersection(ref lineF, 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) ? (double?)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 Line modelSpaceLine, ref float? minDistanceUntilNow, CellData cachedDataCell, IntersectionFlags flags) { m_overlapElementCache.Clear(); if (cachedDataCell.Octree != null) { Vector3 packedStart; cachedDataCell.GetPackedPosition(ref modelSpaceLine.From, out packedStart); var ray = new Ray(packedStart, modelSpaceLine.Direction); 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); //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) { 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; }