/// <param name="minCellLod0">Inclusive.</param> /// <param name="maxCellLod0">Inclusive.</param> public void InvalidateRange(Vector3I minCellLod0, Vector3I maxCellLod0) { //Debug.Print("InvalidateRange Clipmap: " + Id + " Min: " + minCellLod0 + " Max: " + maxCellLod0); if (minCellLod0 == Vector3I.Zero && maxCellLod0 == m_sizeLod0 - 1) { for (int lod = 0; lod < m_lodLevels.Length; ++lod) { m_lodLevels[lod].InvalidateAll(); } } else { for (int lod = 0; lod < m_lodLevels.Length; ++lod) { var shift = lod + MyVoxelCoordSystems.RenderCellSizeInLodVoxelsShiftDelta(lod); m_lodLevels[lod].InvalidateRange( minCellLod0 >> shift, maxCellLod0 >> shift); } } m_invalidated = 2; ResetClipping(); }
/// <summary> /// Checks only immediate children (any deeper would take too long). /// </summary> private static bool ChildrenWereLoaded(LodLevel childLod, ref MyCellCoord thisLodCell) { if (childLod == null) { return(false); } Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1); var childLodCell = new MyCellCoord(); childLodCell.Lod = childLod.m_lodIndex; var shiftToChild = MyVoxelCoordSystems.RenderCellSizeShiftToMoreDetailed(thisLodCell.Lod); var start = thisLodCell.CoordInLod << shiftToChild; var end = start + ((1 << shiftToChild) >> 1); Vector3I.Max(ref childLod.m_lodSizeMinusOne, ref Vector3I.Zero, out childLod.m_lodSizeMinusOne); Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end); childLodCell.CoordInLod = start; for (var it = new Vector3I.RangeIterator(ref start, ref end); it.IsValid(); it.GetNext(out childLodCell.CoordInLod)) { var key = childLodCell.PackId64(); CellData data; if (!childLod.m_storedCellData.TryGetValue(key, out data) || !data.WasLoaded) { return(false); } } return(true); }
internal void UpdateCellsInScene(Vector3D localPosition) { LodLevel parentLod, childLod; GetNearbyLodLevels(out parentLod, out childLod); MyCellCoord thisLodCell = new MyCellCoord(); foreach (var entry in m_nonEmptyCells) { var data = entry.Value; Debug.Assert(data.Cell != null); thisLodCell.SetUnpack(entry.Key); if (ChildrenWereLoaded(childLod, ref thisLodCell) || (MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(thisLodCell.Lod) == 1 && !AllSiblingsWereLoaded(ref thisLodCell))) { RemoveFromScene(entry.Key, data); } else { AddToScene(entry.Key, data); } } }
/// <summary> /// Checks ancestor nodes recursively. /// </summary> private static bool WasAncestorCellLoaded(LodLevel parentLod, ref MyCellCoord thisLodCell) { if (parentLod == null || !parentLod.m_fitsInFrustum || !parentLod.Visible) { return(true); } Debug.Assert(thisLodCell.Lod == parentLod.m_lodIndex - 1); var shiftToParent = MyVoxelCoordSystems.RenderCellSizeShiftToLessDetailed(thisLodCell.Lod); var parentCell = new MyCellCoord(thisLodCell.Lod + 1, thisLodCell.CoordInLod >> shiftToParent); CellData data; if (parentLod.m_storedCellData.TryGetValue(parentCell.PackId64(), out data)) { return(data.WasLoaded); } LodLevel ancestor; if (parentLod.m_parent.m_lodLevels.TryGetValue(parentLod.m_lodIndex + 1, out ancestor)) { return(WasAncestorCellLoaded(ancestor, ref parentCell)); } else { return(false); } }
private static void TestClipSpheres(ref MyCellCoord cell, ref BoundingSphereD nearClipSphere, ref BoundingSphereD farClipSphere, out ContainmentType nearClipRes, out ContainmentType farClipRes) { BoundingBoxD localAabb; MyVoxelCoordSystems.RenderCellCoordToLocalAABB(ref cell, out localAabb); localAabb.Inflate(MyVoxelConstants.VOXEL_SIZE_IN_METRES * (1 << cell.Lod)); nearClipSphere.Contains(ref localAabb, out nearClipRes); farClipSphere.Contains(ref localAabb, out farClipRes); }
public static Vector3I FindBestOctreeSize(float radius) { int nodeRadius = MyVoxelCoordSystems.RenderCellSizeInLodVoxels(0); while (nodeRadius < radius) { nodeRadius *= 2; } return(new Vector3I(nodeRadius, nodeRadius, nodeRadius)); }
public MyClipmap(uint id, MyClipmapScaleEnum scaleGroup, MatrixD worldMatrix, Vector3I sizeLod0, IMyClipmapCellHandler cellProvider) { m_scaleGroup = scaleGroup; m_worldMatrix = worldMatrix; MatrixD.Invert(ref m_worldMatrix, out m_invWorldMatrix); m_sizeLod0 = sizeLod0; m_localAABB = new BoundingBoxD(Vector3D.Zero, new Vector3D(sizeLod0 * MyVoxelCoordSystems.RenderCellSizeInMeters(0))); for (int lod = 0; lod < m_lodLevels.Length; ++lod) { var sizeShift = lod + MyVoxelCoordSystems.RenderCellSizeInLodVoxelsShiftDelta(lod); m_lodLevels[lod] = new LodLevel(this, lod, ((m_sizeLod0 - 1) >> sizeShift) + 1); } m_updateQueueItem = new UpdateQueueItem(this); m_requestCollector = new RequestCollector(id); m_cellHandler = cellProvider; }
/// <summary> /// New clipping routine, call on lowest desired lod with position of camera /// Should be later enhanced with spread if desired lod would be lower than 0 /// Finaly it will be used as hint for structure managing cells to be calculated and rendered /// </summary> /// <param name="localPosition"></param> /// <param name="collector"></param> internal void DoClipping(Vector3D localPosition, RequestCollector collector, int spread) { Vector3I min, max; { Vector3I center; MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref localPosition, out center); min = center - spread; max = center + spread; Vector3I.Clamp(ref min, ref Vector3I.Zero, ref m_lodSizeMinusOne, out min); Vector3I.Clamp(ref max, ref Vector3I.Zero, ref m_lodSizeMinusOne, out max); } var it0 = new Vector3I.RangeIterator(ref min, ref max); var ignore = BoundingBox.CreateInvalid(); DoClipping(collector, min, max, ref ignore); }
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); }
private static BoundingBox GetChildrenCoords(LodLevel childLod, ref MyCellCoord thisLodCell) { if (childLod == null) { return(BoundingBox.CreateInvalid()); } Debug.Assert(thisLodCell.Lod == childLod.m_lodIndex + 1); var childLodCell = new MyCellCoord(); childLodCell.Lod = childLod.m_lodIndex; var shiftToChild = MyVoxelCoordSystems.RenderCellSizeShiftToMoreDetailed(thisLodCell.Lod); var start = thisLodCell.CoordInLod << shiftToChild; var end = start + ((1 << shiftToChild) >> 1); Vector3I.Min(ref end, ref childLod.m_lodSizeMinusOne, out end); return(new BoundingBox(start, end)); }
/// <param name="minCellLod0">Inclusive.</param> /// <param name="maxCellLod0">Inclusive.</param> public void InvalidateRange(Vector3I minCellLod0, Vector3I maxCellLod0) { if (minCellLod0 == Vector3I.Zero && maxCellLod0 == m_sizeLod0 - 1) { for (int lod = 0; lod < m_lodLevels.Length; ++lod) { m_lodLevels[lod].InvalidateAll(); } } else { for (int lod = 0; lod < m_lodLevels.Length; ++lod) { var shift = lod + MyVoxelCoordSystems.RenderCellSizeInLodVoxelsShiftDelta(lod); m_lodLevels[lod].InvalidateRange( minCellLod0 >> shift, maxCellLod0 >> shift); } } m_updateClipping = true; }
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(m_lodIndex, ref minD, out min); MyVoxelCoordSystems.LocalPositionToRenderCellCoord(m_lodIndex, ref maxD, out max); Vector3I.Clamp(ref min, ref Vector3I.Zero, ref m_lodSizeMinusOne, out min); Vector3I.Clamp(ref max, ref Vector3I.Zero, 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); } }
private void Update(ref Vector3D cameraPos, float farPlaneDistance) { ProfilerShort.Begin("MyRenderClipmap.Update"); var mostDetailedLod = (uint)DebugClipmapMostDetailedLod; if (m_lastMostDetailedLod != mostDetailedLod) { m_updateClipping = true; } m_lastMostDetailedLod = mostDetailedLod; for (uint lod = 0; lod < m_lodLevels.Length; ++lod) { m_lodLevels[lod].Visible = lod >= mostDetailedLod; } Vector3D localPosition; Vector3D.Transform(ref cameraPos, ref m_invWorldMatrix, out localPosition); double cellSizeHalf = MyVoxelCoordSystems.RenderCellSizeInMetersHalf(0); double threshold = cellSizeHalf * cellSizeHalf; if (!m_updateClipping && Vector3D.DistanceSquared(localPosition, m_lastClippingPosition) > threshold) { m_updateClipping = true; } if (m_updateClipping) { ProfilerShort.Begin("DoClipping"); Debug.Assert(m_scaleGroup == MyClipmapScaleEnum.Normal || m_scaleGroup == MyClipmapScaleEnum.Massive); for (int lod = m_lodLevels.Length - 1; lod >= mostDetailedLod; --lod) { ProfilerShort.Begin("Lod " + lod); m_lodLevels[lod].DoClipping(localPosition, farPlaneDistance, m_requestCollector); ProfilerShort.End(); } ProfilerShort.End(); ProfilerShort.Begin("KeepOrDiscardClippedCells"); for (int lod = m_lodLevels.Length - 1; lod >= mostDetailedLod; --lod) { m_lodLevels[lod].KeepOrDiscardClippedCells(m_requestCollector); } ProfilerShort.End(); m_lastClippingPosition = localPosition; m_updateClipping = false; } ProfilerShort.Begin("UpdateCellsInScene"); for (int lod = m_lodLevels.Length - 1; lod >= mostDetailedLod; --lod) { m_lodLevels[lod].UpdateCellsInScene(localPosition); } ProfilerShort.End(); m_requestCollector.Submit(); if (m_requestCollector.SentRequestsEmpty) { m_notReady.Remove(this); } ProfilerShort.End(); }
private void Update(ref Vector3D cameraPos, ref Vector3 cameraForward, float farPlaneDistance) { ProfilerShort.Begin("MyRenderClipmap.Update"); LastCameraPosition = cameraPos; if (!Environment.Is64BitProcess) { UseCache = false; } if (NeedsResetCache) { MyClipmap.CellsCache.Reset(); NeedsResetCache = false; } for (uint lod = 0; lod < m_lodLevels.Length; lod++) { if (m_lodLevels[lod].IsDitheringInProgress()) { m_lodLevels[lod].UpdateDithering(); } } Vector3D localPosition; Vector3D.Transform(ref cameraPos, ref m_invWorldMatrix, out localPosition); Vector3 localForward; Vector3.TransformNormal(ref cameraForward, ref m_invWorldMatrix, out localForward); double cellSizeHalf = MyVoxelCoordSystems.RenderCellSizeInMetersHalf(0); double threshold = cellSizeHalf / 4.0f; float thresholdRotation = 0.03f; if (!m_updateClippingFrustum && (Vector3D.DistanceSquared(localPosition, m_lastClippingPosition) > threshold) || (Vector3.DistanceSquared(localForward, m_lastClippingForward) > thresholdRotation) || m_invalidated > 0) { ResetClipping(); m_lastClippingPosition = localPosition; m_lastClippingForward = localForward; } float camDistanceFromCenter = Vector3.Distance(m_massiveCenter, cameraPos); if (m_requestCollector.SentRequestsEmpty && m_updateClippingFrustum) { ProfilerShort.Begin("DoClipping"); //Top priority for 0 lod when invalidated (drill) if (m_invalidated == 2) { m_lodLevels[0].DoClipping(camDistanceFromCenter, localPosition, farPlaneDistance, m_requestCollector, true, 1); m_lodLevels[0].DiscardClippedCells(m_requestCollector); m_lodLevels[0].UpdateCellsInScene(camDistanceFromCenter, localPosition); if (!m_requestCollector.SentRequestsEmpty) { m_requestCollector.Submit(); ProfilerShort.End(); // DoClipping ProfilerShort.End(); // Update return; } m_updateClippingFrustum = false; m_invalidated = 1; } else { //Most important frustum culling for (int lod = m_lodLevels.Length - 1; lod >= 0; --lod) { ProfilerShort.Begin("Lod " + lod); m_lodLevels[lod].DoClipping(camDistanceFromCenter, localPosition, farPlaneDistance, m_requestCollector, true, 1); ProfilerShort.End(); } //ProfilerShort.End(); ProfilerShort.Begin("KeepOrDiscardClippedCells"); for (int lod = m_lodLevels.Length - 1; lod >= 0; --lod) { m_lodLevels[lod].DiscardClippedCells(m_requestCollector); } ProfilerShort.End(); ProfilerShort.Begin("UpdateCellsInScene"); for (int lod = m_lodLevels.Length - 1; lod >= 0; --lod) { m_lodLevels[lod].UpdateCellsInScene(camDistanceFromCenter, localPosition); } ProfilerShort.End(); if (!m_requestCollector.SentRequestsEmpty) { m_requestCollector.Submit(); ProfilerShort.End(); // DoClipping ProfilerShort.End(); // Update return; } m_invalidated = 0; m_notReady.Remove(this); m_updateClippingFrustum = false; } ProfilerShort.End(); } ProfilerShort.End(); }
/// <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); } } }
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(); } }
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); } } }
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); } } }
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); } } } }
private void Update(ref Vector3D cameraPos, float farPlaneDistance) { ProfilerShort.Begin("MyRenderClipmap.Update"); Vector3D localPosition; Vector3D.Transform(ref cameraPos, ref m_invWorldMatrix, out localPosition); double cellSizeHalf = MyVoxelCoordSystems.RenderCellSizeInMetersHalf(0); double threshold = cellSizeHalf * cellSizeHalf; if (!m_updateClipping && Vector3D.DistanceSquared(localPosition, m_lastClippingPosition) > threshold) { m_updateClipping = true; } //modified clipping routine //we clip only when there are no old requests since we are not able to combine //multiple clippings reasonably //(need the structure to hold and merge result otherwise holes are inevitable) if (!m_updateClipping && m_requestCollector.SentRequestsEmpty && m_clipingAdjustment < 5) { m_clipingAdjustment += 2; m_updateClipping = true; } if (m_updateClipping) { m_requestCollector.Submit(); if (m_requestCollector.SentRequestsEmpty) { ProfilerShort.Begin("KeepOrDiscardClippedCells"); for (int lod = m_lodLevels.Length - 1; lod >= 0; --lod) { m_lodLevels[lod].KeepOrDiscardClippedCells(m_requestCollector); } ProfilerShort.End(); if (!ENABLE_CLIPPING_ADJUSTMENT) { m_clipingAdjustment = 1; } var startLod = MathHelper.Clamp(-1 * m_clipingAdjustment, 0, m_lodLevels.Length - 1); ProfilerShort.Begin("DoClipping"); if (NEW_VOXEL_CLIPPING) { m_lodLevels[startLod].DoClipping(localPosition, m_requestCollector, MathHelper.Clamp(m_clipingAdjustment, 0, 5)); } else { Debug.Assert(m_scaleGroup == MyClipmapScaleEnum.Normal); for (int lod = m_lodLevels.Length - 1; lod >= 0; --lod) { ProfilerShort.Begin("Lod " + lod); m_lodLevels[lod].DoClipping_Old(localPosition, farPlaneDistance, m_requestCollector); ProfilerShort.End(); } } ProfilerShort.End(); if (m_requestCollector.SentRequestsEmpty) { m_clipingAdjustment += 2; } } //else // m_clipingAdjustment -= 2; m_lastClippingPosition = localPosition; m_updateClipping = false; } ProfilerShort.Begin("UpdateCellsInScene"); for (int lod = m_lodLevels.Length - 1; lod >= 0; --lod) { m_lodLevels[lod].UpdateCellsInScene(localPosition); } ProfilerShort.End(); m_clipingAdjustment = MathHelper.Clamp(m_clipingAdjustment, -m_lodLevels.Length + 3, 5); m_requestCollector.Submit(); if (m_requestCollector.SentRequestsEmpty) { m_notReady.Remove(this); } ProfilerShort.End(); }