public void TestSpiralForEach3d() { var spi = SpiralIterators.Cube(new Vector3Int(1, 1, 1)); String assume = "(0, 0, 0), (1, 0, 0), (1, -1, 0), (0, -1, 0), (-1, -1, 0), (-1, 0, 0), (-1, 1, 0), (0, 1, 0), (1, 1, 0), (0, 0, -1), (1, 0, -1), (1, -1, -1), (0, -1, -1), (-1, -1, -1), (-1, 0, -1), (-1, 1, -1), (0, 1, -1), (1, 1, -1), (0, 0, 1), (1, 0, 1), (1, -1, 1), (0, -1, 1), (-1, -1, 1), (-1, 0, 1), (-1, 1, 1), (0, 1, 1), (1, 1, 1)"; IList <Vector3Int> test = new List <Vector3Int>(); foreach (Vector3Int v in spi) { test.Add(v); } string result = String.Join(", ", test); Assert.IsTrue(assume.SequenceEqual(result), $"Lists not equal:\n\tAssumed:{assume}\n\tTest:{result}"); }
void InitVisibleChunks() { if (chunks == null) { return; } CreateChunkHolder(); Vector3 p = viewer.position; Vector3 ps = p / boundsSize; Vector3Int viewerCoord = new Vector3Int(Mathf.RoundToInt(ps.x), Mathf.RoundToInt(ps.y), Mathf.RoundToInt(ps.z)); int maxChunksInView = Mathf.CeilToInt(viewDistance / boundsSize); float sqrViewDistance = viewDistance * viewDistance; // Go through all existing chunks and flag for recyling if outside of max view dst float t0 = Time.realtimeSinceStartup; Chunk chunk; Vector3 centre; Vector3 viewerOffset; Vector3 o; float sqrDst; for (int i = chunks.Count - 1; i >= 0; i--) { if (Time.realtimeSinceStartup - t0 > (1.0 / fpsBreakout)) { return; } chunk = chunks[i]; centre = CentreFromCoord(chunk.coord); viewerOffset = p - centre; o = new Vector3(Mathf.Abs(viewerOffset.x), Mathf.Abs(viewerOffset.y), Mathf.Abs(viewerOffset.z)) - Vector3.one * boundsSize / 2; sqrDst = new Vector3(Mathf.Max(o.x, 0), Mathf.Max(o.y, 0), Mathf.Max(o.z, 0)).sqrMagnitude; if (sqrDst > sqrViewDistance) { existingChunks.Remove(chunk.coord); recycleableChunks.Enqueue(chunk); chunks.RemoveAt(i); } } collect_countdown -= 1; if (collect_countdown == 0) { GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized, blocking: false); collect_countdown = 10; } Vector3Int coord; foreach (Vector3Int spi in SpiralIterators.Cube(new Vector3Int(maxChunksInView, maxChunksInView, maxChunksInView))) { if (Time.realtimeSinceStartup - t0 > (1.0 / fpsBreakout)) { return; } coord = spi + viewerCoord; if (existingChunks.ContainsKey(coord)) { if (!blockingGpu && (((!existingChunks[coord].asyncOp0?.done) ?? true) || ((!existingChunks[coord].asyncOp1?.done) ?? true) || ((!existingChunks[coord].asyncOp2?.done) ?? true))) { // wait for centermost chunks to finish return; } else { continue; } } centre = CentreFromCoord(coord); viewerOffset = p - centre; o = new Vector3(Mathf.Abs(viewerOffset.x), Mathf.Abs(viewerOffset.y), Mathf.Abs(viewerOffset.z)) - Vector3.one * boundsSize / 2; sqrDst = new Vector3(Mathf.Max(o.x, 0), Mathf.Max(o.y, 0), Mathf.Max(o.z, 0)).sqrMagnitude; // Chunk is within view distance and should be created (if it doesn't already exist) if (sqrDst <= sqrViewDistance) { Bounds bounds = new Bounds(CentreFromCoord(coord), Vector3.one * boundsSize); if (IsVisibleFrom(bounds, Camera.main)) { if (recycleableChunks.Count > 0) { chunk = recycleableChunks.Dequeue(); chunk.coord = coord; existingChunks.Add(coord, chunk); chunks.Add(chunk); UpdateChunkMesh(chunk, blockingGpu); } else { chunk = CreateChunk(coord); chunk.coord = coord; chunk.SetUp(mat, generateColliders); existingChunks.Add(coord, chunk); chunks.Add(chunk); UpdateChunkMesh(chunk, blockingGpu); } } } } }