public void GetTerrainHeightForPoint_AndLeftWeightGreaterThanZero_ReturnsLeftWeightTimesLeftHeight()
        {
            var point = new Vector2(1f, 2f);

            var left = BuildCell();

            var orientationData = new PointOrientationData()
            {
                IsOnGrid      = true,
                Left          = left,
                LeftWeight    = 12f,
                ElevationDuck = 5.5f
            };

            var flatlandsNoise = new AsyncTextureUnsafe <Color32>();
            var hillsNoise     = new AsyncTextureUnsafe <Color32>();

            MockCellHeightmapLogic.Setup(
                logic => logic.GetHeightForPointForCell(point, left, 5.5f, flatlandsNoise, hillsNoise)
                ).Returns(8f);

            var heightLogic = Container.Resolve <TerrainHeightLogic>();

            Assert.AreEqual(96, heightLogic.GetHeightForPoint(point, orientationData, flatlandsNoise, hillsNoise));
        }
 public float GetHeightForPointForCell(
     Vector2 xzPoint, IHexCell cell, float elevationDuck,
     AsyncTextureUnsafe <Color32> flatlandNoise, AsyncTextureUnsafe <Color32> hillsNoise
     )
 {
     if (cell.Terrain.IsWater())
     {
         return(RenderConfig.SeaFloorElevation);
     }
     if (cell.Shape == CellShape.Flatlands)
     {
         return(FlatlandsHeightmapLogic.GetHeightForPoint(xzPoint, flatlandNoise));
     }
     else if (cell.Shape == CellShape.Hills)
     {
         return(HillsHeightmapLogic.GetHeightForPoint(xzPoint, elevationDuck, flatlandNoise, hillsNoise));
     }
     else if (cell.Shape == CellShape.Mountains)
     {
         return(MountainHeightmapLogic.GetHeightForPoint(xzPoint, cell, elevationDuck, flatlandNoise, hillsNoise));
     }
     else
     {
         throw new NotImplementedException();
     }
 }
        public float GetHeightForPoint(
            Vector2 xzPoint, AsyncTextureUnsafe <Color32> noiseTexture
            )
        {
            float noise = NoiseGenerator.SampleNoise(
                xzPoint, noiseTexture, RenderConfig.FlatlandsElevationNoiseStrength, NoiseType.ZeroToOne
                ).x;

            return(RenderConfig.FlatlandsBaseElevation + noise);
        }
Example #4
0
        public void GetHeightForPositionForCell_AndCellIsFlatlands_ReturnsHeightFromFlatlandsHeightmapLogic()
        {
            var position = new Vector3(1f, 2f, 3f);

            var cell = BuildCell(CellTerrain.Grassland, CellShape.Flatlands);

            var flatlandsNoise = new AsyncTextureUnsafe <Color32>();

            MockFlatlandsHeightmapLogic.Setup(logic => logic.GetHeightForPoint(position, flatlandsNoise)).Returns(15.25f);

            var heightmapLogic = Container.Resolve <CellHeightmapLogic>();

            Assert.AreEqual(15.25f, heightmapLogic.GetHeightForPointForCell(position, cell, 7.27f, flatlandsNoise, null));
        }
        public void GetTerrainHeightForPoint_AndPointNotOnGrid_ReturnsZero()
        {
            var point = new Vector2(1f, 2f);

            var orientationData = new PointOrientationData()
            {
                IsOnGrid = false
            };

            var flatlandsNoise = new AsyncTextureUnsafe <Color32>();
            var hillsNoise     = new AsyncTextureUnsafe <Color32>();

            var heightLogic = Container.Resolve <TerrainHeightLogic>();

            Assert.AreEqual(0f, heightLogic.GetHeightForPoint(point, orientationData, flatlandsNoise, hillsNoise));
        }
Example #6
0
        public float GetHeightForPoint(
            Vector2 xzPoint, PointOrientationData orientationData, AsyncTextureUnsafe <Color32> flatlandsNoise,
            AsyncTextureUnsafe <Color32> hillsNoise
            )
        {
            float retval = 0f;

            if (!orientationData.IsOnGrid)
            {
                return(retval);
            }

            if (orientationData.Center != null && orientationData.CenterWeight > 0f)
            {
                retval += orientationData.CenterWeight * CellHeightmapLogic.GetHeightForPointForCell(
                    xzPoint, orientationData.Center, orientationData.ElevationDuck, flatlandsNoise, hillsNoise
                    );
            }

            if (orientationData.Left != null && orientationData.LeftWeight > 0f)
            {
                retval += orientationData.LeftWeight * CellHeightmapLogic.GetHeightForPointForCell(
                    xzPoint, orientationData.Left, orientationData.ElevationDuck, flatlandsNoise, hillsNoise
                    );
            }

            if (orientationData.Right != null && orientationData.RightWeight > 0f)
            {
                retval += orientationData.RightWeight * CellHeightmapLogic.GetHeightForPointForCell(
                    xzPoint, orientationData.Right, orientationData.ElevationDuck, flatlandsNoise, hillsNoise
                    );
            }

            if (orientationData.NextRight != null && orientationData.NextRightWeight > 0f)
            {
                retval += orientationData.NextRightWeight * CellHeightmapLogic.GetHeightForPointForCell(
                    xzPoint, orientationData.NextRight, orientationData.ElevationDuck, flatlandsNoise, hillsNoise
                    );
            }

            if (orientationData.RiverWeight > 0f)
            {
                retval += orientationData.RiverWeight * RenderConfig.RiverTroughElevation;
            }

            return(retval);
        }
Example #7
0
        public float GetHeightForPoint(
            Vector2 xzPoint, float elevationDuck, AsyncTextureUnsafe <Color32> flatlandsNoiseTexture,
            AsyncTextureUnsafe <Color32> hillsNoiseTexture
            )
        {
            float hillNoise = NoiseGenerator.SampleNoise(
                xzPoint, hillsNoiseTexture, RenderConfig.HillsElevationNoiseStrength, NoiseType.ZeroToOne
                ).x;

            float hillsHeight = RenderConfig.HillsBaseElevation + hillNoise;

            float flatlandsHeight = FlatlandsHeightmapLogic.GetHeightForPoint(xzPoint, flatlandsNoiseTexture);

            var retval = Mathf.Lerp(hillsHeight, flatlandsHeight, elevationDuck);

            return(retval);
        }
        public void GetTerrainHeightForPoint_AndRiverWeightGreaterThanZero_ReturnsRiverWeightTimesTroughElevation()
        {
            var point = new Vector2(1f, 2f);

            var orientationData = new PointOrientationData()
            {
                IsOnGrid    = true,
                RiverWeight = 12f
            };

            var flatlandsNoise = new AsyncTextureUnsafe <Color32>();
            var hillsNoise     = new AsyncTextureUnsafe <Color32>();

            MockMapRenderConfig.Setup(config => config.RiverTroughElevation).Returns(8f);

            var heightLogic = Container.Resolve <TerrainHeightLogic>();

            Assert.AreEqual(96, heightLogic.GetHeightForPoint(point, orientationData, flatlandsNoise, hillsNoise));
        }
        public void GetTerrainHeightForPoint_AndMultipleWeightsGreaterThanZero_SumsAllWeightContributions()
        {
            var point = new Vector2(1f, 2f);

            var center    = BuildCell();
            var left      = BuildCell();
            var right     = BuildCell();
            var nextRight = BuildCell();

            var orientationData = new PointOrientationData()
            {
                IsOnGrid    = true,
                Center      = center, CenterWeight = 1f,
                Left        = left, LeftWeight = 5f,
                Right       = right, RightWeight = 1.5f,
                NextRight   = nextRight, NextRightWeight = 0.6f,
                RiverWeight = 2f, ElevationDuck = 5.5f
            };

            var flatlandsNoise = new AsyncTextureUnsafe <Color32>();
            var hillsNoise     = new AsyncTextureUnsafe <Color32>();

            MockCellHeightmapLogic.Setup(logic => logic.GetHeightForPointForCell(point, center, 5.5f, flatlandsNoise, hillsNoise)).Returns(10f);
            MockCellHeightmapLogic.Setup(logic => logic.GetHeightForPointForCell(point, left, 5.5f, flatlandsNoise, hillsNoise)).Returns(11f);
            MockCellHeightmapLogic.Setup(logic => logic.GetHeightForPointForCell(point, right, 5.5f, flatlandsNoise, hillsNoise)).Returns(12f);
            MockCellHeightmapLogic.Setup(logic => logic.GetHeightForPointForCell(point, nextRight, 5.5f, flatlandsNoise, hillsNoise)).Returns(13f);

            MockMapRenderConfig.Setup(config => config.RiverTroughElevation).Returns(6.2f);

            var heightLogic = Container.Resolve <TerrainHeightLogic>();

            float expectedValue = 10f + 55f + 1.5f * 12f + 0.6f * 13f + 2f * 6.2f;

            float pointHeight = heightLogic.GetHeightForPoint(point, orientationData, flatlandsNoise, hillsNoise);

            Assert.IsTrue(
                Mathf.Approximately(expectedValue, pointHeight), string.Format(
                    "Resulting height not approximately equal to expected results (Expected {0}, got {1})",
                    expectedValue, pointHeight
                    )
                );
        }
Example #10
0
        public void GetHeightForPoint_SamplesFlatlandNoise_AndFlatlandBaseElevation()
        {
            var xzPoint = new Vector2(1f, 2f);

            var noiseTexture = new AsyncTextureUnsafe <Color32>();

            MockRenderConfig.Setup(config => config.FlatlandsElevationNoiseStrength).Returns(-1f);
            MockRenderConfig.Setup(config => config.FlatlandsBaseElevation).Returns(100f);

            MockNoiseGenerator.Setup(generator => generator.SampleNoise(xzPoint, noiseTexture, -1f, NoiseType.ZeroToOne))
            .Returns(new Vector4(10f, 20f, 30f, 40f));

            MockRenderConfig.Setup(config => config.FlatlandsBaseElevation).Returns(100f);

            var cell = new Mock <IHexCell>().Object;

            var heightmapLogic = Container.Resolve <FlatlandsHeightmapLogic>();

            Assert.AreEqual(110f, heightmapLogic.GetHeightForPoint(xzPoint, noiseTexture));
        }
Example #11
0
        public Vector4 SampleNoise(Vector2 xzPosition, AsyncTextureUnsafe <Color32> source, float strength, NoiseType type)
        {
            Vector4 normalizedNoise = RawTextureSampler.SampleBilinear(
                xzPosition.x * RenderConfig.NoiseScale,
                xzPosition.y * RenderConfig.NoiseScale,
                source
                );

            if (type == NoiseType.NegativeOneToOne)
            {
                normalizedNoise.Set(
                    normalizedNoise.x * 2f - 1f,
                    normalizedNoise.y * 2f - 1f,
                    normalizedNoise.z * 2f - 1f,
                    normalizedNoise.w * 2f - 1f
                    );
            }

            return(normalizedNoise * strength);
        }
        public void GetTerrainHeightForPoint_AndNextRightNull_IgnoresNextRightContribution()
        {
            var point = new Vector2(1f, 2f);

            var orientationData = new PointOrientationData()
            {
                IsOnGrid        = true,
                NextRight       = null,
                NextRightWeight = 12f,
                ElevationDuck   = 5.5f
            };

            var flatlandsNoise = new AsyncTextureUnsafe <Color32>();
            var hillsNoise     = new AsyncTextureUnsafe <Color32>();

            MockCellHeightmapLogic.Setup(
                logic => logic.GetHeightForPointForCell(point, It.IsAny <IHexCell>(), 5.5f, flatlandsNoise, hillsNoise)
                ).Returns(8f);

            var heightLogic = Container.Resolve <TerrainHeightLogic>();

            Assert.AreEqual(0, heightLogic.GetHeightForPoint(point, orientationData, flatlandsNoise, hillsNoise));
        }
Example #13
0
        private IEnumerator RefreshHeightmap(ChunkOrientationData chunkOrientation)
        {
            var terrainData = Terrain.terrainData;

            var unsafeOrientationTexture = new AsyncTextureUnsafe <Color32>(chunkOrientation.OrientationTexture);
            var unsafeWeightsTexture     = new AsyncTextureUnsafe <Color32>(chunkOrientation.WeightsTexture);
            var unsafeDuckTexture        = new AsyncTextureUnsafe <Color32>(chunkOrientation.DuckTexture);

            var unsafeFlatlandsNoise = new AsyncTextureUnsafe <Color32>(RenderConfig.FlatlandsElevationNoiseSource);
            var unsafeHillsNoise     = new AsyncTextureUnsafe <Color32>(RenderConfig.HillsElevationNoiseSource);

            Vector3 terrainSize = terrainData.size;

            int mapWidth  = terrainData.heightmapWidth;
            int mapHeight = terrainData.heightmapHeight;

            float[,] heights = terrainData.GetHeights(0, 0, mapWidth, mapHeight);

            float maxTextureNormalX = Width / RenderConfig.ChunkWidth;
            float maxTextureNormalZ = Height / RenderConfig.ChunkHeight;

            float indexToNormalX = 1f / (mapHeight - 1f);
            float indexToNormalZ = 1f / (mapWidth - 1f);

            Vector3 chunkPosition = transform.position;

            var columnTasks = new Task[mapHeight];

            for (int height = 0; height < mapHeight; height++)
            {
                int cachedHeight = height;

                var indexBytes = new byte[2];

                PointOrientationData pointOrientation = new PointOrientationData();

                var columnTask = new Task(() => {
                    for (int width = 0; width < mapWidth; width++)
                    {
                        float terrainNormalX, terrainNormalZ, textureNormalX, textureNormalZ, worldX, worldZ;

                        Color32 orientationColor;
                        Color weightsColor, duckColor;

                        //For some reason, terrainData seems to index its points
                        //as (y, x) rather than the more traditional (x, y), so
                        //we need to sample our texture accordingly
                        terrainNormalX = cachedHeight * indexToNormalX;
                        terrainNormalZ = width * indexToNormalZ;

                        worldX = chunkPosition.x + terrainNormalX * terrainSize.x;
                        worldZ = chunkPosition.z + terrainNormalZ * terrainSize.z;

                        textureNormalX = maxTextureNormalX * terrainNormalX;
                        textureNormalZ = maxTextureNormalZ * terrainNormalZ;

                        orientationColor = ColorCorrection.ARGB_To_RGBA(RawTextureSampler.SamplePoint(textureNormalX, textureNormalZ, unsafeOrientationTexture));
                        weightsColor     = ColorCorrection.ARGB_To_RGBA(RawTextureSampler.SamplePoint(textureNormalX, textureNormalZ, unsafeWeightsTexture));
                        duckColor        = ColorCorrection.ARGB_To_RGBA(RawTextureSampler.SamplePoint(textureNormalX, textureNormalZ, unsafeDuckTexture));

                        PointOrientationLogic.GetOrientationDataFromColors(
                            pointOrientation, indexBytes, orientationColor, weightsColor, duckColor
                            );

                        heights[width, cachedHeight] = HeightLogic.GetHeightForPoint(
                            new Vector2(worldX, worldZ), pointOrientation, unsafeFlatlandsNoise, unsafeHillsNoise
                            );
                    }
                });

                columnTask.Start();

                columnTasks[cachedHeight] = columnTask;
            }

            while (columnTasks.Any(task => !task.IsCompleted))
            {
                yield return(SkipFrame);
            }

            terrainData.SetHeights(0, 0, heights);
        }
Example #14
0
        private IEnumerator RefreshAlphamap(ChunkOrientationData orientationData)
        {
            var terrainData = Terrain.terrainData;

            var unsafeOrientationTexture = new AsyncTextureUnsafe <Color32>(orientationData.OrientationTexture);
            var unsafeWeightsTexture     = new AsyncTextureUnsafe <Color32>(orientationData.WeightsTexture);
            var unsafeDuckTexture        = new AsyncTextureUnsafe <Color32>(orientationData.DuckTexture);

            Vector3 terrainSize = terrainData.size;

            int mapWidth  = terrainData.alphamapWidth;
            int mapHeight = terrainData.alphamapHeight;

            int alphamapLength = RenderConfig.MapTextures.Count();

            float[,,] alphaMaps = terrainData.GetAlphamaps(0, 0, mapWidth, mapHeight);

            float maxTextureNormalX = Width / RenderConfig.ChunkWidth;
            float maxTextureNormalZ = Height / RenderConfig.ChunkHeight;

            float indexToNormalX = 1f / (mapHeight - 1f);
            float indexToNormalZ = 1f / (mapWidth - 1f);

            Vector3 chunkPosition = transform.position;

            var columnTasks = new Task[mapHeight];

            for (int height = 0; height < mapHeight; height++)
            {
                int cachedHeight = height;

                var indexBytes = new byte[2];

                PointOrientationData pointOrientation = new PointOrientationData();

                float[] returnMap       = new float[RenderConfig.MapTextures.Count()];
                float[] intermediateMap = new float[RenderConfig.MapTextures.Count()];

                var columnTask = new Task(() => {
                    for (int width = 0; width < mapWidth; width++)
                    {
                        float terrainNormalX, terrainNormalZ, textureNormalX, textureNormalZ, worldX, worldZ;

                        Color32 orientationColor;
                        Color weightsColor, duckColor;

                        //For some reason, terrainData seems to index its points
                        //as (y, x) rather than the more traditional (x, y), so
                        //we need to sample our texture accordingly
                        terrainNormalX = cachedHeight * indexToNormalX;
                        terrainNormalZ = width * indexToNormalZ;

                        worldX = chunkPosition.x + terrainNormalX * terrainSize.x;
                        worldZ = chunkPosition.z + terrainNormalZ * terrainSize.z;

                        textureNormalX = maxTextureNormalX * terrainNormalX;
                        textureNormalZ = maxTextureNormalZ * terrainNormalZ;

                        orientationColor = ColorCorrection.ARGB_To_RGBA(RawTextureSampler.SamplePoint(textureNormalX, textureNormalZ, unsafeOrientationTexture));
                        weightsColor     = ColorCorrection.ARGB_To_RGBA(RawTextureSampler.SamplePoint(textureNormalX, textureNormalZ, unsafeWeightsTexture));
                        duckColor        = ColorCorrection.ARGB_To_RGBA(RawTextureSampler.SamplePoint(textureNormalX, textureNormalZ, unsafeDuckTexture));

                        PointOrientationLogic.GetOrientationDataFromColors(
                            pointOrientation, indexBytes, orientationColor, weightsColor, duckColor
                            );

                        AlphamapLogic.GetAlphamapFromOrientation(returnMap, intermediateMap, pointOrientation);

                        for (int alphaIndex = 0; alphaIndex < alphamapLength; alphaIndex++)
                        {
                            alphaMaps[width, cachedHeight, alphaIndex] = returnMap[alphaIndex];
                        }
                    }
                });

                columnTask.Start();

                columnTasks[cachedHeight] = columnTask;
            }

            while (columnTasks.Any(task => !task.IsCompleted))
            {
                yield return(SkipFrame);
            }

            terrainData.SetAlphamaps(0, 0, alphaMaps);
        }