VoxelChunk PopNearestChunk(int frustumCheckIteration, float acceptedDistanceSqr, float forceChunkSqrDistance, out float chunkDist) { chunkDist = 1e8f; int nearestNode = 0; float minDist = float.MaxValue; int node = chunkQueueRoot; while (node > 0) { VoxelChunk chunk = linkedChunks [node].chunk; float cdx = chunk.position.x - currentCamPos.x; float cdz = chunk.position.z - currentCamPos.z; float dist = cdx * cdx + cdz * cdz; // if chunk is within forced visible distance, return it immediately if (dist <= forceChunkSqrDistance) { chunkDist = dist; nearestNode = node; break; } // otherwise, prioritize by distance and frustum if (frustumCheckIteration != chunk.frustumCheckIteration) { chunk.frustumCheckIteration = frustumCheckIteration; Vector3 boundsMin; boundsMin.x = chunk.position.x - 8; boundsMin.y = chunk.position.y - 8; boundsMin.z = chunk.position.z - 8; Vector3 boundsMax; boundsMax.x = chunk.position.x + 8; boundsMax.y = chunk.position.y + 8; boundsMax.z = chunk.position.z + 8; chunk.visibleInFrustum = GeometryUtilityNonAlloc.TestPlanesAABB(frustumPlanesNormals, frustumPlanesDistances, ref boundsMin, ref boundsMax); } float frontDist = dist; if (!chunk.visibleInFrustum && !chunk.ignoreFrustum) { bool inDistance = frontDist <= acceptedDistanceSqr; if (onlyRenderInFrustum && !inDistance) { node = linkedChunks [node].next; continue; } frontDist += 1000000000; } if (frontDist < minDist) { minDist = frontDist; chunkDist = dist; nearestNode = node; if (frontDist < acceptedDistanceSqr) { break; } } node = linkedChunks [node].next; } if (nearestNode > 0) { if (nearestNode == chunkQueueRoot) { chunkQueueRoot = linkedChunks [nearestNode].next; linkedChunks [chunkQueueRoot].prev = 0; } else { if (linkedChunks [nearestNode].prev > 0) { linkedChunks [linkedChunks [nearestNode].prev].next = linkedChunks [nearestNode].next; } if (linkedChunks [nearestNode].next > 0) { linkedChunks [linkedChunks [nearestNode].next].prev = linkedChunks [nearestNode].prev; } } linkedChunks [nearestNode].used = false; VoxelChunk chunk = linkedChunks [nearestNode].chunk; return(chunk); } return(null); }
void CheckCuboidVisibility(Octree cuboid) { if (cuboid.exploredChildren >= 8) { return; } Vector3 cuboidCenter = cuboid.center; float dx = cuboidCenter.x - currentCamPos.x; if (dx < 0) { dx = -dx; // simple abs() } dx -= cuboid.extents; dx /= 16f; if (dx > _visibleChunksDistance) { return; } float dy = cuboidCenter.y - currentCamPos.y; if (dy < 0) { dy = -dy; } dy -= cuboid.extents; dy /= 16f; int chunksYDistance = _visibleChunksDistance >= 8 ? 8 : _visibleChunksDistance; if (dy > chunksYDistance) { return; } float dz = cuboidCenter.z - currentCamPos.z; if (dz < 0) { dz = -dz; } dz -= cuboid.extents; dz /= 16f; if (dz > _visibleChunksDistance) { return; } Vector3 cuboidMin, cuboidMax; cuboidMin.x = cuboidCenter.x - cuboid.extents; cuboidMin.y = cuboidCenter.y - cuboid.extents; cuboidMin.z = cuboidCenter.z - cuboid.extents; cuboidMax.x = cuboidCenter.x + cuboid.extents; cuboidMax.y = cuboidCenter.y + cuboid.extents; cuboidMax.z = cuboidCenter.z + cuboid.extents; bool inFrustum; if (onlyRenderInFrustum) { inFrustum = GeometryUtilityNonAlloc.TestPlanesAABB(frustumPlanesNormals, frustumPlanesDistances, ref cuboidMin, ref cuboidMax); } else { inFrustum = true; } if (inFrustum) { int cuboidSize = cuboid.extents * 2; if (cuboidSize > 16) { if (cuboid.children == null) { cuboid.Explode(); } for (int k = 0; k < 8; k++) { if (!cuboid.children [k].explored) { PushCuboid(cuboid.children [k]); } } return; } // cuboid is less than a chunk - use that chunk int chunkX, chunkY, chunkZ; GetChunkCoordinates(cuboid.center, out chunkX, out chunkY, out chunkZ); int hash = GetChunkHash(chunkX, chunkY, chunkZ); CachedChunk cachedChunk; if (cachedChunks.TryGetValue(hash, out cachedChunk)) { cachedChunk.octree = cuboid; cuboid.parent.exploredChildren++; cuboid.explored = true; VoxelChunk chunk = cachedChunk.chunk; if (chunk == null) { return; } if (chunk.isPopulated) { // If this chunk has been created but not rendered yet, request it // if (chunk.renderState == ChunkRenderState.Pending && !chunk.inqueue) { if (chunk.renderState != ChunkRenderState.RenderingComplete || !chunk.mr.enabled) { if (chunk.inqueue) { chunk.needsMeshRebuild = true; } else { ChunkRequestRefresh(chunk, false, true); } } return; } } CreateChunk(hash, chunkX, chunkY, chunkZ, false); chunkCreationCountThisFrame++; } }