コード例 #1
0
        public TerrainData(TiledTerrainConfig config, BinaryReader reader)
        {
            Config = config;
            Reader = reader;

            Heights = new float[Config.PatchHeightRes, Config.PatchHeightRes];
            Normals = new Vector3[Config.PatchHeightRes, Config.PatchHeightRes];
            Splats  = new Vector2[Config.PatchSplatRes, Config.PatchSplatRes];
        }
コード例 #2
0
    private void Initialize()
    {
        if (_tilesList != null)
        {
            return;
        }

        _config = new TiledTerrainConfig(
            _lod0NumTiles,
            _lod0TileSize,
            _lod0PatchSize,
            _lod0HeightResolution,
            _lod0SplatResolution,
            _terrainHeight);

        _trees = new List <TreeLODHelper>(10000);
        _treeQualitySettings = new Dictionary <int, TreeLODConfiguration>()
        {
            { 0, new TreeLODConfiguration(false, 1.0f, 0.75f, 0.5f, 0.02f) },
            { 1, new TreeLODConfiguration(false, 0.75f, 0.5f, 0.33f, 0.01f) },
            { 2, new TreeLODConfiguration(false, 0.5f, 0.25f, 0.12f, 0.005f) },
            { 3, new TreeLODConfiguration(true, 0.33f, 0.15f, 0.05f, 0.0025f) }
        };

        _tiles     = LandmasImporter.FindTerrainTilesInScene();
        _tilesList = new List <TerrainTile>(128);

        foreach (var lodGroup in _tiles)
        {
            foreach (var regionTile in lodGroup.Value)
            {
                _tilesList.Add(regionTile.Value);

                LandmasImporter.SetNeighbours(regionTile.Key, lodGroup.Value);

                if (Application.isPlaying && _generateTreeColliders)
                {
                    CreateTrees(regionTile.Value);
                    CreateTreeColliders(regionTile.Value);
                }
            }
        }

        _lod0Grid = new TerrainTile[8, 8];
        for (int x = 0; x < 8; x++)
        {
            for (int z = 0; z < 8; z++)
            {
                _lod0Grid[x, z] = _tiles[0][new IntVector3(x, 0, z)];
            }
        }
    }
コード例 #3
0
    public static void ExportTerrain()
    {
        var cfg          = new TiledTerrainConfig(8, 1024, 32, 513, 512, 4000f); // Todo: get from global instead of hardcoding
        int totalPatches = cfg.NumTiles * cfg.PatchesPerTile;

        var lodTiles = LandmasImporter.FindTerrainTilesInScene();

        var path = UPath.GetAbsolutePath("Assets/Terrains/SwissAlps/swissalps.land");

        Debug.Log("Exporting terrain to: " + path);

        using (var writer = new BinaryWriter(File.Open(path, FileMode.Create))) {
            try {
                for (int x = 0; x < totalPatches; x++)
                {
                    for (int z = 0; z < totalPatches; z++)
                    {
                        // Find tile this patch is from
                        var tileIndex = new IntVector3(x / cfg.PatchesPerTile, 0, z / cfg.PatchesPerTile);
                        var tile      = lodTiles[0][tileIndex];

                        // Find out which pixels we need to read for this patch
                        var startPatchIndex = new IntVector2(tileIndex.X * cfg.PatchesPerTile, tileIndex.Z * cfg.PatchesPerTile);
                        var localPatchIndex = new IntVector2(x, z) - startPatchIndex;
                        var heightPixIndex  = new IntVector2(localPatchIndex.X * (cfg.PatchHeightRes - 1), localPatchIndex.Y * (cfg.PatchHeightRes - 1));
                        var splatPixIndex   = new IntVector2(localPatchIndex.X * cfg.PatchSplatRes, localPatchIndex.Y * cfg.PatchSplatRes);

                        // Sample PoT+1 blocks, so that each patch's edge overlaps the first edge of its neighbour
                        float[,] heights   = GetHeights(tile.Terrain.terrainData, heightPixIndex, cfg.PatchHeightRes);
                        Vector3[,] normals = GetNormals(tile.Terrain.terrainData, heightPixIndex, cfg.PatchHeightRes);
                        float[,,] splats   = GetSplats(tile.Terrain.terrainData, splatPixIndex, cfg.PatchSplatRes);

                        // Write heights
                        for (int xPixel = 0; xPixel < cfg.PatchHeightRes; xPixel++)
                        {
                            for (int zPixel = 0; zPixel < cfg.PatchHeightRes; zPixel++)
                            {
                                ushort val = (ushort)(heights[xPixel, zPixel] * 65000f);
                                writer.Write(val);
                            }
                        }

                        // Write normals
                        // Todo: calculate normals from loaded height values instead of caching them on disk
                        // Todo: single byte per axis, implicit 3rd axis

                        for (int xPixel = 0; xPixel < cfg.PatchHeightRes; xPixel++)
                        {
                            for (int zPixel = 0; zPixel < cfg.PatchHeightRes; zPixel++)
                            {
                                Vector3 normal = normals[xPixel, zPixel];
                                byte    valX   = (byte)((normal.x * 0.5f + 0.5f) * 250f);
                                byte    valY   = (byte)((normal.y * 0.5f + 0.5f) * 250f);
                                byte    valZ   = (byte)((normal.z * 0.5f + 0.5f) * 250f);
                                writer.Write(valX);
                                writer.Write(valY);
                                writer.Write(valZ);
                            }
                        }

                        // Write splats (todo: byte)
                        for (int xPixel = 0; xPixel < cfg.PatchSplatRes; xPixel++)
                        {
                            for (int zPixel = 0; zPixel < cfg.PatchSplatRes; zPixel++)
                            {
                                // Swizzled writes because Unity's terrain data is store wrong
                                byte valR = (byte)(splats[zPixel, xPixel, 0] * 250f); // Grass
                                byte valA = (byte)(splats[zPixel, xPixel, 3] * 250f); // Snow
                                writer.Write(valR);
                                writer.Write(valA);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                Debug.LogException(e);
            }

            writer.Close();
        }
    }