コード例 #1
0
        public void ProcessChunk(Chunk chunk)
        {
            int xd = Helpers.Abs((m_viewerPos.x - chunk.pos.x) >> Env.ChunkPower);
            int yd = Helpers.Abs((m_viewerPos.y - chunk.pos.y) >> Env.ChunkPower);
            int zd = Helpers.Abs((m_viewerPos.z - chunk.pos.z) >> Env.ChunkPower);

            // Remove the chunk if it is too far away
            if (
                xd * xd + zd * zd >= HorizontalChunkDeleteRadius * HorizontalChunkDeleteRadius ||
                yd * yd >= VerticalChunkDeleteRadius * VerticalChunkDeleteRadius
                )
            {
                chunk.stateManager.RequestState(ChunkState.Remove);
                return;
            }

            // Dummy collider example - create a collider for chunks directly surrounding the viewer
            chunk.NeedsCollider = xd <= 1 && yd <= 1 && zd <= 1;

            // Update visibility information
            bool isInsideFrustum = FullLoadOnStartUp || IsChunkInViewFrustum(chunk);

            ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;

            stateManager.Visible         = isInsideFrustum;
            stateManager.PossiblyVisible = isInsideFrustum;
        }
コード例 #2
0
        public void ProcessChunks()
        {
            Profiler.BeginSample("ProcessChunks");

            HandleVisibility();

            // Process removal requests
            for (int i = 0; i < m_updateRequests.Count;)
            {
                Chunk chunk = m_updateRequests[i];

                ProcessChunk(chunk);

                // Update the chunk if possible
                if (chunk.CanUpdate)
                {
                    chunk.UpdateState();
                    chunk.UpdateRenderGeometry();
                    chunk.UpdateCollisionGeometry();
                }

                // Automatically collect chunks which are ready to be removed from the world
                ChunkStateManagerClient stateManager = chunk.stateManager;
                if (stateManager.IsStateCompleted(ChunkState.Remove))
                {
                    // Remove the chunk from our provider and unregister it from chunk storage
                    world.chunks.RemoveChunk(chunk);

                    // Unregister from updates
                    m_updateRequests.RemoveAt(i);

                    continue;
                }

                ++i;
            }

            world.PerformBlockActions();

            FullLoadOnStartUp = false;

            Profiler.EndSample();

            // Memory savings diagnostic

            /*{
             *  long compressedMem = 0;
             *  foreach (var chunk in world.chunks.chunkCollection)
             *  {
             *      compressedMem += chunk.blocks.BlocksCompressed.Count*
             *                       StructSerialization.TSSize<BlockDataAABB>.ValueSize;
             *  }
             *
             *  long uncompressedMem = (long)world.chunks.Count*Env.ChunkSizeWithPaddingPow3*
             *                         StructSerialization.TSSize<BlockData>.ValueSize;
             *  Debug.LogFormat("mem: {0}/{1} ({2}%)", compressedMem, uncompressedMem, (int)((double)compressedMem/(double)uncompressedMem*100.0));
             * }*/
        }
コード例 #3
0
        public void ProcessChunks()
        {
            Profiler.BeginSample("ProcessChunks");

            HandleVisibility();

            // Process removal requests
            for (int i = 0; i < m_updateRequests.Count;)
            {
                Chunk chunk = m_updateRequests[i];

                ProcessChunk(chunk);

                // Update the chunk if possible
                if (chunk.CanUpdate)
                {
                    chunk.UpdateState();

                    // Build colliders if there is enough time
                    if (Globals.GeometryBudget.HasTimeBudget)
                    {
                        Globals.GeometryBudget.StartMeasurement();

                        bool wasBuilt = chunk.UpdateRenderGeometry();
                        wasBuilt |= chunk.UpdateCollisionGeometry();
                        if (wasBuilt)
                        {
                            Globals.GeometryBudget.StopMeasurement();
                        }
                    }
                }

                // Automatically collect chunks which are ready to be removed from the world
                ChunkStateManagerClient stateManager = chunk.stateManager;
                if (stateManager.IsStateCompleted(ChunkState.Remove))
                {
                    // Remove the chunk from our provider and unregister it from chunk storage
                    world.chunks.RemoveChunk(chunk);

                    // Unregister from updates
                    m_updateRequests.RemoveAt(i);
                    continue;
                }

                ++i;
            }

            world.PerformBlockActions();

            FullLoadOnStartUp = false;

            Profiler.EndSample();
        }
コード例 #4
0
ファイル: Chunk.cs プロジェクト: lasaro-dumer/Voxelmetric
        public Chunk(int sideSize = Env.ChunkSize)
        {
            m_sideSize = sideSize;

            // Associate Chunk with a certain thread and make use of its memory pool
            // This is necessary in order to have lock-free caches
            ThreadID = Globals.WorkPool.GetThreadIDFromIndex(s_id++);
            pools    = Globals.WorkPool.GetPool(ThreadID);

            stateManager = new ChunkStateManagerClient(this);
            blocks       = new ChunkBlocks(this, sideSize);
        }
コード例 #5
0
        private void OnDrawGizmosSelected()
        {
            int size      = Mathf.FloorToInt(Env.ChunkSize * Env.BlockSize);
            int halfSize  = size >> 1;
            int smallSize = size >> 4;

            if (world != null && world.chunks != null && (Diag_DrawWorldBounds || Diag_DrawLoadRange))
            {
                foreach (Chunk chunk in world.chunks.chunkCollection)
                {
                    if (Diag_DrawWorldBounds)
                    {
                        Gizmos.color = Color.blue;
                        Gizmos.DrawWireCube(chunk.WorldBounds.center, chunk.WorldBounds.size);
                    }

                    if (Diag_DrawLoadRange)
                    {
                        Vector3Int pos = chunk.pos;
                        int        xd  = Helpers.Abs((m_viewerPos.x - pos.x) >> Env.ChunkPower);
                        int        zd  = Helpers.Abs((m_viewerPos.z - pos.z) >> Env.ChunkPower);
                        if (xd * xd + zd * zd >= HorizontalChunkDeleteRadius * HorizontalChunkDeleteRadius)
                        {
                            Gizmos.color = Color.red;
                            Gizmos.DrawWireCube(
                                new Vector3(chunk.pos.x + halfSize, 0, chunk.pos.z + halfSize),
                                new Vector3(size - 0.05f, 0, size - 0.05f)
                                );
                        }
                        else
                        {
                            Gizmos.color = Color.green;
                            Gizmos.DrawWireCube(
                                new Vector3(chunk.pos.x + halfSize, 0, chunk.pos.z + halfSize),
                                new Vector3(size - 0.05f, 0, size - 0.05f)
                                );
                        }

                        // Show generated chunks
                        ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;
                        if (stateManager.IsStateCompleted(ChunkState.Generate))
                        {
                            Gizmos.color = Color.magenta;
                            Gizmos.DrawWireCube(
                                new Vector3(chunk.pos.x + halfSize, 0, chunk.pos.z + halfSize),
                                new Vector3(smallSize - 0.05f, 0, smallSize - 0.05f)
                                );
                        }
                    }
                }
            }
        }
コード例 #6
0
        private void FinishChunkDataReceive()
        {
            if (!InitFromBytes())
            {
                Reset();
            }

            ChunkStateManagerClient stateManager = chunk.stateManager;

            ChunkStateManagerClient.OnGenerateDataOverNetworkDone(stateManager);

            receiveBuffer = null;
            receiveIndex  = 0;
        }
コード例 #7
0
        public Chunk()
        {
            // Associate Chunk with a certain thread and make use of its memory pool
            // This is necessary in order to have lock-free caches
            ThreadID = Globals.WorkPool.GetThreadIDFromIndex(s_id++);
            pools    = Globals.WorkPool.GetPool(ThreadID);

            stateManager = new ChunkStateManagerClient(this);
            blocks       = new ChunkBlocks(this);
            logic        = new ChunkLogic(this);

            GeometryHandler = new ChunkRenderGeometryHandler(this);
            ChunkColliderGeometryHandler = new ChunkColliderGeometryHandler(this);
        }
コード例 #8
0
ファイル: Chunk.cs プロジェクト: bejita968/Voxe
        public Chunk()
        {
            Blocks = new BlockStorage();

            // Associate Chunk with a certain thread and make use of its memory pool
            // This is necessary in order to have lock-free caches
            ThreadID = Globals.WorkPool.GetThreadIDFromIndex(s_id++);
            Pools    = Globals.WorkPool.GetPool(ThreadID);

            RenderGeometryBatcher   = new RenderGeometryBatcher(Globals.CubeMeshGeometryBuilder, this);
            BBoxVertices            = new List <Vector3>();
            BBoxVerticesTransformed = new List <Vector3>();

            StateManager = new ChunkStateManagerClient(this);
        }
コード例 #9
0
ファイル: ChunkBlocks.cs プロジェクト: TrueLoop/Voxelmetric
        private void FinishChunkDataReceive()
        {
            GenerateContentsFromBytes();

            ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;

            ChunkStateManagerClient.OnGenerateDataOverNetworkDone(stateManager);

            receiveBuffer = null;
            receiveIndex  = 0;

            if (debugRecieve)
            {
                Debug.Log("ChunkBlocks.FinishChunkDataReceive (" + Thread.CurrentThread.ManagedThreadId + "): " + chunk.pos);
            }
        }
コード例 #10
0
        void IEventListener <ChunkStateExternal> .OnNotified(IEventSource <ChunkStateExternal> source, ChunkStateExternal evt)
        {
            // Unsubscribe from any further events
            ChunkStateManagerClient stateManager = (ChunkStateManagerClient)source;

            stateManager.Subscribe(this, evt, false);

            Assert.IsTrue(evt == ChunkStateExternal.Saved);
            if (evt == ChunkStateExternal.Saved)
            {
                if (!chunksToSave.Contains(stateManager.chunk))
                {
                    return;
                }
                SaveCompleteForChunk(stateManager.chunk);
            }
        }
コード例 #11
0
        public void ProcessChunk(Chunk chunk)
        {
            Profiler.BeginSample("ProcessChunk");

            ChunkStateManagerClient stateManager = chunk.stateManager;

            int tx = m_clipmap.TransformX(chunk.pos.x / Env.ChunkSize);
            int ty = m_clipmap.TransformY(chunk.pos.y / Env.ChunkSize);
            int tz = m_clipmap.TransformZ(chunk.pos.z / Env.ChunkSize);

            // Chunk is too far away. Remove it
            if (!m_clipmap.IsInsideBounds_Transformed(tx, ty, tz))
            {
                stateManager.RequestState(ChunkState.Remove);
            }
            else
            {
                // Dummy collider example - create a collider for chunks directly surrounding the viewer
                int xd = Helpers.Abs((m_viewerPos.x - chunk.pos.x) / Env.ChunkSize);
                int yd = Helpers.Abs((m_viewerPos.y - chunk.pos.y) / Env.ChunkSize);
                int zd = Helpers.Abs((m_viewerPos.z - chunk.pos.z) / Env.ChunkSize);
                chunk.NeedsCollider = xd <= 1 && yd <= 1 && zd <= 1;

                if (!UseFrustumCulling)
                {
                    ClipmapItem item = m_clipmap.Get_Transformed(tx, ty, tz);

                    // Chunk is in visibilty range. Full update with geometry generation is possible
                    if (item.IsInVisibleRange)
                    {
                        //chunk.LOD = item.LOD;
                        stateManager.PossiblyVisible = true;
                        stateManager.Visible         = true;
                    }
                    // Chunk is in cached range. Full update except for geometry generation
                    else
                    {
                        //chunk.LOD = item.LOD;
                        stateManager.PossiblyVisible = true;
                        stateManager.Visible         = false;
                    }
                }
            }
        }
コード例 #12
0
ファイル: Chunk.cs プロジェクト: lasaro-dumer/Voxelmetric
        public void Init(World world, Vector3Int pos)
        {
            this.world = world;
            this.pos   = pos;

            stateManager = new ChunkStateManagerClient(this);

            if (world != null)
            {
                logic = world.config.randomUpdateFrequency > 0.0f ? new ChunkLogic(this) : null;

                if (GeometryHandler == null)
                {
                    GeometryHandler = new ChunkRenderGeometryHandler(this, world.renderMaterials);
                }
                if (ChunkColliderGeometryHandler == null)
                {
                    ChunkColliderGeometryHandler = new ChunkColliderGeometryHandler(this, world.physicsMaterials);
                }
            }
            else
            {
                if (GeometryHandler == null)
                {
                    GeometryHandler = new ChunkRenderGeometryHandler(this, null);
                }
                if (ChunkColliderGeometryHandler == null)
                {
                    ChunkColliderGeometryHandler = new ChunkColliderGeometryHandler(this, null);
                }
            }

            WorldBounds = new AABB(
                pos.x, pos.y, pos.z,
                pos.x + m_sideSize, pos.y + m_sideSize, pos.z + m_sideSize
                );
            minBounds  = maxBounds = 0;
            minBoundsC = maxBoundsC = 0;

            Reset();

            blocks.Init();
            stateManager.Init();
        }
コード例 #13
0
        public SaveProgress(ICollection <Chunk> chunks)
        {
            if (chunks.Count <= 0)
            {
                progress = 100;
                return;
            }

            chunksToSave.AddRange(chunks);
            totalChunksToSave = chunksToSave.Count;

            // Register at each chunk
            for (int i = 0; i < chunksToSave.Count; i++)
            {
                Chunk chunk = chunksToSave[i];
                ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;
                stateManager.Subscribe(this, ChunkStateExternal.Saved, true);
            }
        }
コード例 #14
0
        private ChunkBlocks HandleNeighborBack(ref Vector3Int pos)
        {
            ChunkStateManagerClient stateManager = chunk.stateManager;
            int i = DirectionUtils.Get(Direction.south);

            // If it is an edge position, notify neighbor as well
            // Iterate over neighbors and decide which ones should be notified to rebuild
            var        listeners = stateManager.Listeners;
            ChunkEvent listener  = listeners[i];

            if (listener == null)
            {
                return(null);
            }

            ChunkStateManagerClient listenerClient = (ChunkStateManagerClient)listener;
            Chunk listenerChunk = listenerClient.chunk;

            int cx = chunk.pos.x;
            int cy = chunk.pos.y;
            int cz = chunk.pos.z;
            int lx = listenerChunk.pos.x;
            int ly = listenerChunk.pos.y;
            int lz = listenerChunk.pos.z;

            if (ly != cy && lx != cx)
            {
                return(null);
            }

            if (pos.z != 0 || (lz + m_sideSize != cz))
            {
                return(null);
            }

            rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);
            return(listenerChunk.blocks);
        }
コード例 #15
0
        public void ProcessChunk(Chunk chunk)
        {
            Profiler.BeginSample("ProcessChunk");

            ChunkStateManagerClient stateManager = chunk.stateManager;

            int xd = (m_viewerPos.x - chunk.pos.x) / Env.ChunkSize;
            int yd = (m_viewerPos.y - chunk.pos.y) / Env.ChunkSize;
            int zd = (m_viewerPos.z - chunk.pos.z) / Env.ChunkSize;

            int hRadius = HorizontalChunkLoadRadius;
            int vRadius = VerticalChunkLoadRadius;
            int xDist   = xd * xd + zd * zd;
            int yDist   = yd * yd;

            // Remove the chunk if it is too far away
            if (xDist > hRadius * hRadius || yDist > vRadius * vRadius)
            {
                stateManager.RequestState(ChunkState.Remove);
            }
            else
            {
                // Dummy collider example - create a collider for chunks directly surrounding the viewer
                chunk.NeedsCollider = Helpers.Abs(xd) <= 1 && Helpers.Abs(yd) <= 1 && Helpers.Abs(zd) <= 1;

                if (!UseFrustumCulling)
                {
                    // Update visibility information
                    stateManager.Visible = xDist <= HorizontalChunkLoadRadius * HorizontalChunkLoadRadius &&
                                           yDist <= VerticalChunkLoadRadius * VerticalChunkLoadRadius;
                    stateManager.PossiblyVisible = true;
                }
            }

            Profiler.EndSample();
        }
コード例 #16
0
        /// <summary>
        /// Sends a save request to all chunk currently loaded
        /// </summary>
        /// <param name="world">World holding chunks</param>
        /// <returns>List of chunks waiting to be saved.</returns>
        public static List <Chunk> SaveAll(World world)
        {
            if (world == null || !Features.UseSerialization)
            {
                return(null);
            }

            List <Chunk> chunksToSave = new List <Chunk> ();

            foreach (Chunk chunk in world.chunks.chunkCollection)
            {
                // Ignore chunks that can't be saved at the moment
                ChunkStateManagerClient stateManager = chunk.stateManager;
                if (!stateManager.IsSavePossible)
                {
                    continue;
                }

                chunksToSave.Add(chunk);
                stateManager.RequestState(ChunkState.PrepareSaveData);
            }

            return(chunksToSave);
        }
コード例 #17
0
        public void Update()
        {
            ChunkStateManagerClient stateManager = chunk.stateManager;

            if (!stateManager.IsUpdateBlocksPossible)
            {
                return;
            }

            //UnityEngine.Debug.Log(m_setBlockQueue.Count);

            if (m_setBlockQueue.Count > 0)
            {
                if (rebuildMaskGeometry < 0)
                {
                    rebuildMaskGeometry = 0;
                }
                if (rebuildMaskCollider < 0)
                {
                    rebuildMaskCollider = 0;
                }

                var timeBudget = Globals.SetBlockBudget;

                // Modify blocks
                int j;
                for (j = 0; j < m_setBlockQueue.Count; j++)
                {
                    timeBudget.StartMeasurement();
                    m_setBlockQueue[j].Apply(this);
                    timeBudget.StopMeasurement();

                    // Sync edges if there's enough time

                    /*if (!timeBudget.HasTimeBudget)
                     * {
                     ++j;
                     *  break;
                     * }*/
                }

                rebuildMaskCollider |= rebuildMaskGeometry;

                if (j == m_setBlockQueue.Count)
                {
                    m_setBlockQueue.Clear();
                }
                else
                {
                    m_setBlockQueue.RemoveRange(0, j);
                    return;
                }
            }

            long now = Globals.Watch.ElapsedMilliseconds;

            // Request a geometry update at most 10 times a second
            if (rebuildMaskGeometry >= 0 && now - lastUpdateTimeGeometry >= 100)
            {
                lastUpdateTimeGeometry = now;

                // Request rebuild on this chunk
                stateManager.RequestState(ChunkState.BuildVerticesNow);

                // Notify neighbors that they need to rebuild their geometry
                if (rebuildMaskGeometry > 0)
                {
                    var listeners = stateManager.Listeners;
                    for (int j = 0; j < listeners.Length; j++)
                    {
                        ChunkStateManagerClient listener = (ChunkStateManagerClient)listeners[j];
                        if (listener != null && ((rebuildMaskGeometry >> j) & 1) != 0)
                        {
                            // Request rebuild on neighbor chunks
                            listener.RequestState(ChunkState.BuildVerticesNow);
                        }
                    }
                }

                rebuildMaskGeometry = -1;
            }

            // Request a collider update at most 4 times a second
            if (chunk.NeedsCollider && rebuildMaskCollider >= 0 && now - lastUpdateTimeCollider >= 250)
            {
                lastUpdateTimeCollider = now;

                // Request rebuild on this chunk
                stateManager.RequestState(ChunkState.BuildColliderNow);

                // Notify neighbors that they need to rebuilt their geometry
                if (rebuildMaskCollider > 0)
                {
                    var listeners = stateManager.Listeners;
                    for (int j = 0; j < listeners.Length; j++)
                    {
                        ChunkStateManagerClient listener = (ChunkStateManagerClient)listeners[j];
                        if (listener != null && ((rebuildMaskCollider >> j) & 1) != 0)
                        {
                            // Request rebuild on neighbor chunks
                            if (listener.chunk.NeedsCollider)
                            {
                                listener.RequestState(ChunkState.BuildColliderNow);
                            }
                        }
                    }
                }

                rebuildMaskCollider = -1;
            }
        }
コード例 #18
0
        public void HandleNeighbors(BlockData block, Vector3Int pos)
        {
            if (!NeedToHandleNeighbors(ref pos))
            {
                return;
            }

            int cx = chunk.pos.x;
            int cy = chunk.pos.y;
            int cz = chunk.pos.z;

            ChunkStateManagerClient stateManager = chunk.stateManager;

            // If it is an edge position, notify neighbor as well
            // Iterate over neighbors and decide which ones should be notified to rebuild their geometry
            var listeners = stateManager.Listeners;

            for (int i = 0; i < listeners.Length; i++)
            {
                ChunkEvent listener = listeners[i];
                if (listener == null)
                {
                    continue;
                }

                ChunkStateManagerClient listenerClient = (ChunkStateManagerClient)listener;
                Chunk       listenerChunk       = listenerClient.chunk;
                ChunkBlocks listenerChunkBlocks = listenerChunk.blocks;

                int lx = listenerChunk.pos.x;
                int ly = listenerChunk.pos.y;
                int lz = listenerChunk.pos.z;

                if (ly == cy || lz == cz)
                {
                    // Section to the left
                    if ((pos.x == 0) && (lx + m_sideSize == cx))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(m_sideSize, pos.y, pos.z, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                    // Section to the right
                    else if ((pos.x == (m_sideSize - 1)) && (lx - m_sideSize == cx))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(-1, pos.y, pos.z, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                }

                if (lx == cx || lz == cz)
                {
                    // Section to the bottom
                    if ((pos.y == 0) && (ly + m_sideSize == cy))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(pos.x, m_sideSize, pos.z, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                    // Section to the top
                    else if ((pos.y == (m_sideSize - 1)) && (ly - m_sideSize == cy))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(pos.x, -1, pos.z, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                }

                if (ly == cy || lx == cx)
                {
                    // Section to the back
                    if ((pos.z == 0) && (lz + m_sideSize == cz))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(pos.x, pos.y, m_sideSize, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                    // Section to the front
                    else if ((pos.z == (m_sideSize - 1)) && (lz - m_sideSize == cz))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(pos.x, pos.y, -1, m_pow);
                        listenerChunkBlocks[neighborIndex] = block;
                    }
                }

                // No further checks needed once we know all neighbors need to be notified
                if (rebuildMaskGeometry == 0x3f)
                {
                    break;
                }
            }
        }
コード例 #19
0
        private void OnDrawGizmosSelected()
        {
            int size      = Mathf.FloorToInt(Env.ChunkSize * Env.BlockSize);
            int halfSize  = size >> 1;
            int smallSize = size >> 4;

            if (world != null && world.chunks != null && (Diag_DrawWorldBounds || Diag_DrawLoadRange))
            {
                foreach (Chunk chunk in world.chunks.chunkCollection)
                {
                    if (Diag_DrawWorldBounds)
                    {
                        Gizmos.color = Color.blue;
                        Gizmos.DrawWireCube(chunk.WorldBounds.center, chunk.WorldBounds.size);
                    }

                    if (Diag_DrawLoadRange)
                    {
                        Vector3Int pos = chunk.pos;

                        if (chunk.pos.y == 0)
                        {
                            int tx = m_clipmap.TransformX(pos.x >> Env.ChunkPower);
                            int ty = m_clipmap.TransformY(pos.y >> Env.ChunkPower);
                            int tz = m_clipmap.TransformZ(pos.z >> Env.ChunkPower);

                            if (!m_clipmap.IsInsideBounds_Transformed(tx, ty, tz))
                            {
                                Gizmos.color = Color.red;
                                Gizmos.DrawWireCube(
                                    new Vector3(pos.x + halfSize, 0, pos.z + halfSize),
                                    new Vector3(size - 0.05f, 0, size - 0.05f)
                                    );
                            }
                            else
                            {
                                ClipmapItem item = m_clipmap.Get_Transformed(tx, ty, tz);
                                if (item.IsWithinVisibleRange)
                                {
                                    Gizmos.color = Color.green;
                                    Gizmos.DrawWireCube(
                                        new Vector3(pos.x + halfSize, 0, pos.z + halfSize),
                                        new Vector3(size - 0.05f, 0, size - 0.05f)
                                        );
                                }
                                else // if (item.IsWithinCachedRange)
                                {
                                    Gizmos.color = Color.yellow;
                                    Gizmos.DrawWireCube(
                                        new Vector3(pos.x + halfSize, 0, pos.z + halfSize),
                                        new Vector3(size - 0.05f, 0, size - 0.05f)
                                        );
                                }
                            }
                        }

                        // Show generated chunks
                        ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;
                        if (stateManager.IsStateCompleted(ChunkState.Generate))
                        {
                            Gizmos.color = Color.magenta;
                            Gizmos.DrawWireCube(
                                new Vector3(pos.x + halfSize, pos.y + halfSize, pos.z + halfSize),
                                new Vector3(smallSize - 0.05f, smallSize - 0.05f, smallSize - 0.05f)
                                );
                        }
                    }
                }
            }
        }
コード例 #20
0
        public void ProcessChunk(Chunk chunk)
        {
            int xd = Helpers.Abs((m_viewerPos.x - chunk.pos.x) >> Env.ChunkPower);
            int yd = Helpers.Abs((m_viewerPos.y - chunk.pos.y) >> Env.ChunkPower);
            int zd = Helpers.Abs((m_viewerPos.z - chunk.pos.z) >> Env.ChunkPower);

            int tx = m_clipmap.TransformX(chunk.pos.x >> Env.ChunkPower);
            int ty = m_clipmap.TransformY(chunk.pos.y >> Env.ChunkPower);
            int tz = m_clipmap.TransformZ(chunk.pos.z >> Env.ChunkPower);

            ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;

            // Chunk is too far away. Remove it
            if (!m_clipmap.IsInsideBounds_Transformed(tx, ty, tz))
            {
                stateManager.RequestState(ChunkState.Remove);
            }
            else
            {
                // Dummy collider example - create a collider for chunks directly surrounding the viewer
                chunk.NeedsCollider = xd <= 1 && yd <= 1 && zd <= 1;

                // Chunk is within view frustum
                if (FullLoadOnStartUp || IsChunkInViewFrustum(chunk))
                {
                    ClipmapItem item = m_clipmap.Get_Transformed(tx, ty, tz);

                    // Chunk is within visibilty range. Full update with geometry generation is possible
                    if (item.IsWithinVisibleRange)
                    {
                        //chunk.LOD = item.LOD;
                        stateManager.PossiblyVisible = true;
                        stateManager.Visible         = true;
                    }
                    // Chunk is within cached range. Full update except for geometry generation
                    else // if (item.IsWithinCachedRange)
                    {
                        //chunk.LOD = item.LOD;
                        stateManager.PossiblyVisible = true;
                        stateManager.Visible         = false;
                    }
                }
                else
                {
                    ClipmapItem item = m_clipmap.Get_Transformed(tx, ty, tz);

                    // Chunk is not in the view frustum but still within cached range
                    if (item.IsWithinCachedRange)
                    {
                        //chunk.LOD = item.LOD;
                        stateManager.PossiblyVisible = false;
                        stateManager.Visible         = false;
                    }
                    else
                    // Weird state
                    {
                        Assert.IsFalse(true);
                        stateManager.RequestState(ChunkState.Remove);
                    }
                }
            }
        }
コード例 #21
0
ファイル: Chunk.cs プロジェクト: bejita968/Voxe
        private void ProcessSetBlockQueue()
        {
            if (m_setBlockQueue.Count <= 0)
            {
                return;
            }

            StateManager.RequestState(ChunkState.FinalizeData | ChunkState.BuildVerticesNow);

            int rebuildMask = 0;

            // Modify blocks
            for (int j = 0; j < m_setBlockQueue.Count; j++)
            {
                SetBlockContext context = m_setBlockQueue[j];

                int x, y, z;
                Helpers.GetIndex3DFrom1D(context.Index, out x, out y, out z);
                this[x, y, z] = context.Block;

                if (
                    // Only check neighbors if it is still needed
                    rebuildMask == 0x3f ||
                    // Only check neighbors when it is a change of a block on a chunk's edge
                    (((x + 1) & EngineSettings.ChunkConfig.Mask) > 1 &&
                     ((y + 1) & EngineSettings.ChunkConfig.Mask) > 1 &&
                     ((z + 1) & EngineSettings.ChunkConfig.Mask) > 1)
                    )
                {
                    continue;
                }

                int cx = Pos.X;
                int cy = Pos.Y;
                int cz = Pos.Z;

                // If it is an edge position, notify neighbor as well
                // Iterate over neighbors and decide which ones should be notified to rebuild
                for (int i = 0; i < StateManager.Listeners.Length; i++)
                {
                    ChunkEvent listener = StateManager.Listeners[i];
                    if (listener == null)
                    {
                        continue;
                    }

                    // No further checks needed once we know all neighbors need to be notified
                    if (rebuildMask == 0x3f)
                    {
                        break;
                    }

                    ChunkStateManagerClient listenerChunk = (ChunkStateManagerClient)listener;

                    int lx = listenerChunk.chunk.Pos.X;
                    int ly = listenerChunk.chunk.Pos.Y;
                    int lz = listenerChunk.chunk.Pos.Z;

                    if ((ly == cy || lz == cz) &&
                        (
                            // Section to the left
                            ((x == 0) && (lx + EngineSettings.ChunkConfig.Mask == cx)) ||
                            // Section to the right
                            ((x == EngineSettings.ChunkConfig.Mask) && (lx - EngineSettings.ChunkConfig.Mask == cx))
                        ))
                    {
                        rebuildMask = rebuildMask | (1 << i);
                    }

                    if ((lx == cx || lz == cz) &&
                        (
                            // Section to the bottom
                            ((y == 0) && (ly + EngineSettings.ChunkConfig.Mask == cy)) ||
                            // Section to the top
                            ((y == EngineSettings.ChunkConfig.Mask) && (ly - EngineSettings.ChunkConfig.Mask == cy))
                        ))
                    {
                        rebuildMask = rebuildMask | (1 << i);
                    }

                    if ((ly == cy || lx == cx) &&
                        (
                            // Section to the back
                            ((z == 0) && (lz + EngineSettings.ChunkConfig.Mask == cz)) ||
                            // Section to the front
                            ((z == EngineSettings.ChunkConfig.Mask) && (lz - EngineSettings.ChunkConfig.Mask == cz))
                        ))
                    {
                        rebuildMask = rebuildMask | (1 << i);
                    }
                }
            }

            m_setBlockQueue.Clear();

            // Notify neighbors that they need to rebuilt their geometry
            if (rebuildMask > 0)
            {
                for (int j = 0; j < StateManager.Listeners.Length; j++)
                {
                    ChunkStateManagerClient listener = (ChunkStateManagerClient)StateManager.Listeners[j];
                    if (listener != null && ((rebuildMask >> j) & 1) != 0)
                    {
                        listener.RequestState(ChunkState.FinalizeData | ChunkState.BuildVerticesNow);
                    }
                }
            }
        }
コード例 #22
0
        public void Update()
        {
            ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;

            if (m_setBlockQueue.Count > 0)
            {
                if (rebuildMaskGeometry < 0)
                {
                    rebuildMaskGeometry = 0;
                }
                if (rebuildMaskCollider < 0)
                {
                    rebuildMaskCollider = 0;
                }

                // Modify blocks
                for (int j = 0; j < m_setBlockQueue.Count; j++)
                {
                    SetBlockContext context = m_setBlockQueue[j];

                    if (!context.IsRange())
                    {
                        ProcessSetBlockQueue(context.Block, context.IndexFrom, context.SetBlockModified);
                    }
                    else
                    {
                        int sx, sy, sz, ex, ey, ez;
                        Helpers.GetChunkIndex3DFrom1D(context.IndexFrom, out sx, out sy, out sz);
                        Helpers.GetChunkIndex3DFrom1D(context.IndexTo, out ex, out ey, out ez);

                        for (int y = sy; y <= ey; y++)
                        {
                            for (int z = sz; z <= ez; z++)
                            {
                                for (int x = sx; x <= ex; x++)
                                {
                                    int index = Helpers.GetChunkIndex1DFrom3D(x, y, z);
                                    ProcessSetBlockQueue(context.Block, index, context.SetBlockModified);
                                }
                            }
                        }
                    }
                }

                rebuildMaskCollider |= rebuildMaskGeometry;

                m_setBlockQueue.Clear();
            }

            long now = Globals.Watch.ElapsedMilliseconds;

            // Request a geometry update at most 10 times a second
            if (rebuildMaskGeometry >= 0 && now - lastUpdateTimeGeometry >= 100)
            {
                lastUpdateTimeGeometry = now;

                // Request rebuild on this chunk
                stateManager.RequestState(ChunkState.BuildVerticesNow);;

                // Notify neighbors that they need to rebuilt their geometry
                if (rebuildMaskGeometry > 0)
                {
                    for (int j = 0; j < stateManager.Listeners.Length; j++)
                    {
                        ChunkStateManagerClient listener = (ChunkStateManagerClient)stateManager.Listeners[j];
                        if (listener != null && ((rebuildMaskGeometry >> j) & 1) != 0)
                        {
                            // Request rebuild on neighbor chunks
                            listener.RequestState(ChunkState.BuildVerticesNow);
                        }
                    }
                }

                rebuildMaskGeometry = -1;
            }

            // Request a collider update at most 4 times a second
            if (chunk.NeedsCollider && rebuildMaskCollider >= 0 && now - lastUpdateTimeCollider >= 250)
            {
                lastUpdateTimeCollider = now;

                // Request rebuild on this chunk
                stateManager.RequestState(ChunkState.BuildCollider);

                // Notify neighbors that they need to rebuilt their geometry
                if (rebuildMaskCollider > 0)
                {
                    for (int j = 0; j < stateManager.Listeners.Length; j++)
                    {
                        ChunkStateManagerClient listener = (ChunkStateManagerClient)stateManager.Listeners[j];
                        if (listener != null && ((rebuildMaskCollider >> j) & 1) != 0)
                        {
                            // Request rebuild on neighbor chunks
                            if (listener.chunk.NeedsCollider)
                            {
                                listener.RequestState(ChunkState.BuildCollider);
                            }
                        }
                    }
                }

                rebuildMaskCollider = -1;
            }
        }
コード例 #23
0
        private void ProcessSetBlockQueue(BlockData block, int index, bool setBlockModified)
        {
            int x, y, z;

            Helpers.GetChunkIndex3DFrom1D(index, out x, out y, out z);

            if (x < 0 || y < 0 || z < 0 || x > Env.ChunkMask || y > Env.ChunkMask || z > Env.ChunkMask)
            {
                Assert.IsTrue(false, "Chunk index out of range in setBlockQueue");
                return;
            }

            Vector3Int pos       = new Vector3Int(x, y, z);
            Vector3Int globalPos = pos + chunk.pos;

            BlockData oldBlockData = blocks[index];

            Block oldBlock = m_blockTypes[oldBlockData.Type];
            Block newBlock = m_blockTypes[block.Type];

            oldBlock.OnDestroy(chunk, pos);
            newBlock.OnCreate(chunk, pos);

            SetInternal(index, ref pos, block);

            if (setBlockModified)
            {
                BlockModified(new BlockPos(x, y, z), globalPos, block);

                chunk.blocks.contentsInvalidated = true;
            }

            if (
                // Only check neighbors if it is still needed
                rebuildMaskGeometry == 0x3f ||
                // Only check neighbors when it is a change of a block on a chunk's edge
                (((pos.x + 1) & Env.ChunkMask) > 1 &&
                 ((pos.y + 1) & Env.ChunkMask) > 1 &&
                 ((pos.z + 1) & Env.ChunkMask) > 1)
                )
            {
                return;
            }

            int cx = chunk.pos.x;
            int cy = chunk.pos.y;
            int cz = chunk.pos.z;

            ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;

            // If it is an edge position, notify neighbor as well
            // Iterate over neighbors and decide which ones should be notified to rebuild
            for (int i = 0; i < stateManager.Listeners.Length; i++)
            {
                ChunkEvent listener = stateManager.Listeners[i];
                if (listener == null)
                {
                    continue;
                }

                // No further checks needed once we know all neighbors need to be notified
                if (rebuildMaskGeometry == 0x3f)
                {
                    break;
                }

                ChunkStateManagerClient listenerClient = (ChunkStateManagerClient)listener;
                Chunk listenerChunk = listenerClient.chunk;

                int lx = listenerChunk.pos.x;
                int ly = listenerChunk.pos.y;
                int lz = listenerChunk.pos.z;

                if (ly == cy || lz == cz)
                {
                    // Section to the left
                    if ((pos.x == 0) && (lx + Env.ChunkSize == cx))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(Env.ChunkSize, y, z);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                    // Section to the right
                    else if ((pos.x == Env.ChunkMask) && (lx - Env.ChunkSize == cx))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(-1, y, z);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                }

                if (lx == cx || lz == cz)
                {
                    // Section to the bottom
                    if ((pos.y == 0) && (ly + Env.ChunkSize == cy))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(x, Env.ChunkSize, y);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                    // Section to the top
                    else if ((pos.y == Env.ChunkMask) && (ly - Env.ChunkSize == cy))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(x, -1, y);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                }

                if (ly == cy || lx == cx)
                {
                    // Section to the back
                    if ((pos.z == 0) && (lz + Env.ChunkSize == cz))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(x, y, Env.ChunkSize);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                    // Section to the front
                    else if ((pos.z == Env.ChunkMask) && (lz - Env.ChunkSize == cz))
                    {
                        rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);

                        // Mirror the block to the neighbor edge
                        int neighborIndex = Helpers.GetChunkIndex1DFrom3D(x, y, -1);
                        listenerChunk.blocks.blocks[neighborIndex] = block;
                    }
                }
            }
        }
コード例 #24
0
ファイル: ChunkBlocks.cs プロジェクト: TrueLoop/Voxelmetric
        public void Update()
        {
            ChunkStateManagerClient stateManager = (ChunkStateManagerClient)chunk.stateManager;

            if (m_setBlockQueue.Count > 0)
            {
                if (rebuildMaskGeometry < 0)
                {
                    rebuildMaskGeometry = 0;
                }
                if (rebuildMaskCollider < 0)
                {
                    rebuildMaskCollider = 0;
                }

                // Modify blocks
                for (int j = 0; j < m_setBlockQueue.Count; j++)
                {
                    SetBlockContext context = m_setBlockQueue[j];

                    int x, y, z;
                    Helpers.GetChunkIndex3DFrom1D(context.Index, out x, out y, out z);

                    Vector3Int pos       = new Vector3Int(x, y, z);
                    Vector3Int globalPos = pos + chunk.pos;

                    BlockData oldBlockData = blocks.Get(context.Index);

                    Block oldBlock = m_blockTypes[oldBlockData.Type];
                    Block newBlock = m_blockTypes[context.Block.Type];
                    oldBlock.OnDestroy(chunk, pos, globalPos);
                    newBlock.OnCreate(chunk, pos, globalPos);

                    blocks.Set(context.Index, context.Block);

                    if (context.SetBlockModified)
                    {
                        BlockModified(new BlockPos(x, y, z), globalPos, context.Block);

                        chunk.blocks.contentsInvalidated = true;
                    }

                    if (
                        // Only check neighbors if it is still needed
                        rebuildMaskGeometry == 0x3f ||
                        // Only check neighbors when it is a change of a block on a chunk's edge
                        (((pos.x + 1) & Env.ChunkMask) > 1 &&
                         ((pos.y + 1) & Env.ChunkMask) > 1 &&
                         ((pos.z + 1) & Env.ChunkMask) > 1)
                        )
                    {
                        continue;
                    }

                    int cx = chunk.pos.x;
                    int cy = chunk.pos.y;
                    int cz = chunk.pos.z;

                    // If it is an edge position, notify neighbor as well
                    // Iterate over neighbors and decide which ones should be notified to rebuild
                    for (int i = 0; i < stateManager.Listeners.Length; i++)
                    {
                        ChunkEvent listener = stateManager.Listeners[i];
                        if (listener == null)
                        {
                            continue;
                        }

                        // No further checks needed once we know all neighbors need to be notified
                        if (rebuildMaskGeometry == 0x3f)
                        {
                            break;
                        }

                        ChunkStateManagerClient listenerChunk = (ChunkStateManagerClient)listener;

                        int lx = listenerChunk.chunk.pos.x;
                        int ly = listenerChunk.chunk.pos.y;
                        int lz = listenerChunk.chunk.pos.z;

                        if ((ly == cy || lz == cz) &&
                            (
                                // Section to the left
                                ((pos.x == 0) && (lx + Env.ChunkSize == cx)) ||
                                // Section to the right
                                ((pos.x == Env.ChunkMask) && (lx - Env.ChunkSize == cx))
                            ))
                        {
                            rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);
                        }

                        if ((lx == cx || lz == cz) &&
                            (
                                // Section to the bottom
                                ((pos.y == 0) && (ly + Env.ChunkSize == cy)) ||
                                // Section to the top
                                ((pos.y == Env.ChunkMask) && (ly - Env.ChunkSize == cy))
                            ))
                        {
                            rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);
                        }

                        if ((ly == cy || lx == cx) &&
                            (
                                // Section to the back
                                ((pos.z == 0) && (lz + Env.ChunkSize == cz)) ||
                                // Section to the front
                                ((pos.z == Env.ChunkMask) && (lz - Env.ChunkSize == cz))
                            ))
                        {
                            rebuildMaskGeometry = rebuildMaskGeometry | (1 << i);
                        }
                    }

                    rebuildMaskCollider |= rebuildMaskGeometry;
                }

                m_setBlockQueue.Clear();
            }

            long now = Globals.Watch.ElapsedMilliseconds;

            // Request a geometry update at most 10 times a second
            if (rebuildMaskGeometry >= 0 && now - lastUpdateTimeGeometry >= 100)
            {
                lastUpdateTimeGeometry = now;

                // Request rebuild on this chunk
                stateManager.RequestState(ChunkState.BuildVerticesNow);;

                // Notify neighbors that they need to rebuilt their geometry
                if (rebuildMaskGeometry > 0)
                {
                    for (int j = 0; j < stateManager.Listeners.Length; j++)
                    {
                        ChunkStateManagerClient listener = (ChunkStateManagerClient)stateManager.Listeners[j];
                        if (listener != null && ((rebuildMaskGeometry >> j) & 1) != 0)
                        {
                            // Request rebuild on neighbor chunks
                            listener.RequestState(ChunkState.BuildVerticesNow);
                        }
                    }
                }

                rebuildMaskGeometry = -1;
            }

            // Request a collider update at most 4 times a second
            if (chunk.NeedsCollider && rebuildMaskCollider >= 0 && now - lastUpdateTimeCollider >= 250)
            {
                lastUpdateTimeCollider = now;

                // Request rebuild on this chunk
                stateManager.RequestState(ChunkState.BuildCollider);

                // Notify neighbors that they need to rebuilt their geometry
                if (rebuildMaskCollider > 0)
                {
                    for (int j = 0; j < stateManager.Listeners.Length; j++)
                    {
                        ChunkStateManagerClient listener = (ChunkStateManagerClient)stateManager.Listeners[j];
                        if (listener != null && ((rebuildMaskCollider >> j) & 1) != 0)
                        {
                            // Request rebuild on neighbor chunks
                            if (listener.chunk.NeedsCollider)
                            {
                                listener.RequestState(ChunkState.BuildCollider);
                            }
                        }
                    }
                }

                rebuildMaskCollider = -1;
            }
        }
コード例 #25
0
        private void OnDrawGizmosSelected()
        {
            if (!enabled)
            {
                return;
            }

            float size      = Env.ChunkSize * Env.BlockSize;
            float halfSize  = size * 0.5f;
            float smallSize = size * 0.25f;

            if (world != null && world.chunks != null && (Diag_DrawWorldBounds || Diag_DrawLoadRange))
            {
                foreach (Chunk chunk in world.chunks.chunkCollection)
                {
                    if (Diag_DrawWorldBounds)
                    {
                        // Make central chunks more apparent by using yellow color
                        bool isCentral = chunk.pos.x == m_viewerPos.x || chunk.pos.y == m_viewerPos.y || chunk.pos.z == m_viewerPos.z;
                        Gizmos.color = isCentral ? Color.yellow : Color.blue;
                        Vector3 chunkCenter = new Vector3(
                            chunk.pos.x + (Env.ChunkSize >> 1),
                            chunk.pos.y + (Env.ChunkSize >> 1),
                            chunk.pos.z + (Env.ChunkSize >> 1)
                            );
                        Vector3 chunkSize = new Vector3(Env.ChunkSize, Env.ChunkSize, Env.ChunkSize);
                        Gizmos.DrawWireCube(chunkCenter, chunkSize);
                    }

                    if (Diag_DrawLoadRange)
                    {
                        Vector3Int pos = chunk.pos;

                        if (chunk.pos.y == 0)
                        {
                            int tx = m_clipmap.TransformX(pos.x / Env.ChunkSize);
                            int ty = m_clipmap.TransformY(pos.y / Env.ChunkSize);
                            int tz = m_clipmap.TransformZ(pos.z / Env.ChunkSize);

                            if (!m_clipmap.IsInsideBounds_Transformed(tx, ty, tz))
                            {
                                Gizmos.color = Color.red;
                                Gizmos.DrawWireCube(
                                    new Vector3(pos.x + halfSize, 0, pos.z + halfSize),
                                    new Vector3(size - 1f, 0, size - 1f)
                                    );
                            }
                            else
                            {
                                ClipmapItem item = m_clipmap.Get_Transformed(tx, ty, tz);
                                if (item.IsInVisibleRange)
                                {
                                    Gizmos.color = Color.green;
                                    Gizmos.DrawWireCube(
                                        new Vector3(pos.x + halfSize, 0, pos.z + halfSize),
                                        new Vector3(size - 1f, 0, size - 1f)
                                        );
                                }
                            }
                        }

                        // Show generated chunks
                        ChunkStateManagerClient stateManager = chunk.stateManager;
                        if (stateManager.IsStateCompleted(ChunkState.Generate))
                        {
                            Gizmos.color = Color.magenta;
                            Gizmos.DrawWireCube(
                                new Vector3(pos.x + halfSize, pos.y + halfSize, pos.z + halfSize),
                                new Vector3(smallSize - 0.05f, smallSize - 0.05f, smallSize - 0.05f)
                                );
                        }
                    }
                }
            }
        }
コード例 #26
0
        private void UpdateVisibility(int x, int y, int z, int rangeX, int rangeY, int rangeZ)
        {
            if (rangeX == 0 || rangeY == 0 || rangeZ == 0)
            {
                return;
            }

            bool isLast = rangeX == 1 && rangeY == 1 && rangeZ == 1;

            int wx = x * Env.ChunkSize;
            int wy = y * Env.ChunkSize;
            int wz = z * Env.ChunkSize;

            // Stop if there is no further subdivision possible
            if (isLast)
            {
                // Update chunk's visibility information
                Vector3Int chunkPos = new Vector3Int(wx, wy, wz);
                Chunk      chunk    = world.chunks.Get(ref chunkPos);
                if (chunk == null)
                {
                    return;
                }

                ChunkStateManagerClient stateManager = chunk.stateManager;

                int xd = (m_viewerPos.x - chunk.pos.x) / Env.ChunkSize;
                int yd = (m_viewerPos.y - chunk.pos.y) / Env.ChunkSize;
                int zd = (m_viewerPos.z - chunk.pos.z) / Env.ChunkSize;

                int xDist = xd * xd + zd * zd;
                int yDist = yd * yd;

                // Update visibility information
                bool isVisible = Planes.TestPlanesAABB(m_cameraPlanes, chunk.WorldBounds);

                stateManager.Visible = isVisible &&
                                       xDist <= HorizontalChunkLoadRadius * HorizontalChunkLoadRadius &&
                                       yDist <= VerticalChunkLoadRadius * VerticalChunkLoadRadius;
                stateManager.PossiblyVisible = isVisible || FullLoadOnStartUp;

                return;
            }

            int rx = rangeX * Env.ChunkSize;
            int ry = rangeY * Env.ChunkSize;
            int rz = rangeZ * Env.ChunkSize;

            /*AABB bounds2 = new AABB(wx, wy, wz, wx+rx, wy+ry, wz+rz);
             * int inside = 0;
             *
             * // if the camera position lies inside the bounding box we'll assume partial visibility automatically
             * if (bounds2.IsInside(m_camera.transform.position))
             *  inside = 3;
             * else
             * {
             *  // Check whether the bouding box lies inside the camera's frustum
             *  inside = Geometry.TestPlanesAABB2(m_cameraPlanes, bounds2);
             * }*/
            // Check whether the bouding box lies inside the camera's frustum
            AABB bounds2 = new AABB(wx, wy, wz, wx + rx, wy + ry, wz + rz);
            int  inside  = Planes.TestPlanesAABB2(m_cameraPlanes, bounds2);

            #region Full invisibility

            if (inside == 0)
            {
                // Full invisibility. All chunks in this area need to be made invisible
                for (int cy = wy; cy < wy + ry; cy += Env.ChunkSize)
                {
                    for (int cz = wz; cz < wz + rz; cz += Env.ChunkSize)
                    {
                        for (int cx = wx; cx < wx + rx; cx += Env.ChunkSize)
                        {
                            // Update chunk's visibility information
                            Vector3Int chunkPos = new Vector3Int(cx, cy, cz);
                            Chunk      chunk    = world.chunks.Get(ref chunkPos);
                            if (chunk == null)
                            {
                                continue;
                            }

                            ChunkStateManagerClient stateManager = chunk.stateManager;

                            // Update visibility information
                            stateManager.PossiblyVisible = FullLoadOnStartUp;
                            stateManager.Visible         = false;
                        }
                    }
                }

                return;
            }

            #endregion

            #region Full visibility

            if (inside == 6)
            {
                // Full visibility. All chunks in this area need to be made visible
                for (int cy = wy; cy < wy + ry; cy += Env.ChunkSize)
                {
                    for (int cz = wz; cz < wz + rz; cz += Env.ChunkSize)
                    {
                        for (int cx = wx; cx < wx + rx; cx += Env.ChunkSize)
                        {
                            // Update chunk's visibility information
                            Vector3Int chunkPos = new Vector3Int(cx, cy, cz);
                            Chunk      chunk    = world.chunks.Get(ref chunkPos);
                            if (chunk == null)
                            {
                                continue;
                            }

                            ChunkStateManagerClient stateManager = chunk.stateManager;

                            int xd = (m_viewerPos.x - chunk.pos.x) / Env.ChunkSize;
                            int yd = (m_viewerPos.y - chunk.pos.y) / Env.ChunkSize;
                            int zd = (m_viewerPos.z - chunk.pos.z) / Env.ChunkSize;

                            int xDist = xd * xd + zd * zd;
                            int yDist = yd * yd;

                            // Update visibility information
                            stateManager.Visible = xDist <= HorizontalChunkLoadRadius * HorizontalChunkLoadRadius &&
                                                   yDist <= VerticalChunkLoadRadius * VerticalChunkLoadRadius;
                            stateManager.PossiblyVisible = true;
                        }
                    }
                }

                return;
            }

            #endregion

            #region Partial visibility

            int offX = rangeX;
            if (rangeX > 1)
            {
                offX   = rangeX >> 1;
                rangeX = (rangeX + 1) >> 1; // ceil the number
            }
            int offY = rangeY;
            if (rangeY > 1)
            {
                offY   = rangeY >> 1;
                rangeY = (rangeY + 1) >> 1; // ceil the number
            }
            int offZ = rangeZ;
            if (rangeZ > 1)
            {
                offZ   = rangeZ >> 1;
                rangeZ = (rangeZ + 1) >> 1; // ceil the number
            }

            // Subdivide if possible
            // TODO: Avoid the recursion
            UpdateVisibility(x, y, z, offX, offY, offZ);
            UpdateVisibility(x + offX, y, z, rangeX, offY, offZ);
            UpdateVisibility(x, y, z + offZ, offX, offY, rangeZ);
            UpdateVisibility(x + offX, y, z + offZ, rangeX, offY, rangeZ);
            UpdateVisibility(x, y + offY, z, offX, rangeY, offZ);
            UpdateVisibility(x + offX, y + offY, z, rangeX, rangeY, offZ);
            UpdateVisibility(x, y + offY, z + offZ, offX, rangeY, rangeZ);
            UpdateVisibility(x + offX, y + offY, z + offZ, rangeX, rangeY, rangeZ);

            #endregion
        }
コード例 #27
0
        private void OnDrawGizmosSelected()
        {
            if (!enabled)
            {
                return;
            }

            float size      = Env.ChunkSize * Env.BlockSize;
            float halfSize  = size * 0.5f;
            float smallSize = size * 0.25f;

            if (world != null && world.chunks != null && (Diag_DrawWorldBounds || Diag_DrawLoadRange))
            {
                foreach (Chunk chunk in world.chunks.chunkCollection)
                {
                    if (Diag_DrawWorldBounds)
                    {
                        // Make central chunks more apparent by using yellow color
                        bool isCentral = chunk.pos.x == m_viewerPos.x || chunk.pos.y == m_viewerPos.y || chunk.pos.z == m_viewerPos.z;
                        Gizmos.color = isCentral ? Color.yellow : Color.blue;
                        Vector3 chunkCenter = new Vector3(
                            chunk.pos.x + (Env.ChunkSize >> 1),
                            chunk.pos.y + (Env.ChunkSize >> 1),
                            chunk.pos.z + (Env.ChunkSize >> 1)
                            );
                        Vector3 chunkSize = new Vector3(Env.ChunkSize, Env.ChunkSize, Env.ChunkSize);
                        Gizmos.DrawWireCube(chunkCenter, chunkSize);
                    }

                    if (Diag_DrawLoadRange)
                    {
                        Vector3Int pos  = chunk.pos;
                        int        xd   = Helpers.Abs((m_viewerPos.x - pos.x) / Env.ChunkSize);
                        int        zd   = Helpers.Abs((m_viewerPos.z - pos.z) / Env.ChunkSize);
                        int        dist = xd * xd + zd * zd;
                        if (dist <= HorizontalChunkLoadRadius * HorizontalChunkLoadRadius)
                        {
                            Gizmos.color = Color.green;
                            Gizmos.DrawWireCube(
                                new Vector3(chunk.pos.x + halfSize, 0, chunk.pos.z + halfSize),
                                new Vector3(size - 1f, 0, size - 1f)
                                );
                        }
                        else
                        {
                            Gizmos.color = Color.red;
                            Gizmos.DrawWireCube(
                                new Vector3(chunk.pos.x + halfSize, 0, chunk.pos.z + halfSize),
                                new Vector3(size - 1f, 0, size - 1f)
                                );
                        }

                        // Show generated chunks
                        ChunkStateManagerClient stateManager = chunk.stateManager;
                        if (stateManager.IsStateCompleted(ChunkState.Generate))
                        {
                            Gizmos.color = Color.magenta;
                            Gizmos.DrawWireCube(
                                new Vector3(chunk.pos.x + halfSize, 0, chunk.pos.z + halfSize),
                                new Vector3(smallSize - 0.05f, 0, smallSize - 0.05f)
                                );
                        }
                    }
                }
            }
        }
コード例 #28
0
        public void PostProcessChunks()
        {
            int minX = m_viewerPos.x - (HorizontalChunkLoadRadius * Env.ChunkSize);
            int maxX = m_viewerPos.x + (HorizontalChunkLoadRadius * Env.ChunkSize);
            int minY = m_viewerPos.y - (VerticalChunkLoadRadius * Env.ChunkSize);
            int maxY = m_viewerPos.y + (VerticalChunkLoadRadius * Env.ChunkSize);
            int minZ = m_viewerPos.z - (HorizontalChunkLoadRadius * Env.ChunkSize);
            int maxZ = m_viewerPos.z + (HorizontalChunkLoadRadius * Env.ChunkSize);

            world.CapCoordXInsideWorld(ref minX, ref maxX);
            world.CapCoordYInsideWorld(ref minY, ref maxY);
            world.CapCoordZInsideWorld(ref minZ, ref maxZ);

            world.Bounds = new AABBInt(minX, minY, minZ, maxX, maxY, maxZ);

            int expectedChunks = m_chunkPositions.Length * ((maxY - minY + Env.ChunkSize) / Env.ChunkSize);

            if (// No update necessary if there was no movement
                m_viewerPos == m_viewerPosPrev &&
                // However, we need to make sure that we have enough chunks loaded
                world.chunks.Count >= expectedChunks)
            {
                return;
            }

            // Unregister any non-necessary pending structures
            Profiler.BeginSample("UnregisterStructures");
            {
                world.UnregisterPendingStructures();
            }
            Profiler.EndSample();

            // Cycle through the array of positions
            Profiler.BeginSample("PostProcessChunks");
            {
                WorldChunks chunks = world.chunks;

                // Cycle through the array of positions
                for (int y = maxY; y >= minY; y -= Env.ChunkSize)
                {
                    for (int i = 0; i < m_chunkPositions.Length; i++)
                    {
                        // Skip loading chunks which are off limits
                        int cx = (m_chunkPositions[i].x * Env.ChunkSize) + m_viewerPos.x;
                        if (cx > maxX || cx < minX)
                        {
                            continue;
                        }
                        int cy = (m_chunkPositions[i].y * Env.ChunkSize) + y;
                        if (cy > maxY || cy < minY)
                        {
                            continue;
                        }
                        int cz = (m_chunkPositions[i].z * Env.ChunkSize) + m_viewerPos.z;
                        if (cz > maxZ || cz < minZ)
                        {
                            continue;
                        }

                        // Create a new chunk if possible
                        Vector3Int newChunkPos = new Vector3Int(cx, cy, cz);
                        Chunk      chunk;
                        if (!chunks.CreateOrGetChunk(ref newChunkPos, out chunk))
                        {
                            continue;
                        }

                        if (FullLoadOnStartUp)
                        {
                            ChunkStateManagerClient stateManager = chunk.stateManager;
                            stateManager.PossiblyVisible = true;
                            stateManager.Visible         = false;
                        }

                        m_updateRequests.Add(chunk);
                    }
                }
            }
            Profiler.EndSample();
        }
コード例 #29
0
        private void UpdateVisibility(int x, int y, int z, int rangeX, int rangeY, int rangeZ)
        {
            if (rangeX == 0 || rangeY == 0 || rangeZ == 0)
            {
                return;
            }

            bool isLast = rangeX == 1 && rangeY == 1 && rangeZ == 1;

            int wx = m_viewerPos.x + (x * Env.ChunkSize);
            int wy = m_viewerPos.y + (y * Env.ChunkSize);
            int wz = m_viewerPos.z + (z * Env.ChunkSize);

            int rx = rangeX * Env.ChunkSize;
            int ry = rangeY * Env.ChunkSize;
            int rz = rangeZ * Env.ChunkSize;

            // Stop if there is no further subdivision possible
            if (isLast)
            {
                // Update chunk's visibility information
                Vector3Int chunkPos = new Vector3Int(wx, wy, wz);
                Chunk      chunk    = world.chunks.Get(ref chunkPos);
                if (chunk == null)
                {
                    return;
                }

                ChunkStateManagerClient stateManager = chunk.stateManager;

                int tx = m_clipmap.TransformX(x);
                int ty = m_clipmap.TransformY(y);
                int tz = m_clipmap.TransformZ(z);

                // Skip chunks which are too far away
                if (!m_clipmap.IsInsideBounds_Transformed(tx, ty, tz))
                {
                    return;
                }

                // Update visibility information
                ClipmapItem item      = m_clipmap.Get_Transformed(tx, ty, tz);
                bool        isVisible = Planes.TestPlanesAABB(m_cameraPlanes, chunk.WorldBounds);

                stateManager.Visible         = isVisible && item.IsInVisibleRange;
                stateManager.PossiblyVisible = isVisible || FullLoadOnStartUp;

                return;
            }

            // Check whether the bouding box lies inside the camera's frustum
            AABB bounds2 = new AABB(wx, wy, wz, wx + rx, wy + ry, wz + rz);
            int  inside  = Planes.TestPlanesAABB2(m_cameraPlanes, bounds2);

            #region Full invisibility

            if (inside == 0)
            {
                // Full invisibility. All chunks in this area need to be made invisible
                for (int cy = wy; cy < wy + ry; cy += Env.ChunkSize)
                {
                    for (int cz = wz; cz < wz + rz; cz += Env.ChunkSize)
                    {
                        for (int cx = wx; cx < wx + rx; cx += Env.ChunkSize)
                        {
                            // Update chunk's visibility information
                            Vector3Int chunkPos = new Vector3Int(cx, cy, cz);
                            Chunk      chunk    = world.chunks.Get(ref chunkPos);
                            if (chunk == null)
                            {
                                continue;
                            }

                            ChunkStateManagerClient stateManager = chunk.stateManager;

                            // Update visibility information
                            stateManager.PossiblyVisible = FullLoadOnStartUp;
                            stateManager.Visible         = false;
                        }
                    }
                }

                return;
            }

            #endregion

            #region Full visibility

            if (inside == 6)
            {
                // Full visibility. All chunks in this area need to be made visible
                for (int cy = wy; cy < wy + ry; cy += Env.ChunkSize)
                {
                    for (int cz = wz; cz < wz + rz; cz += Env.ChunkSize)
                    {
                        for (int cx = wx; cx < wx + rx; cx += Env.ChunkSize)
                        {
                            // Update chunk's visibility information
                            Vector3Int chunkPos = new Vector3Int(cx, cy, cz);
                            Chunk      chunk    = world.chunks.Get(ref chunkPos);
                            if (chunk == null)
                            {
                                continue;
                            }

                            ChunkStateManagerClient stateManager = chunk.stateManager;

                            int tx = m_clipmap.TransformX(x);
                            int ty = m_clipmap.TransformY(y);
                            int tz = m_clipmap.TransformZ(z);

                            // Update visibility information
                            ClipmapItem item = m_clipmap.Get_Transformed(tx, ty, tz);

                            stateManager.Visible         = item.IsInVisibleRange;
                            stateManager.PossiblyVisible = true;
                        }
                    }
                }

                return;
            }

            #endregion

            #region Partial visibility

            int offX = rangeX;
            if (rangeX > 1)
            {
                offX   = rangeX >> 1;
                rangeX = (rangeX + 1) >> 1; // ceil the number
            }
            int offY = rangeY;
            if (rangeY > 1)
            {
                offY   = rangeY >> 1;
                rangeY = (rangeY + 1) >> 1; // ceil the number
            }
            int offZ = rangeZ;
            if (rangeZ > 1)
            {
                offZ   = rangeZ >> 1;
                rangeZ = (rangeZ + 1) >> 1; // ceil the number
            }

            // Subdivide if possible
            // TODO: Avoid the recursion
            UpdateVisibility(x, y, z, offX, offY, offZ);
            UpdateVisibility(x + offX, y, z, rangeX, offY, offZ);
            UpdateVisibility(x, y, z + offZ, offX, offY, rangeZ);
            UpdateVisibility(x + offX, y, z + offZ, rangeX, offY, rangeZ);
            UpdateVisibility(x, y + offY, z, offX, rangeY, offZ);
            UpdateVisibility(x + offX, y + offY, z, rangeX, rangeY, offZ);
            UpdateVisibility(x, y + offY, z + offZ, offX, rangeY, rangeZ);
            UpdateVisibility(x + offX, y + offY, z + offZ, rangeX, rangeY, rangeZ);

            #endregion
        }