// Actually, this function marks even cubes around the block to make sure that any changes caused in their triangles // will be reflected in the navigation mesh. public void MarkBlockChanged(MySlimBlock block) { Vector3I min = block.Min - Vector3I.One; Vector3I max = block.Max + Vector3I.One; Vector3I pos = min; for (var it = new Vector3I.RangeIterator(ref block.Min, ref block.Max); it.IsValid(); it.GetNext(out pos)) { m_changedCubes.Add(pos); } Vector3I minCell = CubeToCell(ref min); Vector3I maxCell = CubeToCell(ref max); pos = minCell; for (var it = new Vector3I.RangeIterator(ref minCell, ref maxCell); it.IsValid(); it.GetNext(out pos)) { m_changedCells.Add(pos); MyCellCoord cellCoord = new MyCellCoord(0, pos); ulong packedCell = cellCoord.PackId64(); TryClearCell(packedCell); } }
public IMyClipmapCell CreateCell(MyClipmapScaleEnum scaleGroup, MyCellCoord cellCoord, ref MatrixD worldMatrix) { var cell = new MyClipmapCellProxy(cellCoord, ref worldMatrix, m_massiveCenter, m_massiveRadius, m_renderFlags); cell.SetVisibility(false); cell.ScaleGroup = scaleGroup; return cell; }
public MyRenderVoxelCell(MyClipmapScaleEnum scaleGroup, MyCellCoord coord, ref MatrixD worldMatrix) : base(0, "MyRenderVoxelCell", RenderFlags.Visible | RenderFlags.CastShadows, CullingOptions.VoxelMap) { m_scaleGroup = scaleGroup; m_coord = coord; m_worldMatrix = worldMatrix; m_fakeVoxelMaterial.DrawTechnique = MyMeshDrawTechnique.VOXEL_MAP; }
public MyRenderVoxelCellBackground(MyCellCoord coord, ref MatrixD worldMatrix, Vector3D position, float atmoshpereRadius, float planetRadius, bool hasAtmosphere) : base(MyClipmapScaleEnum.Massive, coord, ref worldMatrix) { m_atmosphereRadius = atmoshpereRadius; m_planetRadius = planetRadius; m_hasAtmosphere = hasAtmosphere; m_position = position; m_leftCornerPositionOffset = worldMatrix.Translation -position; }
IMyClipmapCell IMyClipmapCellHandler.CreateCell(MyClipmapScaleEnum scaleGroup, MyCellCoord cellCoord, ref MatrixD worldMatrix) { switch (scaleGroup) { case MyClipmapScaleEnum.Normal: return new MyRenderVoxelCell(scaleGroup, cellCoord, ref worldMatrix); default: throw new InvalidBranchException(); } }
internal MyClipmapCellProxy(MyCellCoord cellCoord, ref VRageMath.MatrixD worldMatrix, RenderFlags additionalFlags = 0) { m_worldMatrix = worldMatrix; m_actor = MyActorFactory.CreateSceneObject(); m_actor.SetMatrix(ref worldMatrix); m_actor.AddComponent(MyComponentFactory<MyFoliageComponent>.Create()); m_lod = cellCoord.Lod; Mesh = MyMeshes.CreateVoxelCell(cellCoord.CoordInLod, cellCoord.Lod); m_actor.GetRenderable().SetModel(Mesh); m_actor.GetRenderable().m_additionalFlags = MyProxiesFactory.GetRenderableProxyFlags(additionalFlags); }
IMyClipmapCell IMyClipmapCellHandler.CreateCell(MyClipmapScaleEnum scaleGroup, MyCellCoord cellCoord, ref MatrixD worldMatrix) { switch (scaleGroup) { case MyClipmapScaleEnum.Normal: return new MyRenderVoxelCell(scaleGroup, cellCoord, ref worldMatrix); case MyClipmapScaleEnum.Massive: return new MyRenderVoxelCellBackground(cellCoord, ref worldMatrix, m_position, m_atmosphereRadius, m_planetRadius, m_hasAtmosphere); default: throw new InvalidBranchException(); } }
internal MyClipmapCellProxy(MyCellCoord cellCoord, ref VRageMath.Matrix worldMatrix) { m_worldMatrix = worldMatrix; m_actor = MyActorFactory.CreateSceneObject(); //m_mesh = new MyVoxelMesh(cellCoord.CoordInLod, cellCoord.Lod, ""); //m_actor.GetRenderable().SetModel(m_mesh); m_actor.SetMatrix(ref worldMatrix); m_actor.AddComponent(MyComponentFactory<MyFoliageComponent>.Create()); m_lod = cellCoord.Lod; Mesh = MyMeshes.CreateVoxelCell(cellCoord.CoordInLod, cellCoord.Lod); m_actor.GetRenderable().SetModel(Mesh); m_discardingOn = false; }
internal void InvalidateRange(Vector3I lodMin, Vector3I lodMax) { var cell = new MyCellCoord(m_lodIndex, lodMin); for (var it = new Vector3I.RangeIterator(ref lodMin, ref lodMax); it.IsValid(); it.GetNext(out cell.CoordInLod)) { CellData data; var id = cell.PackId64(); using (m_storedCellDataLock.AcquireSharedUsing()) { if (m_storedCellData.TryGetValue(id, out data)) { data.State = CellState.Invalid; } } } }
public static void RenderCellCoordToLocalAABB(ref MyCellCoord renderCell, out BoundingBoxD localAABB) { Vector3D localMinCorner; RenderCellCoordToLocalPosition(ref renderCell, out localMinCorner); localAABB = new BoundingBoxD(localMinCorner, localMinCorner + RenderCellSizeInMeters(renderCell.Lod)); }
internal void DoClipping(Vector3D localPosition, float farPlaneDistance, RequestCollector collector) { MyClipmap.ComputeLodViewBounds(m_parent.m_scaleGroup, m_lodIndex, out m_nearDistance, out m_farDistance); m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance; if (!m_fitsInFrustum) return; Vector3I min, max; { var minD = localPosition - m_farDistance; var maxD = localPosition + m_farDistance; MyVoxelCoordSystems.LocalPositionToRenderCellCoord(ref minD, out min); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(ref maxD, out max); Vector3I.Max(ref min, ref Vector3I.Zero, out min); Vector3I.Max(ref max, ref Vector3I.Zero, out max); min >>= m_lodIndex; max >>= m_lodIndex; Vector3I.Min(ref min, ref m_lodSizeMinusOne, out min); Vector3I.Min(ref max, ref m_lodSizeMinusOne, out max); } if (m_lastMin == min && m_lastMax == max && !m_parent.m_updateClipping) return; m_lastMin = min; m_lastMax = max; LodLevel parentLod, childLod; GetNearbyLodLevels(out parentLod, out childLod); // Moves cells which are still needed from one collection to another. // All that is left behind is unloaded as no longer needed. // Move everything in range to collection of next stored cells. MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); MyCellCoord cell = new MyCellCoord(m_lodIndex, ref min); for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out cell.CoordInLod)) { if (!WasAncestorCellLoaded(parentLod, ref cell)) continue; var cellId = cell.PackId64(); CellData data; if (m_clippedCells.TryGetValue(cellId, out data)) m_clippedCells.Remove(cellId); else data = new CellData(); if (data.State == CellState.Invalid) { collector.AddRequest(cellId, data.WasLoaded); data.State = CellState.Pending; } m_storedCellData.Add(cellId, data); } }
public void Submit() { ProfilerShort.Begin("RequestCollector.Submit"); MyCellCoord cell = default(MyCellCoord); foreach (var cellId in m_cancelRequests) { cell.SetUnpack(cellId); MyRenderProxy.CancelClipmapCell(m_clipmapId, cell); bool removed = m_sentRequests.Remove(cellId); Debug.Assert(removed); } foreach (var request in m_unsentRequests) { m_sentRequests.Add(request.Key); cell.SetUnpack(request.Key); MyRenderProxy.RequireClipmapCell(m_clipmapId, cell, true, request.Value.PriorityFunc, request.Value.DebugDraw); } m_unsentRequests.Clear(); //foreach (var highPriorityRequest in m_unsentRequestsHigh) //{ // cell.SetUnpack(highPriorityRequest); // MyRenderProxy.RequireClipmapCell(m_clipmapId, cell, highPriority: true); //} //m_unsentRequestsHigh.Clear(); int addedCount = 0; for (int i = m_unsentRequestsLow.Length - 1; i >= 0; i--) { var unsent = m_unsentRequestsLow[i]; while (0 < unsent.Count)// && m_sentRequests.Count < m_maxRequests*1000) { var pair = unsent.FirstPair(); var cellId = pair.Key; var hs = new HashSet <object>(); cell.SetUnpack(cellId); // Do Z-order style iteration of siblings that also need to // be requested. This ensures faster processing of cells and // shorter time when both lods are rendered. var baseCoord = (cell.CoordInLod >> 1) << 1; var offset = Vector3I.Zero; for (var it = new Vector3I.RangeIterator(ref Vector3I.Zero, ref Vector3I.One); it.IsValid(); it.GetNext(out offset)) { cell.CoordInLod = baseCoord + offset; cellId = cell.PackId64(); if (!unsent.Remove(cellId)) { continue; } Debug.Assert(!m_cancelRequests.Contains(cellId)); MyRenderProxy.RequireClipmapCell(m_clipmapId, cell, false, pair.Value.PriorityFunc, pair.Value.DebugDraw); bool added = m_sentRequests.Add(cellId); Debug.Assert(added); addedCount++; } } // When set reaches reasonably small size, stop freeing memory //if (unsent.Count > 100) no trim for dictionary :( // unsent.TrimExcess(); } m_cancelRequests.Clear(); ProfilerShort.End(); }
private MyNavigationTriangle GetClosestNavigationTriangle(ref Vector3 point, ref float closestDistanceSq) { // TODO: When point is completely away (according to BB), return null MyNavigationTriangle closestTriangle = null; // Convert from world matrix local coords to LeftBottomCorner-based coords Vector3 lbcPoint = point + (m_voxelMap.PositionComp.GetPosition() - m_voxelMap.PositionLeftBottomCorner); Vector3I closestCellCorner = Vector3I.Round(lbcPoint / m_cellSize); for (int i = 0; i < 8; ++i) { Vector3I cell = closestCellCorner + m_cornerOffsets[i]; if (!m_processedCells.Contains(cell)) continue; MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cell); ulong packedCoord = coord.PackId64(); MyIntervalList triList = m_higherLevelHelper.TryGetTriangleList(packedCoord); if (triList == null) continue; foreach (var triIndex in triList) { MyNavigationTriangle tri = GetTriangle(triIndex); // TODO: Use triangle centers so far float distSq = Vector3.DistanceSquared(tri.Center, point); if (distSq < closestDistanceSq) { closestDistanceSq = distSq; closestTriangle = tri; } } } return closestTriangle; }
private bool AddCell(Vector3I cellPos) { MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cellPos); var generatedMesh = MyPrecalcComponent.IsoMesher.Precalc(new MyIsoMesherArgs() { Storage = m_voxelMap.Storage, GeometryCell = coord, }); if (generatedMesh == null) { m_processedCells.Add(ref cellPos); m_higherLevelHelper.AddExplored(ref cellPos); return false; } ulong packedCoord = coord.PackId64(); List<DebugDrawEdge> debugEdgesList = new List<DebugDrawEdge>(); m_debugCellEdges[packedCoord] = debugEdgesList; MyVoxelPathfinding.CellId cellId = new MyVoxelPathfinding.CellId() { VoxelMap = m_voxelMap, Pos = cellPos }; MyTrace.Send(TraceWindow.Ai, "Adding cell " + cellPos); m_connectionHelper.ClearCell(); m_vertexMapping.Init(generatedMesh.VerticesCount); // Prepare list of possibly intersecting cube grids for voxel-grid navmesh intersection testing Vector3D bbMin = m_voxelMap.PositionLeftBottomCorner + (m_cellSize * (new Vector3D(-0.125) + cellPos)); Vector3D bbMax = m_voxelMap.PositionLeftBottomCorner + (m_cellSize * (Vector3D.One + cellPos)); BoundingBoxD cellBB = new BoundingBoxD(bbMin, bbMax); m_tmpGridList.Clear(); m_navmeshCoordinator.PrepareVoxelTriangleTests(cellBB, m_tmpGridList); Vector3D voxelMapCenter = m_voxelMap.PositionComp.GetPosition(); Vector3 centerDisplacement = voxelMapCenter - m_voxelMap.PositionLeftBottomCorner; // This is needed for correct edge classification - to tell, whether the edges are inner or outer edges of the cell ProfilerShort.Begin("Triangle preprocessing"); for (int i = 0; i < generatedMesh.TrianglesCount; i++) { ushort a = generatedMesh.Triangles[i].VertexIndex0; ushort b = generatedMesh.Triangles[i].VertexIndex1; ushort c = generatedMesh.Triangles[i].VertexIndex2; Vector3 aPos, bPos, cPos; Vector3 vert; generatedMesh.GetUnpackedPosition(a, out vert); aPos = vert - centerDisplacement; generatedMesh.GetUnpackedPosition(b, out vert); bPos = vert - centerDisplacement; generatedMesh.GetUnpackedPosition(c, out vert); cPos = vert - centerDisplacement; bool invalidTriangle = false; if ((bPos - aPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ) { m_vertexMapping.Union(a, b); invalidTriangle = true; } if ((cPos - aPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ) { m_vertexMapping.Union(a, c); invalidTriangle = true; } if ((cPos - bPos).LengthSquared() <= MyVoxelConnectionHelper.OUTER_EDGE_EPSILON_SQ) { m_vertexMapping.Union(b, c); invalidTriangle = true; } if (invalidTriangle) continue; m_connectionHelper.PreprocessInnerEdge(a, b); m_connectionHelper.PreprocessInnerEdge(b, c); m_connectionHelper.PreprocessInnerEdge(c, a); } ProfilerShort.End(); ProfilerShort.Begin("Free face sorting"); // Ensure that the faces have increasing index numbers Mesh.SortFreeFaces(); ProfilerShort.End(); m_higherLevelHelper.OpenNewCell(coord); ProfilerShort.Begin("Adding triangles"); for (int i = 0; i < generatedMesh.TrianglesCount; i++) { ushort a = generatedMesh.Triangles[i].VertexIndex0; ushort b = generatedMesh.Triangles[i].VertexIndex1; ushort c = generatedMesh.Triangles[i].VertexIndex2; ushort setA = (ushort)m_vertexMapping.Find(a); ushort setB = (ushort)m_vertexMapping.Find(b); ushort setC = (ushort)m_vertexMapping.Find(c); if (setA == setB || setB == setC || setA == setC) continue; Vector3 aPos, bPos, cPos; Vector3 vert; generatedMesh.GetUnpackedPosition(a, out vert); aPos = vert - centerDisplacement; generatedMesh.GetUnpackedPosition(b, out vert); bPos = vert - centerDisplacement; generatedMesh.GetUnpackedPosition(c, out vert); cPos = vert - centerDisplacement; if (MyPerGameSettings.NavmeshPresumesDownwardGravity) { Vector3 normal = (cPos - aPos).Cross(bPos - aPos); normal.Normalize(); if (normal.Dot(ref Vector3.Up) <= Math.Cos(MathHelper.ToRadians(54.0f))) continue; } Vector3D aTformed = aPos + voxelMapCenter; Vector3D bTformed = bPos + voxelMapCenter; Vector3D cTformed = cPos + voxelMapCenter; bool intersecting = false; m_tmpLinkCandidates.Clear(); m_navmeshCoordinator.TestVoxelNavmeshTriangle(ref aTformed, ref bTformed, ref cTformed, m_tmpGridList, m_tmpLinkCandidates, out intersecting); if (intersecting) { m_tmpLinkCandidates.Clear(); continue; } if (!m_connectionHelper.IsInnerEdge(a, b)) debugEdgesList.Add(new DebugDrawEdge(aTformed, bTformed)); if (!m_connectionHelper.IsInnerEdge(b, c)) debugEdgesList.Add(new DebugDrawEdge(bTformed, cTformed)); if (!m_connectionHelper.IsInnerEdge(c, a)) debugEdgesList.Add(new DebugDrawEdge(cTformed, aTformed)); int edgeAB = m_connectionHelper.TryGetAndRemoveEdgeIndex(b, a, ref bPos, ref aPos); int edgeBC = m_connectionHelper.TryGetAndRemoveEdgeIndex(c, b, ref cPos, ref bPos); int edgeCA = m_connectionHelper.TryGetAndRemoveEdgeIndex(a, c, ref aPos, ref cPos); int formerAB = edgeAB; int formerBC = edgeBC; int formerCA = edgeCA; ProfilerShort.Begin("AddTriangle"); var tri = AddTriangle(ref aPos, ref bPos, ref cPos, ref edgeAB, ref edgeBC, ref edgeCA); ProfilerShort.End(); CheckMeshConsistency(); m_higherLevelHelper.AddTriangle(tri.Index); if (formerAB == -1) m_connectionHelper.AddEdgeIndex(a, b, ref aPos, ref bPos, edgeAB); if (formerBC == -1) m_connectionHelper.AddEdgeIndex(b, c, ref bPos, ref cPos, edgeBC); if (formerCA == -1) m_connectionHelper.AddEdgeIndex(c, a, ref cPos, ref aPos, edgeCA); // TODO: Instead of this, just add the tri into a list of tris that want to connect with the link candidates //m_navmeshCoordinator.TryAddVoxelNavmeshLinks(tri, cellId, m_tmpLinkCandidates); foreach (var candidate in m_tmpLinkCandidates) { List<MyNavigationPrimitive> primitives = null; if (!m_tmpCubeLinkCandidates.TryGetValue(candidate, out primitives)) { primitives = m_primitiveListPool.Allocate(); m_tmpCubeLinkCandidates.Add(candidate, primitives); } primitives.Add(tri); } m_tmpLinkCandidates.Clear(); } ProfilerShort.End(); m_tmpGridList.Clear(); m_connectionHelper.ClearCell(); m_vertexMapping.Clear(); Debug.Assert(!m_processedCells.Contains(ref cellPos)); m_processedCells.Add(ref cellPos); m_higherLevelHelper.AddExplored(ref cellPos); // Find connected components in the current cell's subgraph of the navigation mesh m_higherLevelHelper.ProcessCellComponents(); m_higherLevelHelper.CloseCell(); // Create navmesh links using the navmesh coordinator, taking into consideration the high level components m_navmeshCoordinator.TryAddVoxelNavmeshLinks2(cellId, m_tmpCubeLinkCandidates); m_navmeshCoordinator.UpdateVoxelNavmeshCellHighLevelLinks(cellId); foreach (var candidate in m_tmpCubeLinkCandidates) { candidate.Value.Clear(); m_primitiveListPool.Deallocate(candidate.Value); } m_tmpCubeLinkCandidates.Clear(); return true; }
public bool Intersects(ref BoundingSphereD localSphere) { MyPrecalcComponent.AssertUpdateThread(); // Get min and max cell coordinate where boundingBox can fit BoundingBoxD sphereBoundingBox = BoundingBoxD.CreateInvalid(); sphereBoundingBox.Include(ref localSphere); Vector3I cellCoordMin, cellCoordMax; { Vector3D minD = sphereBoundingBox.Min; Vector3D maxD = sphereBoundingBox.Max; MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref minD, out cellCoordMin); MyVoxelCoordSystems.LocalPositionToGeometryCellCoord(ref maxD, out cellCoordMax); } // Fix min and max cell coordinates so they don't overlap the voxelmap ClampCellCoord(ref cellCoordMin); ClampCellCoord(ref cellCoordMax); MyCellCoord cell = new MyCellCoord(); for (cell.CoordInLod.X = cellCoordMin.X; cell.CoordInLod.X <= cellCoordMax.X; cell.CoordInLod.X++) { for (cell.CoordInLod.Y = cellCoordMin.Y; cell.CoordInLod.Y <= cellCoordMax.Y; cell.CoordInLod.Y++) { for (cell.CoordInLod.Z = cellCoordMin.Z; cell.CoordInLod.Z <= cellCoordMax.Z; cell.CoordInLod.Z++) { // If no overlap between bounding box of data cell and the sphere BoundingBox cellBoundingBox; MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref cell.CoordInLod, out cellBoundingBox); if (cellBoundingBox.Intersects(ref localSphere) == false) continue; // 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 cachedData = GetCell(ref cell); if (cachedData == null) continue; for (int i = 0; i < cachedData.VoxelTrianglesCount; i++) { MyVoxelTriangle voxelTriangle = cachedData.VoxelTriangles[i]; MyTriangle_Vertexes triangle; cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex0, out triangle.Vertex0); cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex1, out triangle.Vertex1); cachedData.GetUnpackedPosition(voxelTriangle.VertexIndex2, out triangle.Vertex2); BoundingBox localTriangleAABB = BoundingBox.CreateInvalid(); localTriangleAABB.Include(ref triangle.Vertex0); localTriangleAABB.Include(ref triangle.Vertex1); localTriangleAABB.Include(ref triangle.Vertex2); // First test intersection of triangle's bounding box with line's bounding box. And only if they overlap or intersect, do further intersection tests. if (localTriangleAABB.Intersects(ref localSphere)) { PlaneD trianglePlane = new PlaneD(triangle.Vertex0, triangle.Vertex1, triangle.Vertex2); if (MyUtils.GetSphereTriangleIntersection(ref localSphere, ref trianglePlane, ref triangle) != null) { // If intersection found - we are finished. We don't need to look for more. return true; } } } } } } return false; }
public static void RenderCellCoordToLocalPosition(ref MyCellCoord renderCell, out Vector3D localPosition) { var scale = 1 << renderCell.Lod; localPosition = renderCell.CoordInLod * scale * MyVoxelConstants.RENDER_CELL_SIZE_IN_METRES; }
public static void RenderCellCoordToWorldPosition(Vector3D referenceVoxelMapPosition, ref MyCellCoord renderCell, out Vector3D worldPosition) { Vector3D localPosition; RenderCellCoordToLocalPosition(ref renderCell, out localPosition); LocalPositionToWorldPosition(referenceVoxelMapPosition, ref localPosition, out worldPosition); }
public static void GeometryCellCoordToLocalPosition(ref MyCellCoord geometryCellCoord, out Vector3D localPosition) { localPosition = geometryCellCoord.CoordInLod * MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_METRES * (1 << geometryCellCoord.Lod); }
public static void RenderCellCoordToWorldAABB(Vector3D referenceVoxelMapPosition, ref MyCellCoord renderCell, out BoundingBoxD worldAABB) { RenderCellCoordToLocalAABB(ref renderCell, out worldAABB); worldAABB = worldAABB.Translate(referenceVoxelMapPosition); }
public static void GeometryCellCoordToWorldAABB(Vector3D referenceVoxelMapPosition, ref MyCellCoord geometryCellCoord, out BoundingBoxD worldAABB) { Vector3D center; GeometryCellCoordToLocalPosition(ref geometryCellCoord, out center); LocalPositionToWorldPosition(referenceVoxelMapPosition, ref center, out center); worldAABB = new BoundingBoxD(center, center + MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_METRES * (1 << geometryCellCoord.Lod)); }
public static void RenderCellCoordToLocalPosition(ref MyCellCoord renderCell, out Vector3D localPosition) { localPosition = renderCell.CoordInLod * RenderCellSizeInMeters(renderCell.Lod); }
/// <summary> /// Recursive clipping function requests cells in provided range and /// cells needed from parent to wrap the lod safely /// </summary> /// <param name="collector"></param> /// <param name="it0">requested range</param> /// <param name="ignore">inner range filled by children</param> private void DoClipping(RequestCollector collector, Vector3I min, Vector3I max, ref BoundingBox ignore) { LodLevel parentLod, clevel; GetNearbyLodLevels(out parentLod, out clevel); MyCellCoord cell = new MyCellCoord(m_lodIndex, Vector3I.Zero); //if (collector.SentRequestsEmpty) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); } var it0 = new Vector3I.RangeIterator(ref min, ref max); cell.CoordInLod = it0.Current; var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(cell.Lod); var parentCell = parentLod != null ? new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent) : cell; var parentIgnore = new BoundingBox(parentCell.CoordInLod, parentCell.CoordInLod); BoundingBox bb = new BoundingBox(cell.CoordInLod, cell.CoordInLod); for (; it0.IsValid(); it0.GetNext(out cell.CoordInLod)) //cells to be loaded { if (ignore.Contains((Vector3)cell.CoordInLod) == ContainmentType.Contains) { continue; //lower lod requested } if (parentLod != null) //get also their lodcell mates { parentCell = new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent); var it = GetChildrenCoords(this, ref parentCell); bb.Include(it); parentIgnore.Max = parentCell.CoordInLod; } } if (parentLod != null) { Vector3I parentMinI = Vector3I.Round(parentIgnore.Min - Vector3.One); Vector3I parentMaxI = Vector3I.Round(parentIgnore.Max + Vector3.One); //Vector3I.Clamp(ref parentMinI, ref Vector3I.Zero, ref m_lodSizeMinusOne, out parentMinI); //Vector3I.Clamp(ref parentMaxI, ref Vector3I.Zero, ref m_lodSizeMinusOne, out parentMaxI); var parentIterator = new Vector3I.RangeIterator(ref parentMinI, ref parentMaxI); parentLod.DoClipping(collector, parentMinI, parentMaxI, ref parentIgnore); } Vector3I start, end; start = Vector3I.Round(bb.Min); end = Vector3I.Round(bb.Max); Vector3I.Clamp(ref start, ref Vector3I.Zero, ref m_lodSizeMinusOne, out start); Vector3I.Clamp(ref end, ref Vector3I.Zero, ref m_lodSizeMinusOne, out end); it0 = new Vector3I.RangeIterator(ref start, ref end); cell.CoordInLod = it0.Current; for (; it0.IsValid(); it0.GetNext(out cell.CoordInLod)) //cells to be loaded { if (ignore.Contains((Vector3)cell.CoordInLod) == ContainmentType.Contains) { continue; //lower lod requested } var cellId = cell.PackId64(); CellData data; if (m_clippedCells.TryGetValue(cellId, out data)) { m_clippedCells.Remove(cellId); } else { var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); data = CellsCache.Read(clipmapCellId); if (data == null) //cache miss { data = new CellData(); ClippingCacheMisses++; } else { //cache hit ClippingCacheHits++; data.InScene = false; if (data.Cell != null) { m_nonEmptyCells[cellId] = data; } } } if (data.State == CellState.Invalid) { if (!TryAddCellRequest(collector, parentLod, cell, cellId, data)) { continue; } } if (!m_storedCellData.ContainsKey(cellId)) { m_storedCellData.Add(cellId, data); } } }
private void UnclipCell(RequestCollector collector, MyCellCoord cell, bool isVisible) { var cellId = cell.PackId64(); var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); CellData data; if (isVisible) { bool highPriority = true; if (m_clippedCells.TryGetValue(cellId, out data)) { m_clippedCells.Remove(cellId); } else { highPriority = false; CellBlendData blendData; if (!m_blendedCells.TryGetValue(cellId, out blendData)) { data = CellsCache.Read(clipmapCellId); if (data == null) //cache miss { data = new CellData(); ClippingCacheMisses++; } else { //cache hit ClippingCacheHits++; //System.Diagnostics.Debug.Assert((!data.InScene && data.Cell != null) || data.Cell == null, "Not allowed cell state"); data.InScene = false; if (data.Cell != null) { m_nonEmptyCells[cellId] = data; } } } else { data = blendData.CellData; if (blendData.State == BlendState.Removing) { blendData.UndoAfterFinish = true; } if (data.Cell != null) { m_nonEmptyCells[cellId] = data; } } } if (data.State == CellState.Invalid) { if (MyClipmap.UseQueries) { BoundingBoxD bbd; MyVoxelCoordSystems.RenderCellCoordToLocalAABB(ref cell, out bbd); BoundingBox bb = new BoundingBox(bbd); if (m_clipmap.m_prunningFunc == null || m_clipmap.m_prunningFunc(ref bb, false) == ContainmentType.Intersects) { collector.AddRequest(cellId, data, highPriority); } else { data.State = CellState.Loaded; data.WasLoaded = true; } } else { collector.AddRequest(cellId, data, highPriority); } } m_storedCellData.Add(cellId, data); data.ReadyInClipmap = true; data.ClippedOut = false; } else { if (!m_storedCellData.ContainsKey(cellId) && (!PendingCacheCellData.ContainsKey(clipmapCellId) || PendingCacheCellData[clipmapCellId].State == CellState.Invalid) && CellsCache.Read(clipmapCellId) == null) { if (!PendingCacheCellData.TryGetValue(clipmapCellId, out data)) { data = new CellData(); PendingCacheCellData.Add(clipmapCellId, data); } if (MyClipmap.UseQueries) { BoundingBoxD bbd; MyVoxelCoordSystems.RenderCellCoordToLocalAABB(ref cell, out bbd); BoundingBox bb = new BoundingBox(bbd); if (m_clipmap.m_prunningFunc == null || m_clipmap.m_prunningFunc(ref bb, false) == ContainmentType.Intersects) { data.State = CellState.Invalid; collector.AddRequest(cellId, data, false); } else { data.State = CellState.Loaded; data.WasLoaded = true; } } else { data.State = CellState.Invalid; collector.AddRequest(cellId, data, false); } } } }
internal void SetCellMesh(MyRenderMessageUpdateClipmapCell msg) { var cellId = msg.Metadata.Cell.PackId64(); CellData data; var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); // MyCellCoord cellc = new MyCellCoord(); // cellc.SetUnpack(cellId); //MyLog.Default.WriteLine("SetCellMesh Lod: " + cellc.Lod + " Coord: " + cellc.CoordInLod); if (m_storedCellData.TryGetValue(cellId, out data)) { PendingCacheCellData.Remove(clipmapCellId); if (data.State == CellState.Invalid) { // MyLog.Default.WriteLine("Invalid"); //Cell was invalidated while calculating from old data return; } if (data.Cell == null && msg.Batches.Count != 0) { //MyLog.Default.WriteLine("added to nonempty"); data.Cell = m_clipmap.m_cellHandler.CreateCell(m_clipmap.m_scaleGroup, msg.Metadata.Cell, ref m_clipmap.m_worldMatrix); System.Diagnostics.Debug.Assert(data.Cell != null, "Cell not created"); if (data.Cell != null) { if (data.Cell.IsValid()) { data.CellHandler = m_clipmap.m_cellHandler; m_nonEmptyCells[cellId] = data; } } } else if (data.Cell != null && msg.Batches.Count == 0) { //MyLog.Default.WriteLine("removed"); RemoveFromScene(cellId, data); m_nonEmptyCells.Remove(cellId); m_clipmap.m_cellHandler.DeleteCell(data.Cell); m_blendedCells.Remove(cellId); data.Cell = null; data.CellHandler = null; if (UseCache) { CellsCache.Remove(cellId); } } if (data.Cell != null) { //MyLog.Default.WriteLine("mesh updated"); if (data.Cell.IsValid()) { m_clipmap.m_cellHandler.UpdateMesh(data.Cell, msg); } } data.State = CellState.Loaded; data.WasLoaded = true; } else if (PendingCacheCellData.TryGetValue(clipmapCellId, out data)) { if (msg.Batches.Count != 0) { data.Cell = m_clipmap.m_cellHandler.CreateCell(m_clipmap.m_scaleGroup, msg.Metadata.Cell, ref m_clipmap.m_worldMatrix); m_clipmap.m_cellHandler.UpdateMesh(data.Cell, msg); data.CellHandler = m_clipmap.m_cellHandler; } CellsCache.Write(clipmapCellId, data); PendingCacheCellData.Remove(clipmapCellId); data.State = CellState.Loaded; data.WasLoaded = true; } }
private void SetEmpty(ref MyCellCoord cell, bool value) { UInt64 cacheKey; int bitIdx; ComputeIsEmptyLookup(cell, out cacheKey, out bitIdx); var cacheLine = m_isEmptyCache.Read(cacheKey); if (value) cacheLine |= ((ulong)1) << bitIdx; else cacheLine &= ~(((ulong)1) << bitIdx); m_isEmptyCache.Write(cacheKey, cacheLine); Debug.Assert(IsEmpty(ref cell) == value); }
public void DebugDraw() { //if (m_lodIndex > 5) // return; // if (m_lodIndex == 1) // { // float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex); // //var start = localFarCameraBox.Min; // //var end = localFarCameraBox.Max; // var start = m_localNearCameraBox.Min; // var end = m_localNearCameraBox.Max; // Vector3I coord = start; // Color nearColor = Color.Yellow; // Color farColor = Color.White; // var startF = m_localFarCameraBox.Min; // var endF = m_localFarCameraBox.Max; // Vector3I coordF = startF; //// for (var it = new Vector3I.RangeIterator(ref startF, ref endF); ////it.IsValid(); it.GetNext(out coordF)) //// { //// Vector3D min = Vector3D.Transform((Vector3D)(sizeInMetres * coordF), m_parent.m_worldMatrix); //// Vector3D max = Vector3D.Transform((Vector3D)(sizeInMetres * coordF + new Vector3(sizeInMetres)), m_parent.m_worldMatrix); //// BoundingBoxD aabb = new BoundingBoxD(min, max); //// MyRenderProxy.DebugDrawAABB(aabb, farColor, 1, 1, false); //// if (Vector3D.Distance(CameraFrustumGetter().Matrix.Translation, aabb.Center) < 200) //// MyRenderProxy.DebugDrawText3D(aabb.Center, coordF.ToString(), farColor, 0.5f, false); //// } // for (var it = new Vector3I.RangeIterator(ref start, ref end); //it.IsValid(); it.GetNext(out coord)) // { // Vector3D min = Vector3D.Transform((Vector3D)(sizeInMetres * coord), m_clipmap.m_worldMatrix); // Vector3D max = Vector3D.Transform((Vector3D)(sizeInMetres * coord + new Vector3(sizeInMetres)), m_clipmap.m_worldMatrix); // BoundingBoxD aabb = new BoundingBoxD(min, max); // MyRenderProxy.DebugDrawAABB(aabb, nearColor, 1, 1, false); // } // Vector3D center = Vector3D.Transform(m_localPosition, m_clipmap.m_worldMatrix); // MyRenderProxy.DebugDrawSphere(center, m_nearDistance, nearColor, 1, false); // MyRenderProxy.DebugDrawSphere(center, m_farDistance, farColor, 1, false); // } var camera = m_clipmap.LastCameraPosition; //if (m_lodIndex < 6) { float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex); Color color = LOD_COLORS[m_lodIndex] + new Vector4(0.2f); foreach (var cell in m_storedCellData) { if (!cell.Value.InScene) { continue; } MyCellCoord cellStr = new MyCellCoord(); cellStr.SetUnpack(cell.Key); var coordF = cellStr.CoordInLod; Vector3D min = Vector3D.Transform((Vector3D)(sizeInMetres * coordF), m_clipmap.m_worldMatrix); Vector3D max = Vector3D.Transform((Vector3D)(sizeInMetres * coordF + new Vector3(sizeInMetres)), m_clipmap.m_worldMatrix); BoundingBoxD aabb = new BoundingBoxD(min, max); double distance = Vector3D.Distance(camera, aabb.Center); //if (distance < sizeInMetres * 4) MyRenderProxy.DebugDrawAABB(aabb, color, 1, 1, true); if (distance < sizeInMetres * 2) { MyRenderProxy.DebugDrawText3D(aabb.Center, String.Format("{0}:{1}", m_lodIndex, coordF.ToString()), color, 0.7f, false); } } if (m_storedCellData.Count > 0) { Vector3D center = Vector3D.Transform(m_localPosition, m_clipmap.m_worldMatrix); //MyRenderProxy.DebugDrawSphere(center, m_farDistance, color, 1, false); } } }
public void InvalidateRange(Vector3I minVoxelChanged, Vector3I maxVoxelChanged) { minVoxelChanged -= MyPrecalcComponent.InvalidatedRangeInflate; maxVoxelChanged += MyPrecalcComponent.InvalidatedRangeInflate; m_voxelMap.Storage.ClampVoxelCoord(ref minVoxelChanged); m_voxelMap.Storage.ClampVoxelCoord(ref maxVoxelChanged); Vector3I minCell, maxCell; MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref minVoxelChanged, out minCell); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref maxVoxelChanged, out maxCell); Vector3I currentCell = minCell; for (var it = new Vector3I.RangeIterator(ref minCell, ref maxCell); it.IsValid(); it.GetNext(out currentCell)) { if (m_processedCells.Contains(ref currentCell)) { RemoveCell(currentCell); } MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, currentCell); m_higherLevelHelper.TryClearCell(coord.PackId64()); } }
internal void DoClipping(float camDistanceFromCenter, Vector3D localPosition, float farPlaneDistance, RequestCollector collector, bool frustumCulling, float rangeScale) { int lodIndex = m_lodIndex; if (!ShouldBeThisLodVisible(camDistanceFromCenter)) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); return; } m_localPosition = localPosition; MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, lodIndex, out m_nearDistance, out m_farDistance); farPlaneDistance *= rangeScale; m_farDistance *= rangeScale; m_nearDistance *= rangeScale; m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance; if (!m_fitsInFrustum && m_lodIndex == lodIndex) { return; } //var localFrustum = new BoundingFrustumD(CameraFrustumGetter().Matrix * m_parent.m_invWorldMatrix); var frustum = CameraFrustumGetter(); Vector3I min, max; // Vector3I ignoreMin, ignoreMax; var minD = m_localPosition - m_farDistance; var maxD = m_localPosition + m_farDistance; MyVoxelCoordSystems.LocalPositionToRenderCellCoord(lodIndex, ref minD, out min); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(lodIndex, ref maxD, out max); BoundingBoxI lodBox = new BoundingBoxI(Vector3I.Zero, Vector3I.Max(m_lodSizeMinusOne, Vector3I.Zero)); bool intersects = false; //bool intersectsNear = false; m_localFarCameraBox = new BoundingBoxI(min, max); m_localNearCameraBox = new BoundingBoxI(min, max); if (lodBox.Intersects(m_localFarCameraBox)) { intersects = true; var intersection = lodBox; intersection.IntersectWith(ref m_localFarCameraBox); min = intersection.Min; max = intersection.Max; //Optimize only LOD2 and higher by two lods, because neighbour cells shares border cells //if (m_lodIndex > 1) //{ // float lowerFar, lowerNear; // MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, m_lodIndex - 2, out lowerFar, out lowerNear); // var minNear = m_localPosition - (lowerNear - MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex) / 2); // var maxNear = m_localPosition + (lowerNear - MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex) / 2); // MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref minNear, out ignoreMin); // MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxNear, out ignoreMax); // m_localNearCameraBox = new BoundingBoxI(ignoreMin, ignoreMax); // if (lodBox.Intersects(m_localNearCameraBox)) // intersectsNear = false; //} } //if (m_lastMin == min && m_lastMax == max && !m_clipmap.m_updateClipping) // return; //m_lastMin = min; //m_lastMax = max; //LodLevel parentLod, childLod; //GetNearbyLodLevels(out parentLod, out childLod); // Moves cells which are still needed from one collection to another. // All that is left behind is unloaded as no longer needed. // Move everything in range to collection of next stored cells. if (frustumCulling) { MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); } if (intersects) { float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(lodIndex); MyCellCoord cell = new MyCellCoord(lodIndex, ref min); for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out cell.CoordInLod)) { //if (intersectsNear && // m_localNearCameraBox.Contains(cell.CoordInLod) == ContainmentType.Contains) // continue; //if (frustumCulling) //{ // Vector3D minAABB = Vector3D.Transform((Vector3D)(sizeInMetres * (cell.CoordInLod - 2)), m_clipmap.m_worldMatrix); // Vector3D maxAABB = Vector3D.Transform((Vector3D)(sizeInMetres * (cell.CoordInLod + 2) + new Vector3(sizeInMetres)), m_clipmap.m_worldMatrix); // if (frustum.Contains(new BoundingBoxD(minAABB, maxAABB)) == ContainmentType.Disjoint) // { // m_outsideCells.Add(cell.CoordInLod); // continue; // } //} UnclipCell(collector, cell, true); } //cache cells around frustum if (collector.SentRequestsEmpty) { foreach (var outsideCell in m_outsideCells) { cell.CoordInLod = outsideCell; UnclipCell(collector, cell, frustumCulling); } } m_outsideCells.Clear(); } }
private bool RemoveCell(Vector3I cell) { if (!MyFakes.REMOVE_VOXEL_NAVMESH_CELLS) return true; Debug.Assert(m_processedCells.Contains(cell), "Removing a non-existent cell from the navmesh!"); if (!m_processedCells.Contains(cell)) return false; MyTrace.Send(TraceWindow.Ai, "Removing cell " + cell); ProfilerShort.Begin("Removing navmesh links"); MyVoxelPathfinding.CellId cellId = new MyVoxelPathfinding.CellId() { VoxelMap = m_voxelMap, Pos = cell }; m_navmeshCoordinator.RemoveVoxelNavmeshLinks(cellId); ProfilerShort.End(); ProfilerShort.Begin("Removing triangles"); MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cell); ulong packedCoord = coord.PackId64(); MyIntervalList triangleList = m_higherLevelHelper.TryGetTriangleList(packedCoord); if (triangleList != null) { foreach (var triangleIndex in triangleList) { RemoveTerrainTriangle(GetTriangle(triangleIndex)); } m_higherLevelHelper.ClearCachedCell(packedCoord); } ProfilerShort.End(); Debug.Assert(m_processedCells.Contains(ref cell)); m_processedCells.Remove(ref cell); return triangleList != null; }
/// <summary> /// Priority function for sorting render cell precalc jobs /// </summary> /// <param name="cellWorldPos"></param> /// <param name="parent"></param> /// <param name="parentCellId"></param> /// <param name="cell"></param> /// <returns></returns> int PriorityFunc(BoundingBoxD cellWorldPos, LodLevel parent, ulong parentCellId, MyCellCoord cell) { //not using priority now, only physics prefetch is prioritized before graphics return(int.MaxValue); //commented out since now we are not dependent on parent //if (parent != null)//topmost lod does not have parent //{ // //var coordCell = new MyCellCoord(); // //coordCell.SetUnpack(parentCellId); // //if (!AllSiblingsWereLoaded(ref coordCell))//doesnt improve holes and slows progression awfully // // return int.MaxValue; // CellData data; // if (!parent.m_storedCellData.TryGetValue(parentCellId, out data) || !data.WasLoaded) //we need loaded parent for blending lods // return int.MaxValue; //} //var cam = CameraMatrixGetter();//get current cam position ////float mult = m_lodIndex; //var dir = (cellWorldPos.Center - cam.Translation); //direction to camera //var length = dir.Length(); //var dot = (dir/length).Dot(cam.Forward); //dot with look direction //if (cellWorldPos.Contains(cam.Translation) != ContainmentType.Disjoint) //{//we are inside the cell so top priority // length = 1; //} ////commented out since now we are not dependent on parent ////else if (AnySiblingChildrenLoaded(ref cell)) //// mult = 0.1f; //we should speed up since sibling child cannot be rendered without us //length *= 1.5f - dot; //prioritize by view direction //const double intMax = (double)int.MaxValue; //return length > intMax ? (int)intMax : (int)length; }
private MyHighLevelPrimitive GetClosestHighLevelPrimitive(ref Vector3 point, ref float closestDistanceSq) { MyHighLevelPrimitive retval = null; // Convert from world matrix local coords to LeftBottomCorner-based coords Vector3 lbcPoint = point + (m_voxelMap.PositionComp.GetPosition() - m_voxelMap.PositionLeftBottomCorner); m_tmpIntList.Clear(); // Collect components from the eight closest cells Vector3I closestCellCorner = Vector3I.Round(lbcPoint / m_cellSize); for (int i = 0; i < 8; ++i) { Vector3I cell = closestCellCorner + m_cornerOffsets[i]; MyCellCoord coord = new MyCellCoord(NAVMESH_LOD, cell); ulong packedCoord = coord.PackId64(); m_higherLevelHelper.CollectComponents(packedCoord, m_tmpIntList); } foreach (int componentIndex in m_tmpIntList) { var hlPrimitive = m_higherLevel.GetPrimitive(componentIndex); Debug.Assert(hlPrimitive != null, "Couldnt' find a high-level primitive for the index given by higher level helper!"); if (hlPrimitive == null) continue; float distSq = Vector3.DistanceSquared(hlPrimitive.Position, point); if (distSq < closestDistanceSq) { closestDistanceSq = distSq; retval = hlPrimitive; } } m_tmpIntList.Clear(); return retval; }
internal void OnTaskComplete(MyCellCoord coord, HkBvCompressedMeshShape childShape) { Debug.Assert(RigidBody != null, "RigidBody in voxel physics is null! This must not happen."); if (RigidBody != null) { HkUniformGridShape shape = GetShape(coord.Lod); Debug.Assert(shape.Base.IsValid); shape.SetChild(coord.CoordInLod.X, coord.CoordInLod.Y, coord.CoordInLod.Z, childShape, HkReferencePolicy.None); //BoundingBoxD worldAabb; //MyVoxelCoordSystems.GeometryCellCoordToWorldAABB(m_voxelMap.PositionLeftBottomCorner, ref coord, out worldAabb); //VRageRender.MyRenderProxy.DebugDrawAABB(worldAabb, Color.Green, 1f, 1f, true); m_needsShapeUpdate = true; } }
private void AddVoxelMesh(MyVoxelBase voxelBase, IMyStorage storage, Dictionary<Vector3I, MyIsoMesh> cache, float border, Vector3D originPosition, MyOrientedBoundingBoxD obb, List<BoundingBoxD> bbList) { bool useCache = cache != null; if (useCache) CheckCacheValidity(); obb.HalfExtent += new Vector3D(border, 0, border); BoundingBoxD bb = obb.GetAABB(); int aabbSideSide = (int)Math.Round(bb.HalfExtents.Max() * 2); bb = new BoundingBoxD(bb.Min, bb.Min + aabbSideSide); bb.Translate(obb.Center - bb.Center); // For debug bbList.Add(new BoundingBoxD(bb.Min, bb.Max)); bb = (BoundingBoxD)bb.TransformFast(voxelBase.PositionComp.WorldMatrixInvScaled); bb.Translate(voxelBase.SizeInMetresHalf); Vector3I min = Vector3I.Round(bb.Min); Vector3I max = min + aabbSideSide; Vector3I geomMin, geomMax; MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref min, out geomMin); MyVoxelCoordSystems.VoxelCoordToGeometryCellCoord(ref max, out geomMax); var cullBox = obb; cullBox.Transform(voxelBase.PositionComp.WorldMatrixInvScaled); cullBox.Center += voxelBase.SizeInMetresHalf; ProfilerShort.Begin("WOOOORK"); Vector3I_RangeIterator it = new Vector3I_RangeIterator(ref geomMin, ref geomMax); MyCellCoord coord = new MyCellCoord(); BoundingBox localAabb; coord.Lod = NAVMESH_LOD; int hits = 0; MyIsoMesh gMesh; Vector3 offset = originPosition - voxelBase.PositionLeftBottomCorner; // Calculate rotation Vector3 gravityVector = -Vector3.Normalize(GameSystems.MyGravityProviderSystem.CalculateTotalGravityInPoint(originPosition)); Vector3 forwardVector = Vector3.CalculatePerpendicularVector(gravityVector); Quaternion quaternion = Quaternion.CreateFromForwardUp(forwardVector, gravityVector); Matrix rotation = Matrix.CreateFromQuaternion(Quaternion.Inverse(quaternion)); Matrix ownRotation = voxelBase.PositionComp.WorldMatrix.GetOrientation(); while (it.IsValid()) { ProfilerShort.Begin("ITERATOR"); if (useCache && cache.TryGetValue(it.Current, out gMesh)) { if (gMesh != null) { AddMeshTriangles(gMesh, offset, rotation, ownRotation); } it.MoveNext(); ProfilerShort.End(); continue; } coord.CoordInLod = it.Current; MyVoxelCoordSystems.GeometryCellCoordToLocalAABB(ref coord.CoordInLod, out localAabb); if (!cullBox.Intersects(ref localAabb)) { hits++; it.MoveNext(); ProfilerShort.End(); continue; } ProfilerShort.End(); var debugBB = new BoundingBoxD(localAabb.Min, localAabb.Max).Translate(-voxelBase.SizeInMetresHalf); bbList.Add(debugBB); ProfilerShort.Begin("Mesh Calc"); var voxelStart = coord.CoordInLod * MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS - 1; var voxelEnd = voxelStart + MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS //- 1 + 1 // overlap to neighbor so geometry is stitched together within same LOD + 1; // for eg. 9 vertices in row we need 9 + 1 samples (voxels) var generatedMesh = MyPrecalcComponent.IsoMesher.Precalc(storage, NAVMESH_LOD, voxelStart, voxelEnd, false, false, true); ProfilerShort.End(); if (useCache) cache[it.Current] = generatedMesh; if (generatedMesh != null) { ProfilerShort.Begin("Mesh NOT NULL"); AddMeshTriangles(generatedMesh, offset, rotation, ownRotation); ProfilerShort.End(); } it.MoveNext(); } ProfilerShort.End(); }
private bool TryAddCellRequest(RequestCollector collector, LodLevel parentLod, MyCellCoord cell, ulong cellId, CellData data) { var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(cell.Lod); var parentCell = parentLod != null ? new MyCellCoord(parentLod.m_lodIndex, cell.CoordInLod >> shiftToParent) : cell; BoundingBoxD worldAABB; MyVoxelCoordSystems.RenderCellCoordToWorldAABB(m_clipmap.m_worldMatrix.Translation, ref parentCell, out worldAABB); worldAABB.Inflate(-1.0f * m_lodIndex * m_lodIndex); var parentCellId = parentCell.PackId64(); //if (PriorityFunc(worldAABB.Center, parentLod, parentCellId) == int.MaxValue) //this cell would just slow down sorting, it will be added again if needed // return false; collector.AddRequest(cellId, data.WasLoaded, () => PriorityFunc(worldAABB, parentLod, parentCellId, cell), (c) => DebugDrawJob(c, worldAABB)); data.State = CellState.Pending; return(true); }
internal CellData GetCell(ref MyCellCoord cell) { MyPrecalcComponent.AssertUpdateThread(); bool isEmpty; CellData data; if (TryGetCell(cell, out isEmpty, out data)) { return data; } MyIsoMesh mesh; if (!TryGetMesh(cell, out isEmpty, out mesh)) { ProfilerShort.Begin("Cell precalc"); if (true) { var min = cell.CoordInLod << MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; var max = min + MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS; // overlap to neighbor; introduces extra data but it makes logic for raycasts simpler (no need to check neighbor cells) min -= 1; max += 2; mesh = MyPrecalcComponent.IsoMesher.Precalc(m_storage, 0, min, max, false, MyFakes.ENABLE_VOXEL_COMPUTED_OCCLUSION, true); } else { mesh = MyPrecalcComponent.IsoMesher.Precalc(new MyIsoMesherArgs() { Storage = m_storage, GeometryCell = cell, }); } ProfilerShort.End(); } if (mesh != null) { data = new CellData(); data.Init( mesh.PositionOffset, mesh.PositionScale, mesh.Positions.GetInternalArray(), mesh.VerticesCount, mesh.Triangles.GetInternalArray(), mesh.TrianglesCount); } if (cell.Lod == 0) { using (m_lock.AcquireExclusiveUsing()) { if (data != null) { var key = cell.PackId64(); m_cellsByCoordinate[key] = data; } else { SetEmpty(ref cell, true); } } } return data; }
private void ComputeIsEmptyLookup(MyCellCoord cell, out ulong outCacheKey, out int outBit) { var offset = cell.CoordInLod % 4; cell.CoordInLod >>= 2; Debug.Assert(offset.IsInsideInclusive(Vector3I.Zero, new Vector3I(3))); outCacheKey = cell.PackId64(); outBit = offset.X + 4 * (offset.Y + 4 * offset.Z); Debug.Assert((uint)outBit < 64u); }
private bool IsEmpty(ref MyCellCoord cell) { ulong cacheKey; int bitIdx; ComputeIsEmptyLookup(cell, out cacheKey, out bitIdx); var cacheLine = m_isEmptyCache.Read(cacheKey); return (cacheLine & ((ulong)1 << bitIdx)) != 0; }
private void RequestShapeBlockingInternal(int x, int y, int z, out HkBvCompressedMeshShape shape, out HkReferencePolicy refPolicy, bool lod1physics) { ProfilerShort.Begin("MyVoxelPhysicsBody.RequestShapeBlocking"); if (!m_bodiesInitialized) CreateRigidBodies(); int lod = lod1physics ? 1 : 0; var cellCoord = new MyCellCoord(lod, new Vector3I(x, y, z)); shape = (HkBvCompressedMeshShape)HkShape.Empty; // shape must take ownership, otherwise shapes created here will leak, since I can't remove reference refPolicy = HkReferencePolicy.TakeOwnership; MyPrecalcComponent.QueueJobCancel(m_workTracker, cellCoord); if (m_voxelMap.MarkedForClose) { ProfilerShort.End(); return; } if (MyDebugDrawSettings.DEBUG_DRAW_REQUEST_SHAPE_BLOCKING) { BoundingBoxD aabb; MyVoxelCoordSystems.GeometryCellCoordToWorldAABB(m_voxelMap.PositionLeftBottomCorner, ref cellCoord, out aabb); MyRenderProxy.DebugDrawAABB(aabb, lod1physics ? Color.Yellow : Color.Red, 1, 1, true); } ProfilerShort.Begin("Generating geometry"); MyIsoMesh geometryData = CreateMesh(m_voxelMap.Storage, cellCoord); ProfilerShort.End(); if (!MyIsoMesh.IsEmpty(geometryData)) { ProfilerShort.Begin("Shape from geometry"); shape = CreateShape(geometryData); m_needsShapeUpdate = true; ProfilerShort.End(); } ProfilerShort.End(); }
internal void DoClipping_Old(Vector3D localPosition, float farPlaneDistance, RequestCollector collector) { m_localPosition = localPosition; MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, m_lodIndex, out m_nearDistance, out m_farDistance); m_fitsInFrustum = (farPlaneDistance * 1.25f) > m_nearDistance; if (!m_fitsInFrustum) { return; } //var localFrustum = new BoundingFrustumD(CameraFrustumGetter().Matrix * m_parent.m_invWorldMatrix); var frustum = CameraFrustumGetter(); Vector3I min, max; Vector3I ignoreMin, ignoreMax; var minD = m_localPosition - m_farDistance; var maxD = m_localPosition + m_farDistance; MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref minD, out min); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxD, out max); BoundingBoxI lodBox = new BoundingBoxI(Vector3I.Zero, m_lodSizeMinusOne); bool intersects = false; bool intersectsNear = false; m_localFarCameraBox = new BoundingBoxI(min, max); m_localNearCameraBox = new BoundingBoxI(min, max); if (lodBox.Intersects(m_localFarCameraBox)) { intersects = true; var intersection = lodBox.Intersect(m_localFarCameraBox); min = intersection.Min; max = intersection.Max; //Optimize only LOD2 and higher by two lods, because neighbour cells shares border cells if (m_lodIndex > 1) { float lowerFar, lowerNear; MyClipmap.ComputeLodViewBounds(m_clipmap.m_scaleGroup, m_lodIndex - 2, out lowerFar, out lowerNear); var minNear = m_localPosition - (lowerNear - MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex) / 2); var maxNear = m_localPosition + (lowerNear - MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex) / 2); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref minNear, out ignoreMin); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxNear, out ignoreMax); m_localNearCameraBox = new BoundingBoxI(ignoreMin, ignoreMax); if (lodBox.Intersects(m_localNearCameraBox)) { intersectsNear = false; } } } if (m_lastMin == min && m_lastMax == max && !m_clipmap.m_updateClipping) { return; } m_lastMin = min; m_lastMax = max; LodLevel parentLod, childLod; GetNearbyLodLevels(out parentLod, out childLod); // Moves cells which are still needed from one collection to another. // All that is left behind is unloaded as no longer needed. // Move everything in range to collection of next stored cells. MyUtils.Swap(ref m_storedCellData, ref m_clippedCells); m_storedCellData.Clear(); if (intersects) { float sizeInMetres = MyVoxelCoordSystems.RenderCellSizeInMeters(m_lodIndex); MyCellCoord cell = new MyCellCoord(m_lodIndex, ref min); for (var it = new Vector3I.RangeIterator(ref min, ref max); it.IsValid(); it.GetNext(out cell.CoordInLod)) { if (intersectsNear && m_localNearCameraBox.Contains(cell.CoordInLod) == ContainmentType.Contains) { continue; } //if (!WasAncestorCellLoaded(parentLod, ref cell)) // continue; Vector3D minAABB = Vector3D.Transform((Vector3D)(sizeInMetres * (cell.CoordInLod - 2)), m_clipmap.m_worldMatrix); Vector3D maxAABB = Vector3D.Transform((Vector3D)(sizeInMetres * (cell.CoordInLod + 2) + new Vector3(sizeInMetres)), m_clipmap.m_worldMatrix); if (frustum.Contains(new BoundingBoxD(minAABB, maxAABB)) == ContainmentType.Disjoint) { continue; } var cellId = cell.PackId64(); CellData data; if (m_clippedCells.TryGetValue(cellId, out data)) { m_clippedCells.Remove(cellId); } else { var clipmapCellId = MyCellCoord.GetClipmapCellHash(m_clipmap.Id, cellId); data = CellsCache.Read(clipmapCellId); if (data == null) //cache miss { data = new CellData(); ClippingCacheMisses++; } else { //cache hit ClippingCacheHits++; //System.Diagnostics.Debug.Assert((!data.InScene && data.Cell != null) || data.Cell == null, "Not allowed cell state"); data.InScene = false; if (data.Cell != null) { m_nonEmptyCells[cellId] = data; } } } if (data.State == CellState.Invalid) { if (!TryAddCellRequest(collector, parentLod, cell, cellId, data)) { continue; } } m_storedCellData.Add(cellId, data); } } }
internal MyIsoMesh CreateMesh(IMyStorage storage, MyCellCoord coord) { // mk:NOTE This method must be thread safe. Called from worker threads. coord.CoordInLod += m_cellsOffset >> coord.Lod; if (m_voxelMap is MyVoxelPhysics) { var clipmapId = ((MyVoxelPhysics)m_voxelMap).Parent.Render.RenderObjectIDs[0]; var clipmapCellId = MyCellCoord.GetClipmapCellHash(clipmapId, coord.PackId64()); var isoMesh = MyPrecalcJobRender.IsoMeshCache.Read(clipmapCellId); if (isoMesh != null) { return isoMesh; } } var min = coord.CoordInLod << MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; var max = min + MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS; // overlap to neighbor; introduces extra data but it makes logic for raycasts and collisions simpler (no need to check neighbor cells) min -= 1; max += 2; return MyPrecalcComponent.IsoMesher.Precalc(storage, coord.Lod, min, max, false, false); }
/// <param name="minVoxelChanged">Inclusive min.</param> /// <param name="maxVoxelChanged">Inclusive max.</param> private void storage_RangeChanged(Vector3I minChanged, Vector3I maxChanged, MyStorageDataTypeFlags changedData) { MyPrecalcComponent.AssertUpdateThread(); ProfilerShort.Begin("MyVoxelGeometry.storage_RangeChanged"); minChanged -= MyPrecalcComponent.InvalidatedRangeInflate; maxChanged += MyPrecalcComponent.InvalidatedRangeInflate; m_storage.ClampVoxelCoord(ref minChanged); m_storage.ClampVoxelCoord(ref maxChanged); var minCellChanged = minChanged >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; var maxCellChanged = maxChanged >> MyVoxelConstants.GEOMETRY_CELL_SIZE_IN_VOXELS_BITS; using (m_lock.AcquireExclusiveUsing()) { if (minCellChanged == Vector3I.Zero && maxCellChanged == m_cellsCount - 1) { m_cellsByCoordinate.Clear(); m_coordinateToMesh.Clear(); m_isEmptyCache.Reset(); } else { MyCellCoord cell = new MyCellCoord(); cell.CoordInLod = minCellChanged; for (var it = new Vector3I_RangeIterator(ref minCellChanged, ref maxCellChanged); it.IsValid(); it.GetNext(out cell.CoordInLod)) { var key = cell.PackId64(); m_cellsByCoordinate.Remove(key); m_coordinateToMesh.Remove(key); SetEmpty(ref cell, false); } } } ProfilerShort.End(); }