public bool RayCast(Vector3 pos, Vector3 dir, float dst, out RayCastResult result)
        {
            pos = TransformPointToLocalSpace(pos);
            dir = TransformDirToLocalSpace(dir);

            const float step = 0.1f;

            int prevX = int.MaxValue;
            int prevY = int.MaxValue;
            int prevZ = int.MaxValue;

            Vector3 stepOffset = dir.normalized * step;

            for (int i = 0; i < dst / step; i++)
            {
                int x = (int)Mathf.Floor(pos.x);
                int y = (int)Mathf.Floor(pos.y);
                int z = (int)Mathf.Floor(pos.z);

                if (x != prevX || y != prevY || z != prevZ)
                {
                    for (int zo = 0; zo < 2; zo++)
                    {
                        for (int yo = 0; yo < 2; yo++)
                        {
                            for (int xo = 0; xo < 2; xo++)
                            {
                                int bx = x + xo;
                                int by = y + yo;
                                int bz = z + zo;

                                var chunk = GetChunk(ChunkPos.FromVoxel(bx, by, bz, ChunkSize));

                                if (chunk != null)
                                {
                                    int material = chunk.GetMaterial(((bx % ChunkSize) + ChunkSize) % ChunkSize, ((by % ChunkSize) + ChunkSize) % ChunkSize, ((bz % ChunkSize) + ChunkSize) % ChunkSize);
                                    if (material != 0)
                                    {
                                        result = new RayCastResult(new Vector3(x, y, z), new Vector3(prevX, prevY, prevZ), chunk);
                                        return(true);
                                    }
                                }
                            }
                        }
                    }

                    prevX = x;
                    prevY = y;
                    prevZ = z;
                }

                pos += stepOffset;
            }

            result = new RayCastResult(Vector3.zero, Vector3.zero, null);
            return(false);
        }
Beispiel #2
0
        public VoxelChunk(VoxelWorld <TIndexer> world, ChunkPos pos, int chunkSize, IndexerFactory <TIndexer> indexerFactory)
        {
            this.world          = world;
            this.chunkSize      = chunkSize;
            this.chunkSizeSq    = chunkSize * chunkSize;
            this.Pos            = pos;
            this.indexerFactory = indexerFactory;

            voxels = new NativeArray3D <Voxel, TIndexer>(indexerFactory(chunkSize + 1, chunkSize + 1, chunkSize + 1), chunkSize + 1, chunkSize + 1, chunkSize + 1, Allocator.Persistent);
            //voxels = new Voxel[chunkSize * chunkSize * chunkSize];
            //voxels = new NativeArray<Voxel>(chunkSize * chunkSize * chunkSize, Allocator.Persistent); //TODO Dispose
        }
Beispiel #3
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();
                }
            }
        }
 public VoxelChunk <TIndexer> GetChunk(ChunkPos pos)
 {
     chunks.TryGetValue(pos, out VoxelChunk <TIndexer> chunk);
     return(chunk);
 }
        /// <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);
        }