示例#1
0
    private void spawnDigParticle(Vector3 pos)
    {
        if (CoopPeerStarter.DedicatedHost)
        {
            return;
        }
        Vector3 pos2 = pos;

        pos2.y = Terrain.activeTerrain.SampleHeight(pos) + Terrain.activeTerrain.transform.position.y;
        if (this.IsOnSnow())
        {
            PoolManager.Pools["Particles"].Spawn(LocalPlayer.ScriptSetup.events.snowFootParticle.transform, pos2, Quaternion.identity);
            return;
        }
        int prominantTextureIndex = TerrainHelper.GetProminantTextureIndex(base.transform.position);

        if (prominantTextureIndex == 6 || prominantTextureIndex == 1)
        {
            PoolManager.Pools["Particles"].Spawn(LocalPlayer.ScriptSetup.events.leafFootParticle.transform, pos2, Quaternion.identity);
        }
        else if (prominantTextureIndex == 3 || prominantTextureIndex == 0)
        {
            PoolManager.Pools["Particles"].Spawn(LocalPlayer.ScriptSetup.events.dustFootParticle.transform, pos2, Quaternion.identity);
        }
        else if (prominantTextureIndex == 4)
        {
            PoolManager.Pools["Particles"].Spawn(LocalPlayer.ScriptSetup.events.sandFootParticle.transform, pos2, Quaternion.identity);
        }
    }
示例#2
0
        public void InitializeHeightsAndNormals()
        {
            // Create a procedural height field.
            int numberOfSamples = 1025;

            float[] heights = new float[numberOfSamples * numberOfSamples];
            var     creator = new ProceduralTerrainCreator(RandomHelper.Random.Next(), 256, _noiseMu);

            creator.CreateTerrain(
                7777, 9999, _noiseWidth * _terrainTile.CellSize, _noiseWidth * _terrainTile.CellSize,
                0, _noiseHeight, 8, heights, numberOfSamples, numberOfSamples);

            float tileSize = (numberOfSamples - 1) * _terrainTile.CellSize;

            _terrainTile.OriginX = -tileSize / 2;
            _terrainTile.OriginZ = -tileSize / 2;

            Debug.Assert(Numeric.IsZero(_terrainTile.OriginX % _terrainTile.CellSize), "The tile origin must be an integer multiple of the cell size.");
            Debug.Assert(Numeric.IsZero(_terrainTile.OriginZ % _terrainTile.CellSize), "The tile origin must be an integer multiple of the cell size.");

            //TerrainHelper.SmoothTexture(heights, numberOfSamples, numberOfSamples, 1e10f);

            // Rebuild height texture.
            Texture2D heightTexture = _terrainTile.HeightTexture;

            TerrainHelper.CreateHeightTexture(
                _graphicsService.GraphicsDevice,
                heights,
                numberOfSamples,
                numberOfSamples,
                false,
                ref heightTexture);

            // Rebuild normal texture.
            Texture2D normalTexture = _terrainTile.NormalTexture;

            TerrainHelper.CreateNormalTexture(
                _graphicsService.GraphicsDevice,
                heights,
                numberOfSamples,
                numberOfSamples,
                _terrainTile.CellSize,
                false,
                ref normalTexture);

            _terrainTile.HeightTexture = heightTexture;
            _terrainTile.NormalTexture = normalTexture;

            // Set the height field data for collision detection.
            var heightField = (HeightField)_rigidBody.Shape;

            heightField.OriginX = _terrainTile.OriginX;
            heightField.OriginZ = _terrainTile.OriginZ;
            heightField.WidthX  = tileSize;
            heightField.WidthZ  = tileSize;
            heightField.SetSamples(heights, heightTexture.Width, heightTexture.Height);
            heightField.Invalidate();

            TerrainNode.Terrain.Invalidate();
        }
示例#3
0
        /// <summary>
        /// Applies the damage to affected chunks.
        /// </summary>
        /// <param name="damage">Damage.</param>
        private void ApplyDamage(List <IntPoint> damage)
        {
            long minX = long.MaxValue, minY = long.MaxValue,
                 maxX = long.MinValue, maxY = long.MinValue;

            for (int i = 0; i < damage.Count; ++i)
            {
                if (damage[i].X < minX)
                {
                    minX = damage[i].X;
                }
                if (damage[i].X > maxX)
                {
                    maxX = damage[i].X;
                }

                if (damage[i].Y < minY)
                {
                    minY = damage[i].Y;
                }
                if (damage[i].Y > maxY)
                {
                    maxY = damage[i].Y;
                }
            }

            minX = Helper.NegDivision(minX, Chunk.SIZE);
            maxX = Helper.NegDivision(maxX, Chunk.SIZE);
            minY = Helper.NegDivision(minY, Chunk.SIZE);
            maxY = Helper.NegDivision(maxY, Chunk.SIZE);

            var clipper = new Clipper();

            for (int y = (int)minY; y <= maxY; ++y)
            {
                for (int x = (int)minX; x <= maxX; ++x)
                {
                    var chunk = GetChunk(TerrainHelper.PackCoordinates(x, y));

                    clipper.Clear();
                    clipper.AddPolygon(new List <IntPoint>()
                    {
                        new IntPoint(chunk.Left, chunk.Top),
                        new IntPoint(chunk.Left + Chunk.SIZE, chunk.Top),
                        new IntPoint(chunk.Left + Chunk.SIZE, chunk.Top + Chunk.SIZE),
                        new IntPoint(chunk.Left, chunk.Top + Chunk.SIZE)
                    }, PolyType.ptSubject);
                    clipper.AddPolygon(damage, PolyType.ptClip);
                    clipper.AddPolygons(chunk.Damage, PolyType.ptClip);
                    clipper.Execute(ClipType.ctIntersection, chunk.Damage,
                                    PolyFillType.pftNonZero, PolyFillType.pftNonZero);

                    chunk.Recalculate = true;
                    if (ActiveChunks.Contains(chunk))
                    {
                        Task.Run(() => { PlaceChunk(chunk); });
                    }
                }
            }
        }
示例#4
0
    private string GetLandEventForPosition()
    {
        if (this.IsOnSnow())
        {
            this.isSnow = true;
            return(this.landSnow);
        }
        if (this.surfaceDetector.Surface != UnderfootSurfaceDetector.SurfaceType.None)
        {
            return(this.landDefault);
        }
        if (LocalPlayer.FpCharacter.IsInWater())
        {
            return(this.landWater);
        }
        int prominantTextureIndex = TerrainHelper.GetProminantTextureIndex(base.transform.position);

        if (prominantTextureIndex == 1)
        {
            return(this.landMud);
        }
        if (prominantTextureIndex != 4)
        {
            return(this.landDefault);
        }
        return(this.landSand);
    }
        public void GetTerrainForHeight_Returns_Lowland_When_Height_Is_From_145_To_170(byte height)
        {
            var      terrainHelper = new TerrainHelper();
            ITerrain terrain       = terrainHelper.GetTerrainForHeight(height);

            Assert.IsInstanceOf <Lowland>(terrain);
        }
示例#6
0
        protected override void RenderTopCornerFace(TileDrawInfo drawInfo, int index)
        {
            float      height = this.height + tileHeight;
            FastColour colour = lineMode ? new FastColour(150, 150, 150) :
                                TerrainHelper.GetColour(drawInfo.CurrentTile.TerrainId);

            if (!lineMode)
            {
                vertices[index]     = new Vertex(x + halfTileWidth, height, y, colour);
                vertices[index + 1] = new Vertex(x, z2, y + halfTileLength, colour);
                vertices[index + 2] = new Vertex(x + halfTileWidth, height, y + tileWidth, colour);

                vertices[index + 3] = new Vertex(x + halfTileWidth, height, y, colour);
                vertices[index + 4] = new Vertex(x + tileWidth, z1, y + halfTileLength, colour);
                vertices[index + 5] = new Vertex(x + halfTileWidth, height, y + tileWidth, colour);
            }
            else
            {
                vertices[index]     = new Vertex(x + halfTileWidth, height, y, colour);
                vertices[index + 1] = new Vertex(x, z2, y + halfTileLength, colour);
                vertices[index + 2] = new Vertex(x + halfTileWidth, height, y + tileWidth, colour);
                vertices[index + 3] = new Vertex(x + tileWidth, z1, y + halfTileLength, colour);
            }
            drawInfo.TotalTriangles += 2;
        }
示例#7
0
        protected override void RenderStretchedFlatFace(TileDrawInfo drawInfo, int index)
        {
            FastColour colour = lineMode ? new FastColour(150, 150, 150) :
                                TerrainHelper.GetColour(drawInfo.CurrentTile.TerrainId);

            if (!lineMode)
            {
                vertices[index]     = new Vertex(x, z1, y + 0.5f, colour);
                vertices[index + 1] = new Vertex(x + 0.5f, z1, y, colour);
                vertices[index + 2] = new Vertex(x + stretchY, z2, y + stretchY - halfTileLength, colour);

                vertices[index + 3] = new Vertex(x + stretchY, z2, y + stretchY - halfTileLength, colour);
                vertices[index + 4] = new Vertex(x + stretchY - halfTileWidth, z2, y + stretchY, colour);
                vertices[index + 5] = new Vertex(x, z1, y + 0.5f, colour);
            }
            else
            {
                vertices[index]     = new Vertex(x, z1, y + 0.5f, colour);
                vertices[index + 1] = new Vertex(x + 0.5f, z1, y, colour);
                vertices[index + 2] = new Vertex(x + stretchY, z2, y + stretchY - halfTileLength, colour);
                vertices[index + 3] = new Vertex(x + stretchY - halfTileWidth, z2, y + stretchY, colour);
            }

            drawInfo.TotalTriangles += 2;
        }
示例#8
0
    void Start()
    {
        cam = Camera.main.gameObject.
              GetComponent <CameraTest>();

        TerrainHelper.SetTerrainData(
            GetComponent <MeshFilter>().mesh);
    }
示例#9
0
            /// <summary>
            /// Calculate render and physics data.
            /// </summary>
            public void Calculate(GameWorld world)
            {
                var clipper = new Clipper();
                List <List <IntPoint> > output = new List <List <IntPoint> >();

                // Calculate difference
                clipper.AddPolygons(Polygons, PolyType.ptSubject);
                clipper.AddPolygons(Cavities, PolyType.ptClip);
                clipper.AddPolygons(Damage, PolyType.ptClip);
                clipper.Execute(ClipType.ctDifference, output, PolyFillType.pftNonZero, PolyFillType.pftNonZero);

                Hulls.Clear();
                output.ForEach(o =>
                {
                    Vector2[] points = new Vector2[o.Count];
                    int index        = 0;
                    o.ForEach(p => points[index++] = new Vector2(p.X, p.Y));
                    Hulls.Add(new Penumbra.Hull(points));
                });

                // Triangulate background for rendering
                {
                    var triangulation = TerrainHelper.Triangulate(Polygons);
                    TriangulatedBackgroundVertices = new VertexPositionColor[triangulation.Count * 3];
                    int index = 0;
                    for (int i = 0; i < triangulation.Count; ++i)
                    {
                        for (int b = 0; b < 3; ++b)
                        {
                            TriangulatedBackgroundVertices[index++] = new VertexPositionColor(
                                new Vector3(triangulation[i][b].X, triangulation[i][b].Y, 0), world.Planet.BackgroundSoilTint);
                        }
                    }
                }

                // Triangulate foreground for rendering
                {
                    var triangulation = TerrainHelper.Triangulate(output);
                    TriangulatedForegroundVertices = new VertexPositionColor[triangulation.Count * 3];
                    int index = 0;
                    for (int i = 0; i < triangulation.Count; ++i)
                    {
                        for (int b = 0; b < 3; ++b)
                        {
                            TriangulatedForegroundVertices[index++] = new VertexPositionColor(
                                new Vector3(triangulation[i][b].X, triangulation[i][b].Y, 0), world.Planet.SoilTint);
                        }
                    }
                }

                // Convert to Farseer data
                PhysicsOutput.Clear();
                output.ForEach(p =>
                {
                    PhysicsOutput.Add(TerrainHelper.PolygonToVertices(p));
                });
            }
示例#10
0
    public string GetFootstepForPosition()
    {
        this.isSnow = false;
        switch (this.surfaceDetector.Surface)
        {
        case UnderfootSurfaceDetector.SurfaceType.None:
            if (this.IsOnSnow())
            {
                this.isSnow = true;
                return(this.footstepSnow);
            }
            switch (TerrainHelper.GetProminantTextureIndex(base.transform.position))
            {
            case 0:
                return(this.footstepDefault);

            case 1:
                return(this.footstepMud);

            case 2:
            case 3:
            case 5:
            case 7:
                return(this.footstepRock);

            case 4:
                return(this.footstepSand);

            case 6:
                return(this.footstepLeaves);

            default:
                return(this.footstepDefault);
            }
            break;

        case UnderfootSurfaceDetector.SurfaceType.Wood:
            return(this.footstepWood);

        case UnderfootSurfaceDetector.SurfaceType.Rock:
            return(this.footstepRock);

        case UnderfootSurfaceDetector.SurfaceType.Carpet:
            return(this.footstepCarpet);

        case UnderfootSurfaceDetector.SurfaceType.Dirt:
            return(this.footstepDefault);

        case UnderfootSurfaceDetector.SurfaceType.Metal:
            return(this.footstepMetal);

        default:
            return(this.footstepDefault);
        }
    }
示例#11
0
        void RenderTopCornerFace(TileDrawInfo drawInfo, Vertex[] vertices, int index)
        {
            FastColour colour = TerrainHelper.GetColour(drawInfo.CurrentTile.TerrainId);

            vertices[index]     = new Vertex(X + 0.5f, height, Y, colour);
            vertices[index + 1] = new Vertex(X, z2, Y + 0.5f, colour);
            vertices[index + 2] = new Vertex(X + 0.5f, height, Y + tileWidth, colour);

            vertices[index + 3]      = new Vertex(X + 0.5f, height, Y, colour);
            vertices[index + 4]      = new Vertex(X + tileWidth, z1, Y + 0.5f, colour);
            vertices[index + 5]      = new Vertex(X + 0.5f, height, Y + tileWidth, colour);
            drawInfo.TotalTriangles += 2;
        }
示例#12
0
        protected override void RenderBottomCornerFace(TileDrawInfo drawInfo, int index)
        {
            FastColour colour = TerrainHelper.GetColour(drawInfo.CurrentTile.TerrainId);

            vertices[index]     = new Vertex(x + 0.5f, height, y, colour);
            vertices[index + 1] = new Vertex(x, z2, y + 0.5f, colour);
            vertices[index + 2] = new Vertex(x + 0.5f, height, y + tileWidth, colour);

            vertices[index + 3]      = new Vertex(x + 0.5f, height, y, colour);
            vertices[index + 4]      = new Vertex(x + tileWidth, z1, y + 0.5f, colour);
            vertices[index + 5]      = new Vertex(x + 0.5f, height, y + tileWidth, colour);
            drawInfo.TotalTriangles += 2;
        }
示例#13
0
    public void spawnTree(Hex hex, float heightSeed)
    {
        GameObject newTree      = Instantiate(treePrefab);
        Vector2    treePosition = Random.insideUnitCircle * this.getHexSize();

        treePosition += HexMathHelper.hexToWorldCoords(hex.getPosition(), this.getHexSize());
        float   spawnHeight = TerrainHelper.getHeight(heightSeed, treePosition, hex, this.getHexSize(), elevatedHeightmap, mountainHeightmap);
        float   yScale      = Random.Range(0.05f, 0.08f);
        Vector3 newScale    = newTree.transform.localScale;

        newScale.y = yScale;
        newTree.transform.localScale = newScale;
        newTree.transform.position   = new Vector3(treePosition.x, treePosition.y, spawnHeight - 0.12f);
    }
示例#14
0
        protected override void RenderTopCornerFaceRotated(TileDrawInfo drawInfo, int index)
        {
            float      height = this.height + tileHeight;
            FastColour colour = TerrainHelper.GetColour(drawInfo.CurrentTile.TerrainId);

            vertices[index]     = new Vertex(x, height, y + 0.5f, colour);
            vertices[index + 1] = new Vertex(x + 0.5f, z1, y, colour);
            vertices[index + 2] = new Vertex(x + tileWidth, height, y + 0.5f, colour);

            vertices[index + 3]      = new Vertex(x + tileWidth, height, y + 0.5f, colour);
            vertices[index + 4]      = new Vertex(x + 0.5f, z2, y + tileWidth, colour);
            vertices[index + 5]      = new Vertex(x, height, y + 0.5f, colour);
            drawInfo.TotalTriangles += 2;
        }
示例#15
0
        // Modify the terrain height values to add the road to the terrain.
        private void ClampTerrainToRoad()
        {
            // We have to manipulate the height and normal texture of each tile which contains the road.
            foreach (var tile in _terrainObject.TerrainNode.Terrain.Tiles)
            {
                // Get the current height texture of the tile and extract the heights into a float array.
                var     heightTexture = tile.HeightTexture;
                float[] heights       = TerrainHelper.GetTextureLevelSingle(heightTexture, 0);

                // Create a temporary height field.
                var heightField = new HeightField(
                    tile.OriginX,
                    tile.OriginZ,
                    tile.WidthX,
                    tile.WidthZ,
                    heights,
                    heightTexture.Width,
                    heightTexture.Height);

                // Change the height values of the height field.
                TerrainRoadLayer.ClampTerrainToRoad(heightField, _roadPath, 8, 30, 10, 0.1f);

                // Rebuild the height texture.
                TerrainHelper.CreateHeightTexture(
                    GraphicsService.GraphicsDevice,
                    heights,
                    heightTexture.Width,
                    heightTexture.Height,
                    false,
                    ref heightTexture);

                // Rebuild the normal texture.
                var normalTexture = tile.NormalTexture;
                TerrainHelper.CreateNormalTexture(
                    GraphicsService.GraphicsDevice,
                    heights,
                    heightTexture.Width,
                    heightTexture.Height,
                    tile.CellSize,
                    false,
                    ref normalTexture);

                // Get rigid body that represents this tile.
                var rigidBody = Simulation.RigidBodies.First(body => body.UserData == tile);

                // Update the height values of the collision detection height field.
                ((HeightField)rigidBody.Shape).SetSamples(heights, heightTexture.Width, heightTexture.Height);
            }
        }
示例#16
0
        void RenderTile(TileDrawInfo drawInfo, VertexPos3Tex2[] vertices, int index)
        {
            Tile tile = drawInfo.CurrentTile;

            X      = tile.X;
            Y      = tile.Y;
            height = tile.Height;

            RectangleF texRec = TerrainHelper.GetTexRec(tile.TerrainId);

            vertices[index]          = new VertexPos3Tex2(X, height, Y, texRec.Left, texRec.Top);
            vertices[index + 1]      = new VertexPos3Tex2(X + tileWidth, height, Y, texRec.Right, texRec.Top);
            vertices[index + 2]      = new VertexPos3Tex2(X + tileWidth, height, Y + tileWidth, texRec.Right, texRec.Bottom);
            vertices[index + 3]      = new VertexPos3Tex2(X, height, Y + tileWidth, texRec.Left, texRec.Bottom);
            drawInfo.TotalTriangles += 2;
        }
示例#17
0
        /// <summary>
        /// Sets a region around a point as active.
        /// </summary>
        /// <param name="center">Center.</param>
        public override void SetActiveArea(Vector2 center)
        {
            _activeX = Helper.NegDivision((int)center.X, Chunk.SIZE);
            _activeY = Helper.NegDivision((int)center.Y, Chunk.SIZE);

            Chunk[] newActive = new Chunk[CHUNK_CACHE * CHUNK_CACHE];
            for (int y = 0; y < CHUNK_CACHE; ++y)
            {
                for (int x = 0; x < CHUNK_CACHE; ++x)
                {
                    var   cX    = x + _activeX - CHUNK_CACHE / 2;
                    var   cY    = y + _activeY - CHUNK_CACHE / 2;
                    var   id    = TerrainHelper.PackCoordinates(cX, cY);
                    Chunk chunk = null;
                    if (ActiveChunks.Any(c => c != null && c.ID == id))
                    {
                        chunk = ActiveChunks.First(c => c != null && c.ID == id);
                    }
                    else
                    {
                        chunk = GetChunk(id);
                        if (Multithreaded)
                        {
                            Task.Run(() => { PlaceChunk(chunk); });
                        }
                        else
                        {
                            PlaceChunk(chunk);
                        }
                    }
                    newActive[x + y * CHUNK_CACHE] = chunk;
                }
            }

            for (int i = 0; i < ActiveChunks.Length; ++i)
            {
                if (ActiveChunks[i] != null && !newActive.Contains(ActiveChunks[i]))
                {
                    UnplaceChunk(ActiveChunks[i]);
                    if (!ActiveChunks[i].ShouldSave)
                    {
                        ChunkCache.Remove(ActiveChunks[i].ID);
                    }
                }
            }
            ActiveChunks = newActive;
        }
示例#18
0
        void RenderTile(TileDrawInfo drawInfo)
        {
            Tile tile = drawInfo.CurrentTile;

            const int xWidth = 1, yWidth = 1;

            float X = tile.X * xWidth;
            float Y = tile.Y * yWidth;

            float x1 = X, y1 = Y;
            //X = ( x1 * xWidth / 2f ) + ( y1 * xWidth / 2f );
            //Y = ( y1 * yWidth / 2f ) - ( x1 * yWidth / 2f );
            float z = 1;

            /*if( ( tile.X % 2 ) == 0 ) {
             *      //X /= 2f;
             *      //X += xWidth / 2f;
             *      //y += yWidth / 2f;
             *      //Y /= 2f;
             *      Y += yWidth * 5;
             *      Y -= (int)( yWidth / 2f );
             *      //return;
             *      //return;
             * } else {
             *      X /= 2f;
             * }*/

            RectangleF texRec = TerrainHelper.GetTexRec(tile.TerrainId);

            float Width = xWidth;
            float Depth = yWidth;

            float xHalf = Width / 2;

            GL.TexCoord2(0f, 0f); GL.Vertex3(X - xHalf, z, Y + Depth / 4);               // Bottom left
            GL.TexCoord2(1f, 0f); GL.Vertex3(X + xHalf, z, Y + Depth / 4);               // Bottom Right
            GL.TexCoord2(1f, 1f); GL.Vertex3(X + xHalf, z, Y - 3 * Depth / 4);           // Top Right
            GL.TexCoord2(0f, 1f); GL.Vertex3(X - xHalf, z, Y - 3 * Depth / 4);           // Top Left

            //VertexPosUv( x, height, y, texRec.Left, texRec.Top );
            //VertexPosUv( x + tileWidth, height, y, texRec.Right, texRec.Top );
            //VertexPosUv( x + tileWidth, height, y + tileHeight, texRec.Right, texRec.Bottom );
            //VertexPosUv( x, height, y + tileHeight, texRec.Left, texRec.Bottom );

            drawInfo.TotalTriangles += 2;
        }
        public void GetTerrains(BitmapDto model)
        {
            var heightMap = new Bitmap(model.Path);

            TerrainHelper.SetTerrains(BitmapToPixelArray(heightMap));

            var terrainHelper = new TerrainHelper();

            var terrains = terrainHelper.GetAllTerrains()
                           .Select(t => new TerrainDto()
            {
                Type             = t.GetType().Name,
                UpperHeightBound = t.UpperBound
            });

            Clients.All.OnGetTerrainsResponse(terrains);
        }
示例#20
0
    //------------------------ events -------------------------
    void OnMouseDown()
    {
        RaycastHit hit;
        Ray        ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out hit))
        {
            cam.AdjustPath(Quaternion.LookRotation(hit.point));

            int[] selected_quad = TerrainHelper.TriangleIndices(hit.triangleIndex);

            string debug_text = hit.triangleIndex.ToString() + ": "
                                + selected_quad[0].ToString() + ", "
                                + selected_quad[1].ToString();

            Debug.Log(debug_text);
        }
    }
        public TerrainTextureSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            SampleFramework.IsMouseVisible = false;

            _graphicsScreen             = new DeferredGraphicsScreen(Services);
            _graphicsScreen.DrawReticle = true;
            GraphicsService.Screens.Insert(0, _graphicsScreen);
            GameObjectService.Objects.Add(new DeferredGraphicsOptionsObject(Services));

            Services.Register(typeof(DebugRenderer), null, _graphicsScreen.DebugRenderer);

            var scene = _graphicsScreen.Scene;

            Services.Register(typeof(IScene), null, scene);

            // Add gravity and damping to the physics simulation.
            Simulation.ForceEffects.Add(new Gravity());
            Simulation.ForceEffects.Add(new Damping());

            // Add a custom game object which controls the camera.
            var cameraGameObject = new CameraObject(Services, 60);

            cameraGameObject.ResetPose(new Vector3F(0, 1.8f, 0), 0, 0);
            GameObjectService.Objects.Add(cameraGameObject);
            _graphicsScreen.ActiveCameraNode = cameraGameObject.CameraNode;

            for (int i = 0; i < 10; i++)
            {
                GameObjectService.Objects.Add(new DynamicObject(Services, 1));
            }

            GameObjectService.Objects.Add(new DynamicSkyObject(Services, true, false, true));

            // Create a simple flat terrain.
            var terrain = new Terrain();

            _terrainTile = new TerrainTile(GraphicsService)
            {
                OriginX  = -100,
                OriginZ  = -100,
                CellSize = 1,
            };
            terrain.Tiles.Add(_terrainTile);

            // Create a flat dummy height texture.
            float[]   heights       = new float[200 * 200];
            Texture2D heightTexture = null;

            TerrainHelper.CreateHeightTexture(
                GraphicsService.GraphicsDevice,
                heights,
                200,
                200,
                false,
                ref heightTexture);
            _terrainTile.HeightTexture = heightTexture;

            var shadowMapEffect = ContentManager.Load <Effect>("DigitalRune/Terrain/TerrainShadowMap");
            var gBufferEffect   = ContentManager.Load <Effect>("DigitalRune/Terrain/TerrainGBuffer");
            var materialEffect  = ContentManager.Load <Effect>("DigitalRune/Terrain/TerrainMaterial");
            var material        = new Material
            {
                { "ShadowMap", new EffectBinding(GraphicsService, shadowMapEffect, null, EffectParameterHint.Material) },
                { "GBuffer", new EffectBinding(GraphicsService, gBufferEffect, null, EffectParameterHint.Material) },
                { "Material", new EffectBinding(GraphicsService, materialEffect, null, EffectParameterHint.Material) }
            };
            var terrainNode = new TerrainNode(terrain, material)
            {
                DetailClipmap =
                {
                    CellsPerLevel  = 1364,
                    NumberOfLevels =    9,
                    EnableMipMap   = true,
                },
            };

            scene.Children.Add(terrainNode);

            // Add 3 detail textures layers: gravel, rock, snow.
            float detailCellSize = terrainNode.DetailClipmap.CellSizes[0];
            var   materialGravel = new TerrainMaterialLayer(GraphicsService)
            {
                DiffuseTexture  = ContentManager.Load <Texture2D>("Terrain/Gravel-Diffuse"),
                NormalTexture   = ContentManager.Load <Texture2D>("Terrain/Gravel-Normal"),
                SpecularTexture = ContentManager.Load <Texture2D>("Terrain/Gravel-Specular"),
                TileSize        = detailCellSize * 512,
                BlendRange      = 0.1f,
            };

            _terrainTile.Layers.Add(materialGravel);

            var noiseTexture = NoiseHelper.GetNoiseTexture(GraphicsService, 128, 60);

            var materialRock = new TerrainMaterialLayer(GraphicsService)
            {
                DiffuseTexture          = ContentManager.Load <Texture2D>("Terrain/Rock-02-Diffuse"),
                NormalTexture           = ContentManager.Load <Texture2D>("Terrain/Rock-02-Normal"),
                SpecularTexture         = ContentManager.Load <Texture2D>("Terrain/Rock-02-Specular"),
                HeightTexture           = ContentManager.Load <Texture2D>("Terrain/Rock-02-Height"),
                TileSize                = detailCellSize * 1024,
                DiffuseColor            = new Vector3F(1 / 0.702f),
                BlendTexture            = noiseTexture,
                BlendTextureChannel     = 0,
                BlendRange              = 0.1f,
                TerrainHeightBlendRange = 0.1f,
            };

            _terrainTile.Layers.Add(materialRock);

            var materialSnow = new TerrainMaterialLayer(GraphicsService)
            {
                DiffuseTexture      = ContentManager.Load <Texture2D>("Terrain/Snow-Diffuse"),
                NormalTexture       = ContentManager.Load <Texture2D>("Terrain/Snow-Normal"),
                SpecularTexture     = ContentManager.Load <Texture2D>("Terrain/Snow-Specular"),
                TileSize            = detailCellSize * 512,
                BlendTexture        = noiseTexture,
                BlendTextureChannel = 1,
                BlendRange          = 0.1f,
            };

            _terrainTile.Layers.Add(materialSnow);

            // Create a flat plane for collision detection.
            var rigidBody = new RigidBody(new PlaneShape(), new MassFrame(), null)
            {
                MotionType = MotionType.Static,
            };

            Simulation.RigidBodies.Add(rigidBody);

            CreateGuiControls();
        }
示例#22
0
 private float getRandomWanderForce(Vector3 vertice)
 {
     //return Random.Range(-0.05f, 0.05f);
     return(TerrainHelper.getWaterCurvingHeight(vertice, currentPerlinNoise));
 }
示例#23
0
        private void UpdateHoleTexture()
        {
            // Hole information could be loaded from a texture. Here, we procedurally create a pattern of
            // holes.
            // The hole buffer is array with 1 where there is no hole and 0 where there is a hole.
            // (This is similar to an alpha mask: 1 = opaque, 0 = transparent.)
            int numberOfSamples = _terrainObject.TerrainNode.Terrain.Tiles.First().HeightTexture.Width;

            float[] holes = new float[numberOfSamples * numberOfSamples];

            // Fill hole buffer with 1.
            for (int i = 0; i < holes.Length; i++)
            {
                holes[i] = 1;
            }

            if (_holeSize > 0)
            {
                // Add some 0 elements to create holes.
                int counterY = _holeSize;
                for (int y = 0; y < numberOfSamples - 1; y++)
                {
                    int counterX = _holeSize;
                    for (int x = 0; x < numberOfSamples - 1; x++)
                    {
                        holes[y * numberOfSamples + x] = 0;

                        counterX--;
                        if (counterX <= 0)
                        {
                            counterX = _holeSize;
                            x       += _holeSize * 2;
                        }
                    }

                    counterY--;
                    if (counterY <= 0)
                    {
                        counterY = _holeSize;
                        y       += _holeSize * 2;
                    }
                }
            }

            // Copy hole buffer to a texture.
            TerrainHelper.CreateHoleTexture(
                GraphicsService.GraphicsDevice,
                holes,
                numberOfSamples,
                numberOfSamples,
                false,
                ref _holeTexture);

            foreach (var tile in _terrainObject.TerrainNode.Terrain.Tiles)
            {
                // Assign the hole texture to all terrain tiles. (Normally, each tile would have a
                // different hole texture or no hole texture at all.)
                tile.HoleTexture = _holeTexture;

                // We also have to add the holes to the collision detection height fields.
                // Get rigid body that represents this tile.
                var rigidBody   = Simulation.RigidBodies.First(body => body.UserData == tile);
                var heightField = (HeightField)rigidBody.Shape;

                // Update the height values of the collision detection height field.
                float[] heights = TerrainHelper.GetTextureLevelSingle(tile.HeightTexture, 0);
                for (int z = 0; z < numberOfSamples; z++)
                {
                    for (int x = 0; x < numberOfSamples; x++)
                    {
                        if ((!(holes[z * numberOfSamples + x] > 0.5f)))
                        {
                            // The HeightField class treats NaN as holes.
                            heights[z * numberOfSamples + x] = float.NaN;
                        }
                    }
                }
                heightField.SetSamples(heights, numberOfSamples, numberOfSamples);
                heightField.Invalidate();
            }

            _terrainObject.TerrainNode.Terrain.Invalidate();
        }
示例#24
0
 public static int GetProminantTextureIndex(Vector3 worldPosition)
 {
     return(TerrainHelper.GetProminantTextureIndex(Terrain.activeTerrain, worldPosition));
 }
        public override void GenerateSamples(ref MapPixelData mapPixel)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            // Create samples arrays
            mapPixel.tilemapSamples   = new TilemapSample[MapsFile.WorldMapTileDim, MapsFile.WorldMapTileDim];
            mapPixel.heightmapSamples = new float[HeightmapDimension, HeightmapDimension];

            // Divisor ensures continuous 0-1 range of tile samples
            float div = (float)(HeightmapDimension - 1) / 3f;

            // Read neighbouring height samples for this map pixel
            int mx = mapPixel.mapPixelX;
            int my = mapPixel.mapPixelY;

            byte[,] shm = dfUnity.ContentReader.WoodsFileReader.GetHeightMapValuesRange(mx - 2, my - 2, 4);
            byte[,] lhm = dfUnity.ContentReader.WoodsFileReader.GetLargeHeightMapValuesRange(mx - 1, my, 3);

            float[,] multiplierValue = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));

                    multiplierValue[x, y] = ImprovedWorldTerrain.computeHeightMultiplier(mapPixelX, mapPixelY);
                }
            }

            // Extract height samples for all chunks
            float averageHeight = 0;
            float maxHeight = float.MinValue;
            float baseHeight, noiseHeight;
            float x1, x2, x3, x4;
            int   dim = HeightmapDimension;

            //mapPixel.heightmapSamples = new float[dim, dim];
            for (int y = 0; y < dim; y++)
            {
                for (int x = 0; x < dim; x++)
                {
                    float rx           = (float)x / div;
                    float ry           = (float)y / div;
                    int   ix           = Mathf.FloorToInt(rx);
                    int   iy           = Mathf.FloorToInt(ry);
                    float sfracx       = (float)x / (float)(dim - 1);
                    float sfracy       = (float)y / (float)(dim - 1);
                    float fracx        = (float)(x - ix * div) / div;
                    float fracy        = (float)(y - iy * div) / div;
                    float scaledHeight = 0;

                    // Bicubic sample small height map for base terrain elevation
                    x1            = TerrainHelper.CubicInterpolator(shm[0, 3] * multiplierValue[0, 3], shm[1, 3] * multiplierValue[1, 3], shm[2, 3] * multiplierValue[2, 3], shm[3, 3] * multiplierValue[3, 3], sfracx);
                    x2            = TerrainHelper.CubicInterpolator(shm[0, 2] * multiplierValue[0, 2], shm[1, 2] * multiplierValue[1, 2], shm[2, 2] * multiplierValue[2, 2], shm[3, 2] * multiplierValue[3, 2], sfracx);
                    x3            = TerrainHelper.CubicInterpolator(shm[0, 1] * multiplierValue[0, 1], shm[1, 1] * multiplierValue[1, 1], shm[2, 1] * multiplierValue[2, 1], shm[3, 1] * multiplierValue[3, 1], sfracx);
                    x4            = TerrainHelper.CubicInterpolator(shm[0, 0] * multiplierValue[0, 0], shm[1, 0] * multiplierValue[1, 0], shm[2, 0] * multiplierValue[2, 0], shm[3, 0] * multiplierValue[3, 0], sfracx);
                    baseHeight    = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy);
                    scaledHeight += baseHeight * baseHeightScale;

                    // Bicubic sample large height map for noise mask over terrain features
                    x1            = TerrainHelper.CubicInterpolator(lhm[ix, iy + 0], lhm[ix + 1, iy + 0], lhm[ix + 2, iy + 0], lhm[ix + 3, iy + 0], fracx);
                    x2            = TerrainHelper.CubicInterpolator(lhm[ix, iy + 1], lhm[ix + 1, iy + 1], lhm[ix + 2, iy + 1], lhm[ix + 3, iy + 1], fracx);
                    x3            = TerrainHelper.CubicInterpolator(lhm[ix, iy + 2], lhm[ix + 1, iy + 2], lhm[ix + 2, iy + 2], lhm[ix + 3, iy + 2], fracx);
                    x4            = TerrainHelper.CubicInterpolator(lhm[ix, iy + 3], lhm[ix + 1, iy + 3], lhm[ix + 2, iy + 3], lhm[ix + 3, iy + 3], fracx);
                    noiseHeight   = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, fracy);
                    scaledHeight += noiseHeight * noiseMapScale;

                    // Additional noise mask for small terrain features at ground level
                    int   noisex   = mapPixel.mapPixelX * (HeightmapDimension - 1) + x;
                    int   noisey   = (MapsFile.MaxMapPixelY - mapPixel.mapPixelY) * (HeightmapDimension - 1) + y;
                    float lowFreq  = TerrainHelper.GetNoise(noisex, noisey, 0.3f, 0.5f, 0.5f, 1);
                    float highFreq = TerrainHelper.GetNoise(noisex, noisey, 0.9f, 0.5f, 0.5f, 1);
                    scaledHeight += (lowFreq * highFreq) * extraNoiseScale;

                    // Clamp lower values to ocean elevation
                    if (scaledHeight < scaledOceanElevation)
                    {
                        scaledHeight = scaledOceanElevation;
                    }

                    // Accumulate average height
                    averageHeight += scaledHeight;

                    // Get max height
                    if (scaledHeight > maxHeight)
                    {
                        maxHeight = scaledHeight;
                    }

                    // Set sample
                    float height = Mathf.Clamp01(scaledHeight / MaxTerrainHeight);
                    mapPixel.heightmapSamples[y, x] = height;
                }
            }

            // Average and max heights are passed back for locations
            mapPixel.averageHeight = (averageHeight /= (float)(dim * dim)) / MaxTerrainHeight;
            mapPixel.maxHeight     = maxHeight / MaxTerrainHeight;
        }
        public override JobHandle ScheduleGenerateSamplesJob(ref MapPixelData mapPixel)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            // Divisor ensures continuous 0-1 range of tile samples
            float div = (float)(HeightmapDimension - 1) / 3f;

            // Read neighbouring height samples for this map pixel
            int mx = mapPixel.mapPixelX;
            int my = mapPixel.mapPixelY;

            // Seed random with terrain key
            UnityEngine.Random.InitState(TerrainHelper.MakeTerrainKey(mx, my));

            byte[,] shm = dfUnity.ContentReader.WoodsFileReader.GetHeightMapValuesRange(mx - 2, my - 2, 4);
            byte[,] lhm = dfUnity.ContentReader.WoodsFileReader.GetLargeHeightMapValuesRange(mx - 1, my, 3);

            float[,] baseHeightValue = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));

                    baseHeightValue[x, y] = shm[x, y] * ImprovedWorldTerrain.computeHeightMultiplier(mapPixelX, mapPixelY);
                }
            }

            float[,] waterMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    if (shm[x, y] <= 2) // mappixel is water
                    {
                        waterMap[x, y] = 0.0f;
                    }
                    else
                    {
                        waterMap[x, y] = 1.0f;
                    }
                }
            }

            float[,] climateMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));
                    climateMap[x, y] = GetNoiseMapScaleBasedOnClimate(mapPixelX, mapPixelY);
                }
            }

            float[,] waterDistanceMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));
                    waterDistanceMap[x, y] = (float)Math.Sqrt(ImprovedWorldTerrain.MapDistanceSquaredFromWater[mapPixelY * WoodsFile.mapWidthValue + mapPixelX]);
                }
            }

            float[,] noiseHeightMultiplierMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    // interpolation multiplier taking near coast map pixels into account
                    // (multiply with 0 at coast line and 1 at interpolationEndDistanceFromWaterForNoiseScaleMultiplier)
                    float multFact = (Mathf.Min(interpolationEndDistanceFromWaterForNoiseScaleMultiplier, waterDistanceMap[x, y]) / interpolationEndDistanceFromWaterForNoiseScaleMultiplier);

                    // blend watermap with climatemap taking into account multFact
                    noiseHeightMultiplierMap[x, y] = waterMap[x, y] * climateMap[x, y] * multFact;
                }
            }

            float extraNoiseScaleBasedOnClimate = GetExtraNoiseScaleBasedOnClimate(mx, my);

            byte sDim = 4;
            NativeArray <float> baseHeightValueNativeArray = new NativeArray <float>(shm.Length, Allocator.TempJob);
            int i = 0;

            for (int y = 0; y < sDim; y++)
            {
                for (int x = 0; x < sDim; x++)
                {
                    baseHeightValueNativeArray[i++] = baseHeightValue[x, y];
                }
            }

            i = 0;
            NativeArray <float> noiseHeightMultiplierNativeArray = new NativeArray <float>(noiseHeightMultiplierMap.Length, Allocator.TempJob);

            for (int y = 0; y < sDim; y++)
            {
                for (int x = 0; x < sDim; x++)
                {
                    noiseHeightMultiplierNativeArray[i++] = noiseHeightMultiplierMap[x, y];
                }
            }

            // TODO - shortcut conversion & flattening.
            NativeArray <byte> lhmNativeArray = new NativeArray <byte>(lhm.Length, Allocator.TempJob);
            byte lDim = (byte)lhm.GetLength(0);

            i = 0;
            for (int y = 0; y < lDim; y++)
            {
                for (int x = 0; x < lDim; x++)
                {
                    lhmNativeArray[i++] = lhm[x, y];
                }
            }

            // Add the working native arrays to list for later disposal.
            mapPixel.nativeArrayList.Add(baseHeightValueNativeArray);
            mapPixel.nativeArrayList.Add(noiseHeightMultiplierNativeArray);
            mapPixel.nativeArrayList.Add(lhmNativeArray);

            // Extract height samples for all chunks
            int hDim = HeightmapDimension;
            GenerateSamplesJob generateSamplesJob = new GenerateSamplesJob
            {
                baseHeightValue          = baseHeightValueNativeArray,
                lhm                      = lhmNativeArray,
                noiseHeightMultiplierMap = noiseHeightMultiplierNativeArray,
                heightmapData            = mapPixel.heightmapData,
                sd               = sDim,
                ld               = lDim,
                hDim             = hDim,
                div              = div,
                mapPixelX        = mapPixel.mapPixelX,
                mapPixelY        = mapPixel.mapPixelY,
                maxTerrainHeight = MaxTerrainHeight,
                extraNoiseScaleBasedOnClimate = extraNoiseScaleBasedOnClimate,
            };

            JobHandle generateSamplesHandle = generateSamplesJob.Schedule(hDim * hDim, 64);     // Batch = 1 breaks it since shm not copied... test again later

            return(generateSamplesHandle);
        }
            public void Execute(int index)
            {
                // Use cols=x and rows=y for height data
                int x = JobA.Col(index, hDim);
                int y = JobA.Row(index, hDim);

                float rx           = (float)x / div;
                float ry           = (float)y / div;
                int   ix           = Mathf.FloorToInt(rx);
                int   iy           = Mathf.FloorToInt(ry);
                float sfracx       = (float)x / (float)(hDim - 1);
                float sfracy       = (float)y / (float)(hDim - 1);
                float fracx        = (float)(x - ix * div) / div;
                float fracy        = (float)(y - iy * div) / div;
                float scaledHeight = 0;

                // Bicubic sample small height map for base terrain elevation
                x1            = TerrainHelper.CubicInterpolator(baseHeightValue[JobA.Idx(0, 3, sd)], baseHeightValue[JobA.Idx(1, 3, sd)], baseHeightValue[JobA.Idx(2, 3, sd)], baseHeightValue[JobA.Idx(3, 3, sd)], sfracx);
                x2            = TerrainHelper.CubicInterpolator(baseHeightValue[JobA.Idx(0, 2, sd)], baseHeightValue[JobA.Idx(1, 2, sd)], baseHeightValue[JobA.Idx(2, 2, sd)], baseHeightValue[JobA.Idx(3, 2, sd)], sfracx);
                x3            = TerrainHelper.CubicInterpolator(baseHeightValue[JobA.Idx(0, 1, sd)], baseHeightValue[JobA.Idx(1, 1, sd)], baseHeightValue[JobA.Idx(2, 1, sd)], baseHeightValue[JobA.Idx(3, 1, sd)], sfracx);
                x4            = TerrainHelper.CubicInterpolator(baseHeightValue[JobA.Idx(0, 0, sd)], baseHeightValue[JobA.Idx(1, 0, sd)], baseHeightValue[JobA.Idx(2, 0, sd)], baseHeightValue[JobA.Idx(3, 0, sd)], sfracx);
                baseHeight    = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy);
                scaledHeight += baseHeight * baseHeightScale;

                // Bicubic sample large height map for noise mask over terrain features
                x1          = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 0, ld)], lhm[JobA.Idx(ix + 1, iy + 0, ld)], lhm[JobA.Idx(ix + 2, iy + 0, ld)], lhm[JobA.Idx(ix + 3, iy + 0, ld)], fracx);
                x2          = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 1, ld)], lhm[JobA.Idx(ix + 1, iy + 1, ld)], lhm[JobA.Idx(ix + 2, iy + 1, ld)], lhm[JobA.Idx(ix + 3, iy + 1, ld)], fracx);
                x3          = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 2, ld)], lhm[JobA.Idx(ix + 1, iy + 2, ld)], lhm[JobA.Idx(ix + 2, iy + 2, ld)], lhm[JobA.Idx(ix + 3, iy + 2, ld)], fracx);
                x4          = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 3, ld)], lhm[JobA.Idx(ix + 1, iy + 3, ld)], lhm[JobA.Idx(ix + 2, iy + 3, ld)], lhm[JobA.Idx(ix + 3, iy + 3, ld)], fracx);
                noiseHeight = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, fracy);

                x1 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[JobA.Idx(0, 3, sd)], noiseHeightMultiplierMap[JobA.Idx(1, 3, sd)], noiseHeightMultiplierMap[JobA.Idx(2, 3, sd)], noiseHeightMultiplierMap[JobA.Idx(3, 3, sd)], sfracx);
                x2 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[JobA.Idx(0, 2, sd)], noiseHeightMultiplierMap[JobA.Idx(1, 2, sd)], noiseHeightMultiplierMap[JobA.Idx(2, 2, sd)], noiseHeightMultiplierMap[JobA.Idx(3, 2, sd)], sfracx);
                x3 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[JobA.Idx(0, 1, sd)], noiseHeightMultiplierMap[JobA.Idx(1, 1, sd)], noiseHeightMultiplierMap[JobA.Idx(2, 1, sd)], noiseHeightMultiplierMap[JobA.Idx(3, 1, sd)], sfracx);
                x4 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[JobA.Idx(0, 0, sd)], noiseHeightMultiplierMap[JobA.Idx(1, 0, sd)], noiseHeightMultiplierMap[JobA.Idx(2, 0, sd)], noiseHeightMultiplierMap[JobA.Idx(3, 0, sd)], sfracx);
                float noiseHeightMultiplier = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy);

                scaledHeight += noiseHeight * noiseHeightMultiplier;

                // Additional noise mask for small terrain features at ground level
                // small terrain features' height scale should depend on climate of map pixel
                float extraNoiseScale = extraNoiseScaleBasedOnClimate;

                // prevent seams between different climate map pixels
                if (x <= 0 || y <= 0 || x >= hDim - 1 || y >= hDim - 1)
                {
                    extraNoiseScale = defaultExtraNoiseScale;
                }
                int   noisex   = mapPixelX * (hDim - 1) + x;
                int   noisey   = (MapsFile.MaxMapPixelY - mapPixelY) * (hDim - 1) + y;
                float lowFreq  = TerrainHelper.GetNoise(noisex, noisey, 0.3f, 0.5f, 0.5f, 1);
                float highFreq = TerrainHelper.GetNoise(noisex, noisey, 0.9f, 0.5f, 0.5f, 1);

                scaledHeight += (lowFreq * highFreq) * extraNoiseScale;

                // Clamp lower values to ocean elevation
                if (scaledHeight < scaledOceanElevation)
                {
                    scaledHeight = scaledOceanElevation;
                }

                // Set sample
                float height = Mathf.Clamp01(scaledHeight / maxTerrainHeight);

                heightmapData[index] = height;
            }
        public override void GenerateSamples(ref MapPixelData mapPixel)
        {
            //System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
            //long startTime = stopwatch.ElapsedMilliseconds;

            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            // Create samples arrays
            mapPixel.heightmapSamples = new float[HeightmapDimension, HeightmapDimension];

            // Divisor ensures continuous 0-1 range of tile samples
            float div = (float)(HeightmapDimension - 1) / 3f;

            // Read neighbouring height samples for this map pixel
            int mx = mapPixel.mapPixelX;
            int my = mapPixel.mapPixelY;

            // Seed random with terrain key
            UnityEngine.Random.InitState(TerrainHelper.MakeTerrainKey(mx, my));

            byte[,] shm = dfUnity.ContentReader.WoodsFileReader.GetHeightMapValuesRange(mx - 2, my - 2, 4);
            byte[,] lhm = dfUnity.ContentReader.WoodsFileReader.GetLargeHeightMapValuesRange(mx - 1, my, 3);

            float[,] baseHeightValue = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));

                    baseHeightValue[x, y] = shm[x, y] * ImprovedWorldTerrain.computeHeightMultiplier(mapPixelX, mapPixelY);
                }
            }

            float[,] waterMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    if (shm[x, y] <= 2) // mappixel is water
                    {
                        waterMap[x, y] = 0.0f;
                    }
                    else
                    {
                        waterMap[x, y] = 1.0f;
                    }
                }
            }

            float[,] climateMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));
                    climateMap[x, y] = GetNoiseMapScaleBasedOnClimate(mapPixelX, mapPixelY);
                }
            }

            float[,] waterDistanceMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));
                    waterDistanceMap[x, y] = (float)Math.Sqrt(ImprovedWorldTerrain.MapDistanceSquaredFromWater[mapPixelY * WoodsFile.mapWidthValue + mapPixelX]);
                }
            }

            float[,] noiseHeightMultiplierMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    // interpolation multiplier taking near coast map pixels into account
                    // (multiply with 0 at coast line and 1 at interpolationEndDistanceFromWaterForNoiseScaleMultiplier)
                    float multFact = (Mathf.Min(interpolationEndDistanceFromWaterForNoiseScaleMultiplier, waterDistanceMap[x, y]) / interpolationEndDistanceFromWaterForNoiseScaleMultiplier);

                    // blend watermap with climatemap taking into account multFact
                    noiseHeightMultiplierMap[x, y] = waterMap[x, y] * climateMap[x, y] * multFact;
                }
            }

            //float[,] noiseHeightMultiplierMap = new float[4, 4];
            //for (int y = 0; y < 4; y++)
            //{
            //    for (int x = 0; x < 4; x++)
            //    {
            //        int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
            //        int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));

            //        float climateValue = GetNoiseMapScaleBasedOnClimate(mapPixelX, mapPixelY);

            //        float waterDistance = (float)Math.Sqrt(ImprovedWorldTerrain.MapDistanceSquaredFromWater[mapPixelY * WoodsFile.mapWidthValue + mapPixelX]);

            //        float waterValue;
            //        if (shm[x, y] <= 2) // mappixel is water
            //            waterValue = 0.0f;
            //        else
            //            waterValue = 1.0f;

            //        // interpolation multiplier taking near coast map pixels into account
            //        // (multiply with 0 at coast line and 1 at interpolationEndDistanceFromWaterForNoiseScaleMultiplier)
            //        float multFact = (Mathf.Min(interpolationEndDistanceFromWaterForNoiseScaleMultiplier, waterDistance) / interpolationEndDistanceFromWaterForNoiseScaleMultiplier);

            //        // blend watermap with climatemap taking into account multFact
            //        noiseHeightMultiplierMap[x, y] = waterValue * climateValue * multFact;
            //    }
            //}

            //int numWorkerThreads = 0, completionPortThreads = 0;
            //int numMinWorkerThreads = 0, numMaxWorkerThreads = 0;
            //ThreadPool.GetAvailableThreads(out numWorkerThreads, out completionPortThreads);
            //ThreadPool.GetMinThreads(out numMinWorkerThreads, out completionPortThreads);
            //ThreadPool.GetMaxThreads(out numMaxWorkerThreads, out completionPortThreads);
            //Debug.Log(String.Format("available threads: {0}, numMinWorkerThreads: {1}, numMaxWorkerThreads: {2}", numWorkerThreads, numMinWorkerThreads, numMaxWorkerThreads));

            float extraNoiseScaleBasedOnClimate = GetExtraNoiseScaleBasedOnClimate(mx, my);

            // the number of parallel tasks (use logical processor count for now - seems to be a good value)
            int numParallelTasks = Environment.ProcessorCount;

            // events used to synchronize thread computations (wait for them to finish)
            var doneEvents = new ManualResetEvent[numParallelTasks];

            // the array of instances of the height computations helper class
            var heightsComputationTaskArray = new HeightsComputationTask[numParallelTasks];

            // array of the data needed by the different tasks
            var dataForTasks = new HeightsComputationTask.DataForTask[numParallelTasks];

            for (int i = 0; i < numParallelTasks; i++)
            {
                doneEvents[i] = new ManualResetEvent(false);
                var heightsComputationTask = new HeightsComputationTask(doneEvents[i]);
                heightsComputationTaskArray[i] = heightsComputationTask;
                dataForTasks[i]                               = new HeightsComputationTask.DataForTask();
                dataForTasks[i].numTasks                      = numParallelTasks;
                dataForTasks[i].currentTask                   = i;
                dataForTasks[i].HeightmapDimension            = HeightmapDimension;
                dataForTasks[i].MaxTerrainHeight              = MaxTerrainHeight;
                dataForTasks[i].div                           = div;
                dataForTasks[i].baseHeightValue               = baseHeightValue;
                dataForTasks[i].lhm                           = lhm;
                dataForTasks[i].noiseHeightMultiplierMap      = noiseHeightMultiplierMap;
                dataForTasks[i].extraNoiseScaleBasedOnClimate = extraNoiseScaleBasedOnClimate;
                dataForTasks[i].mapPixel                      = mapPixel;
                ThreadPool.QueueUserWorkItem(heightsComputationTask.ThreadProc, dataForTasks[i]);
            }

            // wait for all tasks to finish computation
            WaitHandle.WaitAll(doneEvents);

            // computed average and max height in a second pass (after threaded tasks computed all heights)
            float averageHeight = 0;
            float maxHeight     = float.MinValue;

            int dim = HeightmapDimension;

            for (int y = 0; y < dim; y++)
            {
                for (int x = 0; x < dim; x++)
                {
                    // get sample
                    float height = mapPixel.heightmapSamples[y, x];

                    // Accumulate average height
                    averageHeight += height;

                    // Get max height
                    if (height > maxHeight)
                    {
                        maxHeight = height;
                    }
                }
            }

            // Average and max heights are passed back for locations
            mapPixel.averageHeight = (averageHeight /= (float)(dim * dim));
            mapPixel.maxHeight     = maxHeight;

            //long totalTime = stopwatch.ElapsedMilliseconds - startTime;
            //DaggerfallUnity.LogMessage(string.Format("GenerateSamples took: {0}ms", totalTime), true);
        }
            public void ThreadProc(System.Object stateInfo)
            {
                DataForTask dataForTask = stateInfo as DataForTask;

                // Extract height samples for all chunks
                float baseHeight, noiseHeight;
                float x1, x2, x3, x4;

                int   dim = dataForTask.HeightmapDimension;
                float div = dataForTask.div;

                float[,] baseHeightValue = dataForTask.baseHeightValue;
                byte[,] lhm = dataForTask.lhm;
                float[,] noiseHeightMultiplierMap = dataForTask.noiseHeightMultiplierMap;
                float extraNoiseScaleBasedOnClimate = dataForTask.extraNoiseScaleBasedOnClimate;

                // split the work between different tasks running in different threads (thread n computes data elements n, n + numTasks, n + numTasks*2, ...)
                for (int y = dataForTask.currentTask; y < dim; y += dataForTask.numTasks)
                {
                    for (int x = 0; x < dim; x++)
                    {
                        float rx           = (float)x / div;
                        float ry           = (float)y / div;
                        int   ix           = Mathf.FloorToInt(rx);
                        int   iy           = Mathf.FloorToInt(ry);
                        float sfracx       = (float)x / (float)(dim - 1);
                        float sfracy       = (float)y / (float)(dim - 1);
                        float fracx        = (float)(x - ix * div) / div;
                        float fracy        = (float)(y - iy * div) / div;
                        float scaledHeight = 0;

                        // Bicubic sample small height map for base terrain elevation
                        x1            = TerrainHelper.CubicInterpolator(baseHeightValue[0, 3], baseHeightValue[1, 3], baseHeightValue[2, 3], baseHeightValue[3, 3], sfracx);
                        x2            = TerrainHelper.CubicInterpolator(baseHeightValue[0, 2], baseHeightValue[1, 2], baseHeightValue[2, 2], baseHeightValue[3, 2], sfracx);
                        x3            = TerrainHelper.CubicInterpolator(baseHeightValue[0, 1], baseHeightValue[1, 1], baseHeightValue[2, 1], baseHeightValue[3, 1], sfracx);
                        x4            = TerrainHelper.CubicInterpolator(baseHeightValue[0, 0], baseHeightValue[1, 0], baseHeightValue[2, 0], baseHeightValue[3, 0], sfracx);
                        baseHeight    = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy);
                        scaledHeight += baseHeight * baseHeightScale;

                        // Bicubic sample large height map for noise mask over terrain features
                        x1          = TerrainHelper.CubicInterpolator(lhm[ix, iy + 0], lhm[ix + 1, iy + 0], lhm[ix + 2, iy + 0], lhm[ix + 3, iy + 0], fracx);
                        x2          = TerrainHelper.CubicInterpolator(lhm[ix, iy + 1], lhm[ix + 1, iy + 1], lhm[ix + 2, iy + 1], lhm[ix + 3, iy + 1], fracx);
                        x3          = TerrainHelper.CubicInterpolator(lhm[ix, iy + 2], lhm[ix + 1, iy + 2], lhm[ix + 2, iy + 2], lhm[ix + 3, iy + 2], fracx);
                        x4          = TerrainHelper.CubicInterpolator(lhm[ix, iy + 3], lhm[ix + 1, iy + 3], lhm[ix + 2, iy + 3], lhm[ix + 3, iy + 3], fracx);
                        noiseHeight = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, fracy);

                        x1 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[0, 3], noiseHeightMultiplierMap[1, 3], noiseHeightMultiplierMap[2, 3], noiseHeightMultiplierMap[3, 3], sfracx);
                        x2 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[0, 2], noiseHeightMultiplierMap[1, 2], noiseHeightMultiplierMap[2, 2], noiseHeightMultiplierMap[3, 2], sfracx);
                        x3 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[0, 1], noiseHeightMultiplierMap[1, 1], noiseHeightMultiplierMap[2, 1], noiseHeightMultiplierMap[3, 1], sfracx);
                        x4 = TerrainHelper.CubicInterpolator(noiseHeightMultiplierMap[0, 0], noiseHeightMultiplierMap[1, 0], noiseHeightMultiplierMap[2, 0], noiseHeightMultiplierMap[3, 0], sfracx);
                        float noiseHeightMultiplier = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy);

                        scaledHeight += noiseHeight * noiseHeightMultiplier;

                        // Additional noise mask for small terrain features at ground level
                        // small terrain features' height scale should depend on climate of map pixel
                        float extraNoiseScale = extraNoiseScaleBasedOnClimate;
                        // prevent seams between different climate map pixels
                        if (x <= 0 || y <= 0 || x >= dim - 1 || y >= dim - 1)
                        {
                            extraNoiseScale = defaultExtraNoiseScale;
                        }
                        int   noisex   = dataForTask.mapPixel.mapPixelX * (dataForTask.HeightmapDimension - 1) + x;
                        int   noisey   = (MapsFile.MaxMapPixelY - dataForTask.mapPixel.mapPixelY) * (dataForTask.HeightmapDimension - 1) + y;
                        float lowFreq  = TerrainHelper.GetNoise(noisex, noisey, 0.3f, 0.5f, 0.5f, 1);
                        float highFreq = TerrainHelper.GetNoise(noisex, noisey, 0.9f, 0.5f, 0.5f, 1);
                        scaledHeight += (lowFreq * highFreq) * extraNoiseScale;

                        // Clamp lower values to ocean elevation
                        if (scaledHeight < scaledOceanElevation)
                        {
                            scaledHeight = scaledOceanElevation;
                        }

                        // Set sample
                        float height = Mathf.Clamp01(scaledHeight / dataForTask.MaxTerrainHeight);
                        dataForTask.mapPixel.heightmapSamples[y, x] = height;
                    }
                }

                _doneEvent.Set();
            }
示例#30
0
    // Initialize the terrain geometry from height textures.
    public void InitializeHeightsAndNormals()
    {
      var content = _services.GetInstance<ContentManager>();

      // Create the height and normal texture for the 4 tiles.
      // We can do this in parallel. We use following lock for parts which are not thread-safe.
      var lockObject = new object();

      Parallel.For(0, 2, row =>
      //for (int row = 0; row < 2; row++)
      {
        Parallel.For(0, 2, column =>
        //for (int column = 0; column < 2; column++)
        {
          string tilePostfix = "-" + row + "-" + column; // e.g. "-0-1"
          var tile = _tiles[row, column];
          var terrainTile = tile.TerrainTile;

          // The height data is loaded from a 16-bit grayscale texture.
          Texture2D inputHeightTexture;
          lock (lockObject)
             inputHeightTexture = content.Load<Texture2D>("Terrain/Terrain001-Height" + tilePostfix);

          Debug.Assert(inputHeightTexture.Width == inputHeightTexture.Height, "This code assumes that terrain tiles are square.");

          // The height textures of the tiles overlap by one texel to avoid gaps. That means, the
          // input height texture for each tile is 1025 x 1025. The last texture column of the top
          // left tile is the same as the first column of the top right tile. The last row of the
          // top left tile is the same as the first row of the bottom left tile.
          // The tile size in world space units is:
          float tileSize = (inputHeightTexture.Width - 1) * terrainTile.CellSize;

          terrainTile.OriginX = -tileSize + tileSize * column;
          terrainTile.OriginZ = -tileSize + tileSize * row;

          Debug.Assert(Numeric.IsZero(terrainTile.OriginX % terrainTile.CellSize), "The tile origin must be an integer multiple of the cell size.");
          Debug.Assert(Numeric.IsZero(terrainTile.OriginZ % terrainTile.CellSize), "The tile origin must be an integer multiple of the cell size.");

          // Extract the height values from the texture.
          float[] heights = TerrainHelper.GetTextureLevelSingle(inputHeightTexture, 0);

          // Transform height values from [0, 1] to [_minHeight, _maxheight].
          TerrainHelper.TransformTexture(heights, (_maxHeight - _minHeight), _minHeight);

          // Optional: Smooth the processed height map. (Very useful to remove artifacts from 8-bit
          // height maps.)
          TerrainHelper.SmoothTexture(heights, inputHeightTexture.Width, inputHeightTexture.Height, _smoothness);

          // We have to create a height and normal texture for each tile.
          // Reuse existing textures to avoid unnecessary allocation. (XNA can run out of memory
          // if we allocate to many textures in a short time.)
          Texture2D heightTexture = terrainTile.HeightTexture;
          Texture2D normalTexture = terrainTile.NormalTexture;

          // Convert the height value array into a suitable height texture.
          TerrainHelper.CreateHeightTexture(
            _graphicsService.GraphicsDevice,
            heights,
            inputHeightTexture.Width,
            inputHeightTexture.Height,
            _useNearestNeighborMipmaps,
            ref heightTexture);

          // Create a normal texture from the height values.
          TerrainHelper.CreateNormalTexture(
            _graphicsService.GraphicsDevice,
            heights,
            inputHeightTexture.Width,
            inputHeightTexture.Height,
            terrainTile.CellSize,
            _useNearestNeighborMipmaps,
            ref normalTexture);

          // If terrainTile.HeightTexture/NormalTexture was null, then CreateHeight/CreateNormal
          // has created a new texture. We have to dispose this textures in Dispose().
          terrainTile.HeightTexture = heightTexture;
          terrainTile.NormalTexture = normalTexture;

          // Set the height field data for collision detection.
          var heightField = (HeightField)tile.RigidBody.Shape;
          heightField.OriginX = terrainTile.OriginX;
          heightField.OriginZ = terrainTile.OriginZ;
          heightField.WidthX = tileSize;
          heightField.WidthZ = tileSize;
          lock (lockObject)
          {
            heightField.SetSamples(heights, heightTexture.Width, heightTexture.Height);
            heightField.Invalidate();
          }
        });
      });

      // Inform the terrain that the old texture content is invalid.
      TerrainNode.Terrain.Invalidate();
    }