Exemple #1
0
        /// <summary>
        /// Get a point on the flattening plane and flatten the terrain around it
        /// </summary>
        private void FlattenTerrain()
        {
            PlaneLineIntersectionResult result = IntersectionUtilities.PlaneLineIntersection(_flatteningOrigin, _flatteningNormal, playerCamera.position, playerCamera.forward, out float3 intersectionPoint);

            if (result != PlaneLineIntersectionResult.OneHit)
            {
                return;
            }

            float flattenOffset = 0;

            // This is a bit hacky. One fix could be that the VoxelMesher class has a flattenOffset property, but I'm not sure if that's a good idea either.
            if (voxelWorld.VoxelMesher is MarchingCubesMesher marchingCubesMesher)
            {
                flattenOffset = marchingCubesMesher.Isolevel;
            }

            int       intRange        = (int)math.ceil(deformRange);
            int       size            = 2 * intRange + 1;
            int3      queryPosition   = (int3)(intersectionPoint - new int3(intRange));
            BoundsInt worldSpaceQuery = new BoundsInt(queryPosition.ToVectorInt(), new Vector3Int(size, size, size));

            voxelWorld.VoxelDataStore.SetVoxelDataCustom(worldSpaceQuery, (voxelDataWorldPosition, voxelData) =>
            {
                float distance = math.distance(voxelDataWorldPosition, intersectionPoint);
                if (distance > deformRange)
                {
                    return(voxelData);
                }

                float voxelDataChange = (math.dot(_flatteningNormal, voxelDataWorldPosition) - math.dot(_flatteningNormal, _flatteningOrigin)) / deformRange;

                return((byte)math.clamp(((voxelDataChange * 0.5f + voxelData / 255f - flattenOffset) * 0.8f + flattenOffset) * 255, 0, 255));
            });
        }
Exemple #2
0
        /// <summary>
        /// Loops through each voxel data point that is contained in <paramref name="dataChunk"/> AND in <paramref name="worldSpaceQuery"/>, and performs <paramref name="function"/> on it
        /// </summary>
        /// <param name="worldSpaceQuery">The query that determines whether or not a voxel data point is contained.</param>
        /// <param name="chunkCoordinate">The coordinate of <paramref name="dataChunk"/></param>
        /// <param name="dataChunk">The voxel datas of the chunk</param>
        /// <param name="function">The function that will be performed on each voxel data point. The arguments are as follows: 1) The world space position of the voxel data point, 2) The chunk space position of the voxel data point, 3) The index of the voxel data point inside of <paramref name="dataChunk"/>, 4) The value of the voxel data</param>
        public void ForEachVoxelDataInQueryInChunk(BoundsInt worldSpaceQuery, int3 chunkCoordinate, VoxelDataVolume <T> dataChunk, Action <int3, int3, int, T> function)
        {
            int3 chunkBoundsSize       = VoxelWorld.WorldSettings.ChunkSize;
            int3 chunkWorldSpaceOrigin = chunkCoordinate * VoxelWorld.WorldSettings.ChunkSize;

            BoundsInt chunkWorldSpaceBounds = new BoundsInt(chunkWorldSpaceOrigin.ToVectorInt(), chunkBoundsSize.ToVectorInt());

            BoundsInt 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;
                        int  voxelDataIndex         = IndexUtilities.XyzToIndex(voxelDataLocalPosition, chunkBoundsSize.x + 1, chunkBoundsSize.y + 1);
                        if (dataChunk.TryGetVoxelData(voxelDataIndex, out T voxelData))
                        {
                            function(voxelDataWorldPosition, voxelDataLocalPosition, voxelDataIndex, voxelData);
                        }
                    }
                }
            }
        }
Exemple #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;
                        }
                    }
                }
            }
        }
        public void Test4()
        {
            Bounds a = new Bounds(new Vector3(-10, -10, -10), new Vector3(4, 4, 4));
            Bounds b = new Bounds(new Vector3(-1, -1, -1), new Vector3(16, 16, 16));

            Bounds intersection = IntersectionUtilities.GetIntersectionVolume(a, b);

            Assert.AreEqual(new Bounds(new Vector3(-8.5f, -8.5f, -8.5f), new Vector3(1, 1, 1)), intersection);
        }
        public void Test3_Swapped()
        {
            Bounds a = new Bounds(new Vector3(-10, -10, -10), new Vector3(4, 4, 4));
            Bounds b = new Bounds(new Vector3(0, 0, 0), new Vector3(16, 16, 16));

            Bounds intersection = IntersectionUtilities.GetIntersectionVolume(b, a);

            Assert.AreEqual(new Bounds(new Vector3(-8, -8, -8), new Vector3(0, 0, 0)), intersection);
        }
        public void Bounds_Are_Same_Should_Return_Same()
        {
            Bounds a = new Bounds(new Vector3(41, 24, 85), new Vector3(48, 26, 23));
            Bounds b = a;

            Bounds intersection = IntersectionUtilities.GetIntersectionVolume(a, b);

            Assert.AreEqual(a, intersection);
        }
        public void Test2_Swapped()
        {
            Bounds a = new Bounds(new Vector3(0, 0, 0), new Vector3(2, 3, 3));
            Bounds b = new Bounds(new Vector3(2, 0, 0), new Vector3(2, 3, 3));

            Bounds intersection = IntersectionUtilities.GetIntersectionVolume(b, a);

            Assert.AreEqual(new Bounds(new Vector3(1, 0, 0), new Vector3(0, 3, 3)), intersection);
        }
        public void Test1()
        {
            Bounds a = new Bounds(new Vector3(0, 0, 0), new Vector3(4, 4, 4));
            Bounds b = new Bounds(new Vector3(2, 2, 2), new Vector3(4, 4, 4));

            Bounds intersection = IntersectionUtilities.GetIntersectionVolume(a, b);

            Assert.AreEqual(new Bounds(new Vector3(1, 1, 1), new Vector3(2, 2, 2)), intersection);
        }
 public override void UpdateObservation()
 {
     foreach (var transform1 in this._transforms)
     {
         if (IntersectionUtilities.ConeSphereIntersection(this._light, transform1))
         {
             //Debug.Log("Intersect");
         }
     }
 }
Exemple #10
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);
        }
Exemple #11
0
        public void Line_At_1_0_0_Plane_At_0_0_0_Custom_Angle_Should_Be_1_Negative2_0()
        {
            float3 planeOrigin   = new float3(0, 0, 0);
            float3 planeNormal   = math.normalize(new float3(1, 0.5f, 0));
            float3 lineOrigin    = new float3(1, 0, 0);
            float3 lineDirection = new float3(0, -1, 0);

            PlaneLineIntersectionResult result = IntersectionUtilities.PlaneLineIntersection(planeOrigin, planeNormal, lineOrigin, lineDirection, out float3 intersectionPoint);

            Assert.AreEqual(new float3(1, -2, 0), intersectionPoint);
        }
Exemple #12
0
        public void Line_Above_Directly_Down_Result_Should_Be_OneHit()
        {
            float3 planeOrigin   = new float3(0, 0, 0);
            float3 planeNormal   = math.normalize(new float3(0, 1, 0));
            float3 lineOrigin    = new float3(0, 10, 0);
            float3 lineDirection = new float3(0, -1, 0);

            PlaneLineIntersectionResult result = IntersectionUtilities.PlaneLineIntersection(planeOrigin, planeNormal, lineOrigin, lineDirection, out float3 intersectionPoint);

            Assert.AreEqual(PlaneLineIntersectionResult.OneHit, result);
        }
Exemple #13
0
        public void Line_Parallel_To_Plane_Inside_Result_Should_Be_ParallelInsidePlane()
        {
            float3 planeOrigin   = new float3(0, 4, 0);
            float3 planeNormal   = math.normalize(new float3(0, 1, 0));
            float3 lineOrigin    = new float3(0, 4, 0);
            float3 lineDirection = new float3(1, 0, 0);

            PlaneLineIntersectionResult result = IntersectionUtilities.PlaneLineIntersection(planeOrigin, planeNormal, lineOrigin, lineDirection, out float3 intersectionPoint);

            Assert.AreEqual(PlaneLineIntersectionResult.ParallelInsidePlane, result);
        }
Exemple #14
0
        public void Line_At_10_4_5_Directly_Down_Should_Hit_10_0_5()
        {
            float3 planeOrigin   = new float3(0, 0, 0);
            float3 planeNormal   = math.normalize(new float3(0, 1, 0));
            float3 lineOrigin    = new float3(10, 4, 5);
            float3 lineDirection = new float3(0, -1, 0);

            PlaneLineIntersectionResult result = IntersectionUtilities.PlaneLineIntersection(planeOrigin, planeNormal, lineOrigin, lineDirection, out float3 intersectionPoint);

            Assert.AreEqual(new float3(10, 0, 5), intersectionPoint);
        }
        /// <summary>
        /// Gets the list of new coordinates that should be generated when the player moved from <paramref name="oldChunks"/> to <paramref name="newChunks"/>; Every coordinate in <paramref name="newChunks"/> that is not in <paramref name="oldChunks"/>
        /// </summary>
        /// <param name="oldChunks">The old rendering bounds of the chunks the player saw</param>
        /// <param name="newChunks">The new rendering bounds of the chunks the player sees</param>
        /// <returns>Returns the new coordinates that need chunks</returns>
        public static int3[] GetCoordinatesThatNeedChunks(BoundsInt oldChunks, BoundsInt newChunks)
        {
            // Cache the min/max values because accessing them repeatedly in a loop is surprisingly costly
            int newChunksMinX = newChunks.xMin;
            int newChunksMaxX = newChunks.xMax;
            int newChunksMinY = newChunks.yMin;
            int newChunksMaxY = newChunks.yMax;
            int newChunksMinZ = newChunks.zMin;
            int newChunksMaxZ = newChunks.zMax;

            int oldChunksMinX = oldChunks.xMin;
            int oldChunksMaxX = oldChunks.xMax;
            int oldChunksMinY = oldChunks.yMin;
            int oldChunksMaxY = oldChunks.yMax;
            int oldChunksMinZ = oldChunks.zMin;
            int oldChunksMaxZ = oldChunks.zMax;

            int count = newChunks.CalculateVolume();

            BoundsInt intersection = IntersectionUtilities.GetIntersectionVolume(oldChunks, newChunks);

            if (math.all(intersection.size.ToInt3() > 0))
            {
                count -= intersection.CalculateVolume();
            }

            int3[] coordinates = new int3[count];

            int i = 0;

            for (int x = newChunksMinX; x < newChunksMaxX; x++)
            {
                for (int y = newChunksMinY; y < newChunksMaxY; y++)
                {
                    for (int z = newChunksMinZ; z < newChunksMaxZ; z++)
                    {
                        if (oldChunksMinX <= x && x < oldChunksMaxX &&
                            oldChunksMinY <= y && y < oldChunksMaxY &&
                            oldChunksMinZ <= z && z < oldChunksMaxZ)
                        {
                            continue;
                        }

                        coordinates[i] = new int3(x, y, z);
                        i++;
                    }
                }
            }

            return(coordinates);
        }
        private static void TestIntersection(Vector3Int aPosition, Vector3Int aSize, Vector3Int bPosition, Vector3Int bSize, Vector3Int expectedPosition, Vector3Int expectedSize)
        {
            BoundsInt a        = new BoundsInt(aPosition, aSize);
            BoundsInt b        = new BoundsInt(bPosition, bSize);
            BoundsInt expected = new BoundsInt(expectedPosition, expectedSize);

            string message = $"Test failed with objects {a} and {b}. Expected {expected}";

            BoundsInt intersection = IntersectionUtilities.GetIntersectionVolume(a, b);

            Assert.AreEqual(expected, intersection, "Regular: " + message);

            BoundsInt intersectionSwapped = IntersectionUtilities.GetIntersectionVolume(b, a);

            Assert.AreEqual(expected, intersectionSwapped, "Swapped: " + message);
        }
Exemple #17
0
        /// <summary>
        /// Get a point on the flattening plane and flatten the terrain around it
        /// </summary>
        private void FlattenTerrain()
        {
            PlaneLineIntersectionResult result = IntersectionUtilities.PlaneLineIntersection(_flatteningOrigin, _flatteningNormal, playerCamera.position, playerCamera.forward, out float3 intersectionPoint);

            if (result != PlaneLineIntersectionResult.OneHit)
            {
                return;
            }

            int intRange = (int)math.ceil(deformRange);

            for (int x = -intRange; x <= intRange; x++)
            {
                for (int y = -intRange; y <= intRange; y++)
                {
                    for (int z = -intRange; z <= intRange; z++)
                    {
                        int3   localPosition = new int3(x, y, z);
                        float3 offsetPoint   = intersectionPoint + localPosition;

                        float distance = math.distance(offsetPoint, intersectionPoint);
                        if (distance > deformRange)
                        {
                            continue;
                        }

                        int3 voxelDataWorldPosition = (int3)offsetPoint;
                        if (voxelDataStore.TryGetVoxelData(voxelDataWorldPosition, out float oldVoxelData))
                        {
                            float voxelDataChange = (math.dot(_flatteningNormal, voxelDataWorldPosition) - math.dot(_flatteningNormal, _flatteningOrigin)) / deformRange;
                            voxelDataStore.SetVoxelData((voxelDataChange * 0.5f + oldVoxelData) * 0.8f, voxelDataWorldPosition);
                        }
                    }
                }
            }
        }
 private static void TestPlaneLineIntersectionPoint(float3 planeOrigin, float3 planeNormal, float3 lineOrigin, float3 lineDirection, float3 expected)
 {
     _ = IntersectionUtilities.PlaneLineIntersection(planeOrigin, planeNormal, lineOrigin, lineDirection, out float3 intersectionPoint);
     Assert.AreEqual(expected, intersectionPoint);
 }
        private static void TestPlaneLineIntersectionResult(float3 planeOrigin, float3 planeNormal, float3 lineOrigin, float3 lineDirection, PlaneLineIntersectionResult expected)
        {
            PlaneLineIntersectionResult result = IntersectionUtilities.PlaneLineIntersection(planeOrigin, math.normalize(planeNormal), lineOrigin, lineDirection, out _);

            Assert.AreEqual(expected, result);
        }