Ejemplo n.º 1
0
        /// <summary>
        /// Propagates the -X/-Y/-Z border voxels to the padding of the -X/-Y/-Z adjacent chunks
        /// </summary>
        private void PropagatePadding()
        {
            var jobs = new List <JobHandle>();

            world.GetChunk(ChunkPos.FromChunk(Pos.x - 1, Pos.y, Pos.z))?.ScheduleUpdatePadding(this, jobs);
            world.GetChunk(ChunkPos.FromChunk(Pos.x, Pos.y - 1, Pos.z))?.ScheduleUpdatePadding(this, jobs);
            world.GetChunk(ChunkPos.FromChunk(Pos.x, Pos.y, Pos.z - 1))?.ScheduleUpdatePadding(this, jobs);

            world.GetChunk(ChunkPos.FromChunk(Pos.x - 1, Pos.y - 1, Pos.z))?.ScheduleUpdatePadding(this, jobs);
            world.GetChunk(ChunkPos.FromChunk(Pos.x - 1, Pos.y, Pos.z - 1))?.ScheduleUpdatePadding(this, jobs);
            world.GetChunk(ChunkPos.FromChunk(Pos.x, Pos.y - 1, Pos.z - 1))?.ScheduleUpdatePadding(this, jobs);

            world.GetChunk(ChunkPos.FromChunk(Pos.x - 1, Pos.y - 1, Pos.z - 1))?.ScheduleUpdatePadding(this, jobs);

            foreach (var handle in jobs)
            {
                handle.Complete();
            }
        }
        public void ApplyGrid <TGridIndexer>(int x, int y, int z, NativeArray3D <Voxel, TGridIndexer> grid, bool propagatePadding, bool includePadding, VoxelEditConsumer <TIndexer> edits, bool writeToChunks = true, bool writeUnsetVoxels = false)
            where TGridIndexer : struct, IIndexer
        {
            int minX = Mathf.FloorToInt((float)x / ChunkSize);
            int minY = Mathf.FloorToInt((float)y / ChunkSize);
            int minZ = Mathf.FloorToInt((float)z / ChunkSize);

            int maxX = Mathf.FloorToInt((float)(x + grid.Length(0)) / ChunkSize);
            int maxY = Mathf.FloorToInt((float)(y + grid.Length(1)) / ChunkSize);
            int maxZ = Mathf.FloorToInt((float)(z + grid.Length(2)) / ChunkSize);

            var handles = new List <VoxelChunk <TIndexer> .FinalizeChange>();

            var watch = System.Diagnostics.Stopwatch.StartNew();

            if (edits != null)
            {
                var snapshots = new List <VoxelChunk <TIndexer> .Snapshot>();

                //Include padding
                int minX2 = Mathf.FloorToInt((float)(x - 1) / ChunkSize);
                int minY2 = Mathf.FloorToInt((float)(y - 1) / ChunkSize);
                int minZ2 = Mathf.FloorToInt((float)(z - 1) / ChunkSize);

                int maxX2 = Mathf.FloorToInt((float)(x + grid.Length(0) + 1) / ChunkSize);
                int maxY2 = Mathf.FloorToInt((float)(y + grid.Length(1) + 1) / ChunkSize);
                int maxZ2 = Mathf.FloorToInt((float)(z + grid.Length(2) + 1) / ChunkSize);

                var snapshotChunks = new List <VoxelChunk <TIndexer> >();

                for (int cx = minX2; cx <= maxX2; cx++)
                {
                    for (int cy = minY2; cy <= maxY2; cy++)
                    {
                        for (int cz = minZ2; cz <= maxZ2; cz++)
                        {
                            ChunkPos chunkPos = ChunkPos.FromChunk(cx, cy, cz);

                            chunks.TryGetValue(chunkPos, out VoxelChunk <TIndexer> chunk);
                            if (chunk != null)
                            {
                                snapshots.Add(chunk.ScheduleSnapshot());
                            }
                            else
                            {
                                snapshotChunks.Add(new VoxelChunk <TIndexer>(this, chunkPos, ChunkSize, IndexerFactory));
                            }
                        }
                    }
                }

                //Finalize clone jobs
                foreach (VoxelChunk <TIndexer> .Snapshot snapshot in snapshots)
                {
                    snapshot.handle.Complete();
                    snapshotChunks.Add(snapshot.chunk);
                }

                //Produce edit
                edits(new VoxelEdit <TIndexer>(this, snapshotChunks));
            }

            if (writeToChunks)
            {
                var changes = new List <VoxelChunk <TIndexer> .Change>();

                //Schedule all jobs
                for (int cx = minX; cx <= maxX; cx++)
                {
                    for (int cy = minY; cy <= maxY; cy++)
                    {
                        for (int cz = minZ; cz <= maxZ; cz++)
                        {
                            ChunkPos chunkPos = ChunkPos.FromChunk(cx, cy, cz);

                            chunks.TryGetValue(chunkPos, out VoxelChunk <TIndexer> chunk);
                            if (chunk == null)
                            {
                                chunks[chunkPos] = chunk = new VoxelChunk <TIndexer>(this, chunkPos, ChunkSize, IndexerFactory);
                            }

                            var gx = (cx - minX) * ChunkSize;
                            var gy = (cy - minY) * ChunkSize;
                            var gz = (cz - minZ) * ChunkSize;

                            changes.Add(chunk.ScheduleGrid(0, 0, 0, gx, gy, gz, grid, propagatePadding, includePadding, writeUnsetVoxels));
                        }
                    }
                }

                //Wait and finalize jobs
                foreach (var change in changes)
                {
                    change.handle.Complete();
                }

                //Finalize
                foreach (var change in changes)
                {
                    change.finalize();
                }
            }
        }
        /// <summary>
        /// Applies the specified signed distance field function to the world.
        /// The SDF is applied in local space, i.e. 1 voxel = 1 unit on the signed distance field!
        /// </summary>
        /// <param name="pos">World position</param>
        /// <param name="rot">World rotation</param>
        /// <param name="sdf">Signed distance field function</param>
        /// <param name="material">Material to be added</param>
        /// <param name="replace">Whether only solid material should be replaced</param>
        /// <param name="edits">Consumes the voxel edit. Can be null if no voxel edits should be stored</param>
        public void ApplySdf <TSdf>(Vector3 pos, Quaternion rot, TSdf sdf, int material, bool replace, VoxelEditConsumer <TIndexer> edits)
            where TSdf : struct, ISdf
        {
            pos = TransformPointToLocalSpace(pos);
            rot = TransformQuatToLocalSpace(rot);

            Debug.Log("Apply sdf at: " + pos);

            var transformedSdf = new TransformSDF <TSdf>(Matrix4x4.TRS(pos, rot, Vector3.one), sdf);

            Vector3 minBound = transformedSdf.Min();
            Vector3 maxBound = transformedSdf.Max();

            int minX = Mathf.FloorToInt((float)minBound.x / ChunkSize);
            int minY = Mathf.FloorToInt((float)minBound.y / ChunkSize);
            int minZ = Mathf.FloorToInt((float)minBound.z / ChunkSize);

            int maxX = Mathf.FloorToInt((float)maxBound.x / ChunkSize);
            int maxY = Mathf.FloorToInt((float)maxBound.y / ChunkSize);
            int maxZ = Mathf.FloorToInt((float)maxBound.z / ChunkSize);

            var changes = new List <VoxelChunk <TIndexer> .Change>();

            var watch = System.Diagnostics.Stopwatch.StartNew();

            if (edits != null)
            {
                var snapshots = new List <VoxelChunk <TIndexer> .Snapshot>();

                //Include padding
                int minX2 = Mathf.FloorToInt((float)(minBound.x - 1) / ChunkSize);
                int minY2 = Mathf.FloorToInt((float)(minBound.y - 1) / ChunkSize);
                int minZ2 = Mathf.FloorToInt((float)(minBound.z - 1) / ChunkSize);

                int maxX2 = Mathf.FloorToInt((float)(maxBound.x + 1) / ChunkSize);
                int maxY2 = Mathf.FloorToInt((float)(maxBound.y + 1) / ChunkSize);
                int maxZ2 = Mathf.FloorToInt((float)(maxBound.z + 1) / ChunkSize);

                var snapshotChunks = new List <VoxelChunk <TIndexer> >();

                for (int cx = minX2; cx <= maxX2; cx++)
                {
                    for (int cy = minY2; cy <= maxY2; cy++)
                    {
                        for (int cz = minZ2; cz <= maxZ2; cz++)
                        {
                            ChunkPos chunkPos = ChunkPos.FromChunk(cx, cy, cz);

                            chunks.TryGetValue(chunkPos, out VoxelChunk <TIndexer> chunk);
                            if (chunk != null)
                            {
                                snapshots.Add(chunk.ScheduleSnapshot());
                            }
                            else
                            {
                                snapshotChunks.Add(new VoxelChunk <TIndexer>(this, chunkPos, ChunkSize, IndexerFactory));
                            }
                        }
                    }
                }

                //Finalize clone jobs
                foreach (VoxelChunk <TIndexer> .Snapshot snapshot in snapshots)
                {
                    snapshot.handle.Complete();
                    snapshotChunks.Add(snapshot.chunk);
                }

                //Produce edit
                edits(new VoxelEdit <TIndexer>(this, snapshotChunks));
            }

            //Schedule all jobs
            for (int cx = minX; cx <= maxX; cx++)
            {
                for (int cy = minY; cy <= maxY; cy++)
                {
                    for (int cz = minZ; cz <= maxZ; cz++)
                    {
                        ChunkPos chunkPos = ChunkPos.FromChunk(cx, cy, cz);

                        chunks.TryGetValue(chunkPos, out VoxelChunk <TIndexer> chunk);
                        if (chunk == null)
                        {
                            chunks[chunkPos] = chunk = new VoxelChunk <TIndexer>(this, chunkPos, ChunkSize, IndexerFactory);
                        }

                        changes.Add(chunk.ScheduleSdf(-cx * ChunkSize, -cy * ChunkSize, -cz * ChunkSize, transformedSdf, material, replace));
                    }
                }
            }

            //Wait and finalize jobs
            foreach (var change in changes)
            {
                change.handle.Complete();
            }

            //Finalize
            foreach (var change in changes)
            {
                change.finalize();
            }

            watch.Stop();

            string text = "Applied SDF to " + changes.Count + " voxel chunks in " + watch.ElapsedMilliseconds + "ms. Avg: " + (watch.ElapsedMilliseconds / (float)changes.Count) + "ms.";

            Debug.Log(text);
        }