public override void GenerateDataForChunkUnchecked(int3 chunkCoordinate, VoxelDataVolume <byte> existingData)
        {
            int3 chunkWorldOrigin = chunkCoordinate * VoxelWorld.WorldSettings.ChunkSize;
            JobHandleWithData <IVoxelDataGenerationJob> jobHandleWithData = VoxelWorld.VoxelDataGenerator.GenerateVoxelData(chunkWorldOrigin, existingData);

            _generationJobHandles.Add(chunkCoordinate, jobHandleWithData);
        }
        /// <summary>
        /// Starts generating the voxel data for a specified volume
        /// </summary>
        /// <param name="bounds">The world-space volume to generate the voxel data for</param>
        /// <param name="allocator">The allocator for the new voxel data array</param>
        /// <returns>The job handle and the voxel data generation job</returns>
        public JobHandleWithData <IVoxelDataGenerationJob> GenerateVoxelData(BoundsInt bounds, Allocator allocator)
        {
            VoxelDataVolume <byte> voxelDataArray = new VoxelDataVolume <byte>(bounds.size, allocator);
            int3 worldSpaceOrigin = bounds.min.ToInt3();

            return(GenerateVoxelData(worldSpaceOrigin, voxelDataArray));
        }
Example #3
0
        /// <summary>
        /// Sets the voxel data for a volume in the world
        /// </summary>
        /// <param name="voxelDataVolume">The new voxel data volume</param>
        /// <param name="originPosition">The world position of the origin where the voxel data should be set</param>
        public void SetVoxelDataCustom(VoxelDataVolume voxelDataVolume, int3 originPosition)
        {
            Bounds worldSpaceQuery = new Bounds();

            worldSpaceQuery.SetMinMax(originPosition.ToVectorInt(), (originPosition + voxelDataVolume.Size - new int3(1, 1, 1)).ToVectorInt());

            int chunkSize = VoxelWorld.WorldSettings.ChunkSize;

            int3 minChunkCoordinate = VectorUtilities.WorldPositionToCoordinate(worldSpaceQuery.min - Vector3Int.one, chunkSize);
            int3 maxChunkCoordinate = VectorUtilities.WorldPositionToCoordinate(worldSpaceQuery.max + Vector3Int.one, chunkSize);

            for (int chunkCoordinateX = minChunkCoordinate.x; chunkCoordinateX <= maxChunkCoordinate.x; chunkCoordinateX++)
            {
                for (int chunkCoordinateY = minChunkCoordinate.y; chunkCoordinateY <= maxChunkCoordinate.y; chunkCoordinateY++)
                {
                    for (int chunkCoordinateZ = minChunkCoordinate.z; chunkCoordinateZ <= maxChunkCoordinate.z; chunkCoordinateZ++)
                    {
                        int3 chunkCoordinate = new int3(chunkCoordinateX, chunkCoordinateY, chunkCoordinateZ);
                        if (!TryGetVoxelDataChunk(chunkCoordinate, out VoxelDataVolume voxelDataChunk))
                        {
                            continue;
                        }

                        Vector3 chunkBoundsSize       = new Vector3(voxelDataChunk.Width - 1, voxelDataChunk.Height - 1, voxelDataChunk.Depth - 1);
                        int3    chunkWorldSpaceOrigin = chunkCoordinate * chunkSize;

                        Bounds chunkWorldSpaceBounds = new Bounds();
                        chunkWorldSpaceBounds.SetMinMax(chunkWorldSpaceOrigin.ToVectorInt(), chunkWorldSpaceOrigin.ToVectorInt() + chunkBoundsSize);

                        Bounds intersectionVolume    = IntersectionUtilities.GetIntersectionVolume(worldSpaceQuery, chunkWorldSpaceBounds);
                        int3   intersectionVolumeMin = intersectionVolume.min.ToInt3();
                        int3   intersectionVolumeMax = intersectionVolume.max.ToInt3();

                        for (int voxelDataWorldPositionX = intersectionVolumeMin.x; voxelDataWorldPositionX <= intersectionVolumeMax.x; voxelDataWorldPositionX++)
                        {
                            for (int voxelDataWorldPositionY = intersectionVolumeMin.y; voxelDataWorldPositionY <= intersectionVolumeMax.y; voxelDataWorldPositionY++)
                            {
                                for (int voxelDataWorldPositionZ = intersectionVolumeMin.z; voxelDataWorldPositionZ <= intersectionVolumeMax.z; voxelDataWorldPositionZ++)
                                {
                                    int3 voxelDataWorldPosition = new int3(voxelDataWorldPositionX, voxelDataWorldPositionY, voxelDataWorldPositionZ);

                                    if (voxelDataChunk.TryGetVoxelData(voxelDataWorldPosition - worldSpaceQuery.min.ToInt3(), out float voxelData))
                                    {
                                        voxelDataChunk.SetVoxelData(voxelData, voxelDataWorldPosition - chunkWorldSpaceOrigin);
                                    }
                                }
                            }
                        }

                        if (VoxelWorld.ChunkStore.TryGetChunkAtCoordinate(chunkCoordinate, out Chunk chunk))
                        {
                            chunk.HasChanges = true;
                        }
                    }
                }
            }
        }
Example #4
0
        /// <summary>
        /// Gets the voxel data of a custom volume in the world
        /// </summary>
        /// <param name="bounds">The world-space volume to get the voxel data for</param>
        /// <param name="allocator">How the new voxel data volume should be allocated</param>
        /// <returns>The voxel data volume inside the bounds</returns>
        public VoxelDataVolume GetVoxelDataCustom(Bounds bounds, Allocator allocator)
        {
            VoxelDataVolume voxelDataVolume = new VoxelDataVolume(bounds.size.ToInt3(), allocator);

            Bounds worldSpaceQuery = bounds;

            int chunkSize = VoxelWorld.WorldSettings.ChunkSize;

            int3 minChunkCoordinate = VectorUtilities.WorldPositionToCoordinate(worldSpaceQuery.min - Vector3Int.one, chunkSize);
            int3 maxChunkCoordinate = VectorUtilities.WorldPositionToCoordinate(worldSpaceQuery.max + Vector3Int.one, chunkSize);

            for (int chunkCoordinateX = minChunkCoordinate.x; chunkCoordinateX <= maxChunkCoordinate.x; chunkCoordinateX++)
            {
                for (int chunkCoordinateY = minChunkCoordinate.y; chunkCoordinateY <= maxChunkCoordinate.y; chunkCoordinateY++)
                {
                    for (int chunkCoordinateZ = minChunkCoordinate.z; chunkCoordinateZ <= maxChunkCoordinate.z; chunkCoordinateZ++)
                    {
                        int3 chunkCoordinate = new int3(chunkCoordinateX, chunkCoordinateY, chunkCoordinateZ);
                        if (!TryGetVoxelDataChunk(chunkCoordinate, out VoxelDataVolume voxelDataChunk))
                        {
                            continue;
                        }

                        Vector3 chunkBoundsSize       = new Vector3(voxelDataChunk.Width - 1, voxelDataChunk.Height - 1, voxelDataChunk.Depth - 1);
                        int3    chunkWorldSpaceOrigin = chunkCoordinate * chunkSize;

                        Bounds chunkWorldSpaceBounds = new Bounds();
                        chunkWorldSpaceBounds.SetMinMax(chunkWorldSpaceOrigin.ToVectorInt(), chunkWorldSpaceOrigin.ToVectorInt() + chunkBoundsSize);

                        Bounds intersectionVolume    = IntersectionUtilities.GetIntersectionVolume(worldSpaceQuery, chunkWorldSpaceBounds);
                        int3   intersectionVolumeMin = intersectionVolume.min.ToInt3();
                        int3   intersectionVolumeMax = intersectionVolume.max.ToInt3();

                        for (int voxelDataWorldPositionX = intersectionVolumeMin.x; voxelDataWorldPositionX < intersectionVolumeMax.x; voxelDataWorldPositionX++)
                        {
                            for (int voxelDataWorldPositionY = intersectionVolumeMin.y; voxelDataWorldPositionY < intersectionVolumeMax.y; voxelDataWorldPositionY++)
                            {
                                for (int voxelDataWorldPositionZ = intersectionVolumeMin.z; voxelDataWorldPositionZ < intersectionVolumeMax.z; voxelDataWorldPositionZ++)
                                {
                                    int3 voxelDataWorldPosition = new int3(voxelDataWorldPositionX, voxelDataWorldPositionY, voxelDataWorldPositionZ);
                                    int3 voxelDataLocalPosition = voxelDataWorldPosition - chunkWorldSpaceOrigin;

                                    if (voxelDataChunk.TryGetVoxelData(voxelDataLocalPosition, out float voxelData))
                                    {
                                        voxelDataVolume.SetVoxelData(voxelData, voxelDataWorldPosition - bounds.min.ToInt3());
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(voxelDataVolume);
        }
 /// <summary>
 /// Copies the voxel data from the source volume if the volumes are the same size
 /// </summary>
 /// <param name="sourceVolume">The source volume, which should be the same size as this volume</param>
 public void CopyFrom(VoxelDataVolume <T> sourceVolume)
 {
     if (Width == sourceVolume.Width && Height == sourceVolume.Height && Depth == sourceVolume.Depth)
     {
         _voxelData.CopyFrom(sourceVolume._voxelData);
     }
     else
     {
         throw new ArgumentException($"The chunks are not the same size! Width: {Width}/{sourceVolume.Width}, Height: {Height}/{sourceVolume.Height}, Depth: {Depth}/{sourceVolume.Depth}");
     }
 }
Example #6
0
        /// <summary>
        /// Sets a chunk's voxel data
        /// </summary>
        /// <param name="chunkVoxelData">The new voxel data</param>
        /// <param name="chunkCoordinate">The coordinate of the chunk whose voxel data should be set</param>
        public void SetVoxelDataChunk(VoxelDataVolume chunkVoxelData, int3 chunkCoordinate)
        {
            if (_chunks.TryGetValue(chunkCoordinate, out VoxelDataVolume voxelDataVolume))
            {
                voxelDataVolume.CopyFrom(chunkVoxelData);
            }
            else
            {
                _chunks.Add(chunkCoordinate, chunkVoxelData);
            }

            if (VoxelWorld.ChunkStore.TryGetChunkAtCoordinate(chunkCoordinate, out Chunk chunk))
            {
                chunk.HasChanges = true;
            }
        }
        public override void SetDataChunk(int3 chunkCoordinate, VoxelDataVolume <byte> newData)
        {
            if (TryGetDataChunkWithoutApplying(chunkCoordinate, out VoxelDataVolume <byte> oldData))
            {
                oldData.CopyFrom(newData);
                newData.Dispose();
            }
            else
            {
                AddChunkUnchecked(chunkCoordinate, newData);
            }

            if (VoxelWorld.ChunkStore.TryGetDataChunk(chunkCoordinate, out ChunkProperties chunkProperties))
            {
                chunkProperties.HasChanges = true;
            }
        }
Example #8
0
        /// <summary>
        /// Starts generating the voxel data for a specified volume
        /// </summary>
        /// <param name="bounds">The volume to generate the voxel data for</param>
        /// <param name="allocator">The allocator for the new <see cref="VoxelDataVolume"/></param>
        /// <returns>The job handle and the voxel data generation job</returns>
        public override JobHandleWithData <IVoxelDataGenerationJob> GenerateVoxelData(Bounds bounds, Allocator allocator)
        {
            VoxelDataVolume voxelData = new VoxelDataVolume(bounds.size.ToInt3(), allocator);
            ProceduralTerrainVoxelDataCalculationJob job = new ProceduralTerrainVoxelDataCalculationJob
            {
                WorldPositionOffset       = bounds.min.ToInt3(),
                OutputVoxelData           = voxelData,
                ProceduralTerrainSettings = proceduralTerrainSettings
            };

            JobHandle jobHandle = job.Schedule(voxelData.Length, 256);

            JobHandleWithData <IVoxelDataGenerationJob> jobHandleWithData = new JobHandleWithData <IVoxelDataGenerationJob>();

            jobHandleWithData.JobHandle = jobHandle;
            jobHandleWithData.JobData   = job;

            return(jobHandleWithData);
        }
Example #9
0
        /// <summary>
        /// Starts generating the voxel data for a specified volume
        /// </summary>
        /// <param name="bounds">The volume to generate the voxel data for</param>
        /// <param name="allocator">The allocator for the new <see cref="VoxelDataVolume"/></param>
        /// <returns>The job handle and the voxel data generation job</returns>
        public override JobHandleWithData <IVoxelDataGenerationJob> GenerateVoxelData(Bounds bounds, Allocator allocator)
        {
            VoxelDataVolume voxelData = new VoxelDataVolume(bounds.size.ToInt3(), allocator);

            HeightmapTerrainVoxelDataCalculationJob job = new HeightmapTerrainVoxelDataCalculationJob
            {
                WorldPositionOffset = bounds.min.ToInt3(),
                OutputVoxelData     = voxelData,
                HeightmapData       = heightmapWorldGenerator.HeightmapTerrainSettings.HeightmapData,
                HeightmapWidth      = heightmapWorldGenerator.HeightmapTerrainSettings.Width,
                HeightmapHeight     = heightmapWorldGenerator.HeightmapTerrainSettings.Height,
                Amplitude           = heightmapWorldGenerator.HeightmapTerrainSettings.Amplitude,
                HeightOffset        = heightmapWorldGenerator.HeightmapTerrainSettings.HeightOffset
            };

            JobHandle jobHandle = job.Schedule(voxelData.Length, 256);

            JobHandleWithData <IVoxelDataGenerationJob> jobHandleWithData = new JobHandleWithData <IVoxelDataGenerationJob>();

            jobHandleWithData.JobHandle = jobHandle;
            jobHandleWithData.JobData   = job;

            return(jobHandleWithData);
        }
Example #10
0
 /// <summary>
 /// Tries to get the <see cref="VoxelDataVolume"/> for one chunk with a persistent allocator. If a chunk doesn't exist there, false will be returned and <paramref name="chunk"/> will be set to null. If a chunk exists there, true will be returned and <paramref name="chunk"/> will be set to the chunk.
 /// </summary>
 /// <param name="chunkCoordinate">The coordinate of the chunk whose voxel data should be gotten</param>
 /// <param name="chunk">The voxel data of a chunk at the coordinate</param>
 /// <returns>Does a chunk exists at that coordinate</returns>
 public bool TryGetVoxelDataChunk(int3 chunkCoordinate, out VoxelDataVolume chunk)
 {
     ApplyChunkChanges(chunkCoordinate);
     return(_chunks.TryGetValue(chunkCoordinate, out chunk));
 }
Example #11
0
        /// <summary>
        /// Generates the colors for a chunk at <paramref name="chunkCoordinate"/>, where the output array is <paramref name="outputColors"/> to save memory by not needing to allocate a new array. This does not check if a color array already exists at <paramref name="chunkCoordinate"/>
        /// </summary>
        /// <param name="chunkCoordinate">The coordinate of the chunk which to generate the colors for</param>
        /// <param name="outputColors">The array that should be filled with the new colors</param>
        public override unsafe void GenerateDataForChunkUnchecked(int3 chunkCoordinate, VoxelDataVolume <Color32> outputColors)
        {
            // Fill the array with the default terrain color
            Color32 *defaultColorArray = stackalloc Color32[1]
            {
                defaultTerrainColor
            };

            unsafe
            {
                UnsafeUtility.MemCpyReplicate(outputColors.GetUnsafePtr(), defaultColorArray, sizeof(Color32), outputColors.Length);
            }

            SetDataChunkUnchecked(chunkCoordinate, outputColors, false);
        }
 /// <summary>
 /// Tries to get the voxel data array for one chunk with a persistent allocator. If a chunk doesn't exist there, false will be returned and <paramref name="chunk"/> will be set to null. If a chunk exists there, true will be returned and <paramref name="chunk"/> will be set to the chunk. If the data for that chunk is currently being calculated, the job will NOT be completed.
 /// <param name="chunkCoordinate">The coordinate of the chunk whose voxel data should be gotten</param>
 /// <param name="chunk">The voxel data of a chunk at the coordinate</param>
 /// <returns>Does a chunk exists at that coordinate</returns>
 private bool TryGetDataChunkWithoutApplying(int3 chunkCoordinate, out VoxelDataVolume <byte> chunk)
 {
     return(_chunks.TryGetValue(chunkCoordinate, out chunk));
 }
 /// <summary>
 /// Tries to get the voxel data array for one chunk with a persistent allocator. If a chunk doesn't exist there, false will be returned and <paramref name="chunk"/> will be set to null. If a chunk exists there, true will be returned and <paramref name="chunk"/> will be set to the chunk. If the data for that chunk is currently being calculated, the job will complete and the new data will be set to <paramref name="chunk"/>
 /// </summary>
 /// <param name="chunkCoordinate">The coordinate of the chunk whose voxel data should be gotten</param>
 /// <param name="chunk">The voxel data of a chunk at the coordinate</param>
 /// <returns>Does a chunk exists at that coordinate</returns>
 public override bool TryGetDataChunk(int3 chunkCoordinate, out VoxelDataVolume <byte> chunk)
 {
     ApplyChunkChanges(chunkCoordinate);
     return(TryGetDataChunkWithoutApplying(chunkCoordinate, out chunk));
 }
Example #14
0
        /// <inheritdoc/>
        public override JobHandleWithData <IVoxelDataGenerationJob> GenerateVoxelData(int3 worldSpaceOrigin, VoxelDataVolume <byte> outputVoxelDataArray)
        {
            HeightmapTerrainVoxelDataCalculationJob job = new HeightmapTerrainVoxelDataCalculationJob
            {
                WorldPositionOffset = worldSpaceOrigin,
                OutputVoxelData     = outputVoxelDataArray,
                HeightmapData       = heightmapWorldGenerator.HeightmapTerrainSettings.HeightmapData,
                HeightmapWidth      = heightmapWorldGenerator.HeightmapTerrainSettings.Width,
                HeightmapHeight     = heightmapWorldGenerator.HeightmapTerrainSettings.Height,
                Amplitude           = heightmapWorldGenerator.HeightmapTerrainSettings.Amplitude,
                HeightOffset        = heightmapWorldGenerator.HeightmapTerrainSettings.HeightOffset
            };

            JobHandle jobHandle = job.Schedule();

            JobHandleWithData <IVoxelDataGenerationJob> jobHandleWithData = new JobHandleWithData <IVoxelDataGenerationJob>
            {
                JobHandle = jobHandle,
                JobData   = job
            };

            return(jobHandleWithData);
        }
        /// <inheritdoc/>
        public override JobHandleWithData <IVoxelDataGenerationJob> GenerateVoxelData(int3 worldSpaceOrigin, VoxelDataVolume <byte> outputVoxelDataArray)
        {
            ProceduralTerrainVoxelDataCalculationJob job = new ProceduralTerrainVoxelDataCalculationJob
            {
                WorldPositionOffset       = worldSpaceOrigin,
                OutputVoxelData           = outputVoxelDataArray,
                ProceduralTerrainSettings = proceduralTerrainSettings
            };

            JobHandle jobHandle = job.Schedule();

            JobHandleWithData <IVoxelDataGenerationJob> jobHandleWithData = new JobHandleWithData <IVoxelDataGenerationJob>
            {
                JobHandle = jobHandle,
                JobData   = job
            };

            return(jobHandleWithData);
        }
 /// <summary>
 /// Starts generating the voxel data for the given volume, where the origin of the volume is at <paramref name="worldSpaceOrigin"/>
 /// </summary>
 /// <param name="worldSpaceOrigin">The world space origin of <paramref name="outputVoxelDataArray"/></param>
 /// <param name="outputVoxelDataArray">The volume where the new voxel data should be generated to</param>
 /// <returns>The job handle and the voxel data generation job</returns>
 public abstract JobHandleWithData <IVoxelDataGenerationJob> GenerateVoxelData(int3 worldSpaceOrigin, VoxelDataVolume <byte> outputVoxelDataArray);