Пример #1
0
        public static Vector3 MercatCoordsToWorld(double mx, float y, double mz, TerrainContainerObject container)
        {
            var sx = (mx - container.TLPointMercator.x) / (container.DRPointMercator.x - container.TLPointMercator.x) * container.size.x;
            var sz = (1 - (mz - container.TLPointMercator.y) / (container.DRPointMercator.y - container.TLPointMercator.y)) * container.size.z;

            return(new Vector3((float)sx, y * container.scale.y, (float)sz));
        }
        private TerrainObject CreateTerrain(TerrainContainerObject parent, int x, int y, Vector3 size, Vector3 scale)
        {
            TerrainData tdata = new TerrainData
            {
                baseMapResolution   = 32,
                heightmapResolution = 32
            };

            tdata.heightmapResolution = heightmapResolution;
            tdata.baseMapResolution   = baseMapResolution;
            tdata.SetDetailResolution(detailResolution, resolutionPerPatch);
            tdata.size = size;

            GameObject GO = Terrain.CreateTerrainGameObject(tdata);

            GO.gameObject.SetActive(true);
            GO.name               = string.Format("{0}-{1}", x, y);
            GO.transform.parent   = parent.gameObject.transform;
            GO.transform.position = new Vector3(size.x * x, 0, size.z * y);
            GO.isStatic           = false;
            TerrainObject item = GO.AddComponent <TerrainObject>();

            item.Number            = new Vector2Int(x, y);
            item.size              = size;
            item.ElevationFilePath = TerrainFilePath;

            string filename = Path.Combine(parent.GeneratedTerrainfolder, GO.name) + ".asset";

            AssetDatabase.CreateAsset(tdata, filename);

            AssetDatabase.SaveAssets();

            return(item);
        }
        private static void AddTreesToTerrains(TerrainContainerObject container, List <GameObject> m_treesPrefabs)
        {
            TreePrototype[] prototypes = new TreePrototype[m_treesPrefabs.Count];

            for (int i = 0; i < prototypes.Length; i++)
            {
                if (m_treesPrefabs[i] != null)
                {
                    prototypes[i] = new TreePrototype
                    {
                        prefab = m_treesPrefabs[i]
                    };
                }
            }

            foreach (var item in container.terrains)
            {
                item.terrainData.treePrototypes = prototypes;
                item.terrainData.treeInstances  = new TreeInstance[0];
            }
        }
Пример #4
0
        /// <summary>
        /// Generate HeightMaps by spliting Single terrain elevation file to tiles
        /// </summary>
        /// <param name="prefs"></param>
        /// <param name="item"></param>
        public void GenerateHeightMap(TerrainContainerObject container, TerrainObject item)
        {
            tdata = item.terrain.terrainData;
            if (tdataHeightmap == null)
            {
                tdataHeightmap = new float[tdata.heightmapHeight, tdata.heightmapWidth];
            }

            //if (tdata == null)
            //{

            //    tdata.baseMapResolution = prefs.baseMapResolution;
            //    tdata.SetDetailResolution(prefs.detailResolution, prefs.resolutionPerPatch);
            //    tdata.heightmapResolution = prefs.heightmapResolution;
            //    tdata.size = item.size;

            //    if (tdataHeightmap == null)
            //        tdataHeightmap = new float[tdata.heightmapHeight, tdata.heightmapWidth];
            //}

            float elevationRange = MaxElevation - MinElevation;

            long startTime = DateTime.Now.Ticks;

            float thx = tdata.heightmapWidth - 1;
            float thy = tdata.heightmapHeight - 1;


            var y_Terrain_Col_num = (mapSize_row_y / container.terrainCount.x);
            var x_Terrain_row_num = (mapSize_col_x / container.terrainCount.y);

            // heightmap rotation
            int tw = tdata.heightmapWidth;
            int th = tdata.heightmapHeight;

            for (int x = lastX; x < tw; x++)
            {
                for (int y = 0; y < th; y++)
                {
                    var x_from = item.Number.x * x_Terrain_row_num;
                    var x_To   = item.Number.x * x_Terrain_row_num + x_Terrain_row_num - 1;

                    var y_from = item.Number.y * y_Terrain_Col_num;
                    var y_To   = item.Number.y * y_Terrain_Col_num + y_Terrain_Col_num - 1;

                    float px = Mathf.Lerp(x_from, x_To, x / thx);
                    float py = Mathf.Lerp(y_from, y_To, y / thy);

                    var el = _floatheightData[(int)((px)), (int)(py)];

                    tdataHeightmap[y, x] = (el - MinElevation) / elevationRange;
                }
                lastX = x;
                //progress = hx / (float)tdata.heightmapWidth;
                if (new TimeSpan(DateTime.Now.Ticks - startTime).TotalSeconds > 1)
                {
                    return;
                }
            }

            lastX = 0;
            tdata.SetHeights(0, 0, tdataHeightmap);

            tdata            = null;
            generateComplete = true;
        }
        private static void GenerateTerrainsTrees(float TreeScaleFactor, float TreeRandomScaleFactor, TerrainContainerObject container, float treeDensity, int factorX, int factorY, Rect rect, List <Vector3> points)
        {
            Bounds bounds = container.GlobalTerrainBounds;

            Vector3 Bmin = bounds.min;
            Vector3 Bmax = bounds.max;

            float TreeValue = 400f / treeDensity;

            float rectx = (rect.xMax - rect.xMin) / factorX;
            float recty = (rect.yMax - rect.yMin) / factorY;

            int counter = 0;

            Vector3[] ps = points.ToArray();

            int Max_S_x = Mathf.Max(Mathf.FloorToInt((Bmin.x - rect.xMin) / rectx + 1), 0);
            int Min_E_x = Mathf.Min(Mathf.FloorToInt((Bmax.x - rect.xMin) / rectx), factorX);

            int Max_S_y = Mathf.Max(Mathf.FloorToInt((Bmin.z - rect.yMin) / recty + 1), 0);
            int Min_E_y = Mathf.Min(Mathf.FloorToInt((Bmax.z - rect.yMin) / recty), factorY);

            for (int x = Max_S_x; x < Min_E_x; x++)
            {
                float rx = x * rectx + rect.xMin;

                for (int y = Max_S_y; y < Min_E_y; y++)
                {
                    float ry = y * recty + rect.yMin;

                    float px = rx + UnityEngine.Random.Range(-TreeValue, TreeValue);
                    float pz = ry + UnityEngine.Random.Range(-TreeValue, TreeValue);

                    if (Extensions.IsPointInPolygon(ps, px, pz))
                    {
                        SetTreeToTerrain(TreeScaleFactor, TreeRandomScaleFactor, container, new Vector3(px, 0, pz));
                        counter++;
                    }
                }
            }
        }
        public static void GenerateTrees(TerrainContainerObject container, List <GameObject> m_treesPrefabs, float m_treeDensity, float TreeScaleFactor, float TreeRandomScaleFactor, float m_TreeDistance, float m_BillBoardStartDistance, Dictionary <string, OSMNode> nodes, Dictionary <string, OSMWay> ways, List <OSMMapMembers> relations)
        {
            TreeDistance           = m_TreeDistance;
            BillBoardStartDistance = m_BillBoardStartDistance;

            AddTreesToTerrains(container, m_treesPrefabs);

            treeNodes   = new List <OSMNode>();
            woodWays    = new List <OSMWay>();
            treeRowWays = new List <OSMWay>();

            foreach (KeyValuePair <string, OSMNode> pair in nodes)
            {
                OSMNode n = pair.Value;
                if (n.HasTag("natural", "tree"))
                {
                    treeNodes.Add(n);
                }
            }

            foreach (KeyValuePair <string, OSMWay> pair in ways)
            {
                OSMWay w = pair.Value;
                if (w.HasTag("natural", "wood") || w.HasTags("landuse", "forest", "park"))
                {
                    woodWays.Add(w);
                }
                else if (w.HasTag("natural", "tree_row"))
                {
                    treeRowWays.Add(w);
                }
            }


            totalTreeCount = treeNodes.Count + treeRowWays.Count + woodWays.Count;

            if (totalTreeCount == 0)
            {
                return;
            }

            alreadyCreated = new HashSet <string>();

            var treeDensity = m_treeDensity;

            var TLPMercator_X = container.TLPointMercator.x;
            var TLPMercator_Y = container.TLPointMercator.y;

            var DRPMercator_X = container.DRPointMercator.x;
            var DRPMercator_Y = container.DRPointMercator.y;


            for (int i = 0; i < treeNodes.Count; i++)
            {
                OSMNode node = treeNodes[i];

                if (alreadyCreated.Contains(node.id))
                {
                    continue;
                }

                alreadyCreated.Add(node.id);

                var NodeP_Merc = GeoRefConversion.LatLongToMercat(node.Longitude, node.Latitude);

                double Offest_x = (NodeP_Merc.x - TLPMercator_X) / (DRPMercator_X - TLPMercator_X);

                double Offest_y = 1 - (NodeP_Merc.y - TLPMercator_Y) / (DRPMercator_Y - TLPMercator_Y);

                Vector3 WSPos = new Vector3((float)(container.transform.position.x + container.size.x * Offest_x), 0, (float)(container.size.z + container.size.z * Offest_y));

                SetTreeToTerrain(TreeScaleFactor, TreeRandomScaleFactor, container, WSPos);
            }

            for (int index = 0; index < treeRowWays.Count; index++)
            {
                OSMWay way = treeRowWays[index];
                if (alreadyCreated.Contains(way.id))
                {
                    continue;
                }
                alreadyCreated.Add(way.id);
                List <Vector3> points = OSMWay.GetGlobalPointsFromWay(way, nodes);

                for (int i = 0; i < points.Count; i++)
                {
                    Vector3 WSPos = points[i];

                    var WSPos_Merc = GeoRefConversion.LatLongToMercat(WSPos.x, WSPos.z);

                    double Offest_x = (WSPos_Merc.x - TLPMercator_X) / (DRPMercator_X - TLPMercator_X);
                    double Offest_y = 1 - (WSPos_Merc.y - TLPMercator_Y) / (DRPMercator_Y - TLPMercator_Y);

                    WSPos.x = (float)(container.transform.position.x + container.size.x * Offest_x);
                    WSPos.z = (float)(container.transform.position.z + container.size.z * Offest_y);

                    points[i] = WSPos;
                }

                for (int i = 0; i < points.Count - 1; i++)
                {
                    int len = Mathf.RoundToInt((points[i] - points[i + 1]).magnitude / m_treeDensity);
                    if (len > 0)
                    {
                        for (int j = 0; j <= len; j++)
                        {
                            SetTreeToTerrain(TreeScaleFactor, TreeRandomScaleFactor, container, Vector3.Lerp(points[i], points[i + 1], j / (float)len));
                        }
                    }
                    else
                    {
                        SetTreeToTerrain(TreeScaleFactor, TreeRandomScaleFactor, container, points[i]);
                    }
                }
            }

            for (int index = 0; index < woodWays.Count; index++)
            {
                OSMWay way = woodWays[index];
                if (alreadyCreated.Contains(way.id))
                {
                    continue;
                }
                alreadyCreated.Add(way.id);
                List <Vector3> points = OSMWay.GetGlobalPointsFromWay(way, nodes);

                for (int i = 0; i < points.Count; i++)
                {
                    Vector3 p = points[i];

                    var sp = GeoRefConversion.LatLongToMercat(p.x, p.z);

                    double rx = (sp.x - TLPMercator_X) / (DRPMercator_X - TLPMercator_X);
                    double ry = 1 - (sp.y - TLPMercator_Y) / (DRPMercator_Y - TLPMercator_Y);

                    p.x = (float)(container.transform.position.x + container.size.x * rx);
                    p.z = (float)(container.transform.position.z + container.size.z * ry);

                    points[i] = p;
                }

                Rect rect = Extensions.GetRectFromPoints(points);
                int  lx   = Mathf.RoundToInt(rect.width / m_treeDensity);
                int  ly   = Mathf.RoundToInt(rect.height / m_treeDensity);

                if (lx > 0 && ly > 0)
                {
                    m_currentWayID = way.id;

                    GenerateTerrainsTrees(TreeScaleFactor, TreeRandomScaleFactor, container, treeDensity, lx, ly, rect, points);
                }
            }
        }
 private static void SetTreeToTerrain(float TreeScaleFactor, float RandomScaleFactor, TerrainContainerObject container, Vector3 pos)
 {
     for (int x = 0; x < container.terrainCount.x; x++)
     {
         for (int y = 0; y < container.terrainCount.y; y++)
         {
             TerrainObject item    = container.terrains[x, y];
             Terrain       terrain = item.terrain;
             terrain.treeBillboardDistance = BillBoardStartDistance;
             terrain.treeDistance          = TreeDistance;
             TerrainData tData           = terrain.terrainData;
             Vector3     terPos          = terrain.transform.position;
             Vector3     localPos        = pos - terPos;
             float       heightmapWidth  = (tData.heightmapWidth - 1) * tData.heightmapScale.x;
             float       heightmapHeight = (tData.heightmapHeight - 1) * tData.heightmapScale.z;
             if (localPos.x > 0 && localPos.z > 0 && localPos.x < heightmapWidth && localPos.z < heightmapHeight)
             {
                 terrain.AddTreeInstance(new TreeInstance
                 {
                     color          = Color.white,
                     heightScale    = TreeScaleFactor + UnityEngine.Random.Range(-RandomScaleFactor, RandomScaleFactor),
                     lightmapColor  = Color.white,
                     position       = new Vector3(localPos.x / heightmapWidth, 0, localPos.z / heightmapHeight),
                     prototypeIndex = UnityEngine.Random.Range(0, tData.treePrototypes.Length),
                     widthScale     = TreeScaleFactor + UnityEngine.Random.Range(-RandomScaleFactor, RandomScaleFactor)
                 });
                 break;
             }
         }
     }
 }
        public void GenerateTerrains()
        {
            const string containerName = "Terrains";
            string       cName         = containerName;

            //Destroy prv created terrain
            if (RemovePrvTerrain)
            {
                DestroyImmediate(GameObject.Find(cName));
            }
            else
            {
                int index = 1;
                while (GameObject.Find(cName) != null)
                {
                    cName = containerName + " " + index.ToString();
                    index++;
                }
            }


            var container = new GameObject(cName);

            container.transform.position = new Vector3(0, 0, 0);
            CurrentTerrainIndex          = 0;

            Vector2Int tCount = new Vector2Int(terrainCount.x, terrainCount.y);

            float maxElevation   = floatReader.MaxElevation;
            float minElevation   = floatReader.MinElevation;
            float ElevationRange = maxElevation - minElevation;

            var sizeX = Mathf.Floor(m_terrainDimensions.x * terrainScale.x * 10) / terrainCount.x;
            var sizeZ = Mathf.Floor(m_terrainDimensions.y * terrainScale.z * 10) / terrainCount.y;
            var sizeY = (ElevationRange) / ElevationScaleValue * TerrainExaggeration * 100 * terrainScale.y * 10;

            Vector3 size;

            if (terrainElevation == TerrainElevation.RealWorldElevation)
            {
                sizeY = ((ElevationRange)) * terrainScale.y;
                size  = new Vector3(sizeX, sizeY, sizeZ);
            }
            else
            {
                sizeY = sizeY * 10;
                size  = new Vector3(sizeX, sizeY, sizeZ);
            }

            string resultFolder   = "Assets/Generated GIS Terrains";
            string resultFullPath = Path.Combine(Application.dataPath, "Generated GIS Terrains");

            if (!Directory.Exists(resultFullPath))
            {
                Directory.CreateDirectory(resultFullPath);
            }
            string dateStr = DateTime.Now.ToString("yyyy-MM-dd HH-mm-") + DateTime.Now.Second.ToString();

            resultFolder  += "/" + dateStr;
            resultFullPath = Path.Combine(resultFullPath, dateStr);
            if (!Directory.Exists(resultFullPath))
            {
                Directory.CreateDirectory(resultFullPath);
            }



            terrains = new TerrainObject[tCount.x, tCount.y];

            container.AddComponent <TerrainContainerObject>();

            var terrainContainer = container.GetComponent <TerrainContainerObject>();

            terrainContainer.terrainCount = new Vector2Int(terrainCount.x, terrainCount.y);

            terrainContainer.GeneratedTerrainfolder = resultFolder;

            terrainContainer.scale = terrainScale;

            terrainContainer.size = new Vector3(size.x * tCount.x, size.y, size.z * tCount.y);

            //Set Terrain Coordinates to the container TerrainContainer script (Lat/lon) + Mercator
            terrainContainer.TLPointLatLong = floatReader.TopLeftPoint;
            terrainContainer.DRPointLatLong = floatReader.DownRightPoint;

            terrainContainer.TLPointMercator = GeoRefConversion.LatLongToMercat(terrainContainer.TLPointLatLong.x, terrainContainer.TLPointLatLong.y);
            terrainContainer.DRPointMercator = GeoRefConversion.LatLongToMercat(terrainContainer.DRPointLatLong.x, terrainContainer.DRPointLatLong.y);

            //Terrain Size Bounds
            var centre = new Vector3(terrainContainer.size.x / 2, 0, terrainContainer.size.z / 2);

            terrainContainer.GlobalTerrainBounds = new Bounds(centre, new Vector3(centre.x + terrainContainer.size.x / 2, 0, centre.z + terrainContainer.size.z / 2));



            for (int x = 0; x < tCount.x; x++)
            {
                for (int y = 0; y < tCount.y; y++)
                {
                    terrains[x, y]           = CreateTerrain(terrainContainer, x, y, size, terrainScale);
                    terrains[x, y].container = terrainContainer;
                }
            }

            terrainContainer.terrains = terrains;

            GeneratedContainer = terrainContainer;

            phase = GeneratingTerrainPhase.generateHeightmaps;
        }
Пример #9
0
        public void GenerateTerrains()
        {
            ListTerrainObjects = new List <TerrainObject>();

            const string containerName = "Terrains";
            string       cName         = containerName;

            //Destroy prv created terrain
            if (RemovePrevTerrain)
            {
                Destroy(GameObject.Find(cName));
            }
            else
            {
                int index = 1;
                while (GameObject.Find(cName) != null)
                {
                    cName = containerName + " " + index.ToString();
                    index++;
                }
            }


            var container = new GameObject(cName);

            container.transform.position = new Vector3(0, 0, 0);

            progress = 0;

            Vector2 TlimiteFrom = new Vector2(prefs.terrainDimensions.x, 0);
            Vector2 TlimiteTo   = new Vector2(prefs.terrainDimensions.y, 0);

            Vector2Int tCount = new Vector2Int((int)prefs.terrainCount.x, (int)prefs.terrainCount.y);

            float maxElevation   = floatReader.MaxElevation;
            float minElevation   = floatReader.MinElevation;
            float ElevationRange = maxElevation - minElevation;

            var sizeX = Mathf.Floor(prefs.terrainDimensions.x * prefs.terrainScale.x) / prefs.terrainCount.x;
            var sizeZ = Mathf.Floor(prefs.terrainDimensions.y * prefs.terrainScale.z) / prefs.terrainCount.y;
            var sizeY = (ElevationRange) / ElevationScaleValue * prefs.TerrainExaggeration * 100 * prefs.terrainScale.y;

            Vector3 size;

            if (prefs.TerrainElevation == TerrainElevation.RealWorldElevation)
            {
                sizeY = ((ElevationRange)) * prefs.terrainScale.y / 100;
                size  = new Vector3(sizeX, sizeY, sizeZ);
            }
            else
            {
                size = new Vector3(sizeX, sizeY, sizeZ);
            }

            terrains = new TerrainObject[tCount.x, tCount.y];

            container.AddComponent <TerrainContainerObject>();

            var terrainContainer = container.GetComponent <TerrainContainerObject>();

            Terrainscontainer = terrainContainer;

            terrainContainer.terrainCount = prefs.terrainCount;

            terrainContainer.scale = prefs.terrainScale;

            terrainContainer.size = new Vector3(size.x * tCount.x, size.y, size.z * tCount.y);

            //Set Terrain Coordinates to the container TerrainContainer script (Lat/lon) + Mercator
            terrainContainer.TLPointLatLong = floatReader.TopLeftPoint;
            terrainContainer.DRPointLatLong = floatReader.DownRightPoint;

            terrainContainer.TLPointMercator = GeoRefConversion.LatLongToMercat(terrainContainer.TLPointLatLong.x, terrainContainer.TLPointLatLong.y);
            terrainContainer.DRPointMercator = GeoRefConversion.LatLongToMercat(terrainContainer.DRPointLatLong.x, terrainContainer.DRPointLatLong.y);



            progress = 0;

            for (int x = 0; x < tCount.x; x++)
            {
                for (int y = 0; y < tCount.y; y++)
                {
                    terrains[x, y]           = CreateTerrain(container.transform, x, y, size, prefs.terrainScale);
                    terrains[x, y].container = terrainContainer;

                    ListTerrainObjects.Add(terrains[x, y]);
                }
            }

            terrainContainer.terrains = terrains;

            phase = GeneratingTerrainPhase.generateHeightmaps;
        }
        public static void GenerateGrass(TerrainContainerObject m_container, List <GISTerrainLoaderSO_Grass> m_GrassPrefabs, float m_GrassDensity, float m_GrassScaleFactor, float m_DetailDistance, Dictionary <string, OSMNode> nodes, Dictionary <string, OSMWay> ways, List <OSMMapMembers> relations)
        {
            GrassPrefabs     = m_GrassPrefabs;
            container        = m_container;
            GrassScaleFactor = m_GrassScaleFactor;
            DetailDistance   = m_DetailDistance;

            AddDetailsLayersToTerrains();

            TerrainData tdata            = container.terrains[0, 0].terrainData;
            int         detailResolution = tdata.detailResolution;


            alreadyCreated = new List <string>();

            details = new List <int[, ]>(container.terrains.Length);

            foreach (var item in container.terrains)
            {
                for (int i = 0; i < GrassPrefabs.Count; i++)
                {
                    details.Add(new int[detailResolution, detailResolution]);
                }
            }

            var detailsInPoint = new float[GrassPrefabs.Count];

            var grassWays = new List <OSMWay>();

            foreach (KeyValuePair <string, OSMWay> pair in ways)
            {
                OSMWay w = pair.Value;
                if (w.HasTags("landuse", "grass", "farmland", "forest", "meadow", "park", "pasture", "recreation_ground") ||
                    w.HasTags("leisure", "park", "golf_course") || w.HasTags("natural", "scrub", "wood"))
                {
                    grassWays.Add(w);
                }
            }

            var totalCount = grassWays.Count + container.terrainCount.x;

            float density = m_GrassDensity / 100f;

            if (density > 1)
            {
                density = 1;
            }

            density *= 64;

            for (int i = 0; i < grassWays.Count; i++)
            {
                OSMWay way = grassWays[i];

                if (alreadyCreated.Contains(way.id))
                {
                    continue;
                }
                alreadyCreated.Add(way.id);

                if (way.nodeRefs.Count == 0)
                {
                    continue;
                }

                List <Vector3> Points = new List <Vector3>();

                float pxmin = float.MaxValue, pxmax = float.MinValue, pymin = float.MaxValue, pymax = float.MinValue;

                for (int m = 0; m < way.nodeRefs.Count; m++)
                {
                    string nodeRef = way.nodeRefs[m];

                    OSMNode node;
                    if (!nodes.TryGetValue(nodeRef, out node))
                    {
                        continue;
                    }


                    var NodeP_Merc = GeoRefConversion.LatLongToMercat(node.Longitude, node.Latitude);

                    Vector3 wspostion = GeoRefConversion.MercatCoordsToWorld(NodeP_Merc.x, 0, NodeP_Merc.y, container) - container.transform.position;

                    wspostion = new Vector3(wspostion.x / tdata.size.x * detailResolution, 0, wspostion.z / tdata.size.z * detailResolution);

                    if (wspostion.x < pxmin)
                    {
                        pxmin = wspostion.x;
                    }
                    if (wspostion.x > pxmax)
                    {
                        pxmax = wspostion.x;
                    }
                    if (wspostion.z < pymin)
                    {
                        pymin = wspostion.z;
                    }
                    if (wspostion.z > pymax)
                    {
                        pymax = wspostion.z;
                    }

                    Points.Add(wspostion);
                }

                if (Points.Count < 3)
                {
                    continue;
                }

                Vector3[] points = Points.ToArray();
                for (int x = (int)pxmin; x < pxmax; x++)
                {
                    int tix = Mathf.FloorToInt(x / (float)detailResolution);
                    if (tix < 0 || tix >= container.terrainCount.x)
                    {
                        continue;
                    }

                    int tx = x - tix * detailResolution;

                    for (int y = (int)pymin; y < pymax; y++)
                    {
                        int tiy = Mathf.FloorToInt(y / (float)detailResolution);
                        if (tiy >= container.terrainCount.y || tiy < 0)
                        {
                            continue;
                        }

                        int tIndex = tiy * container.terrainCount.x + tix;
                        if (tIndex < 0 || tIndex >= container.terrains.Length)
                        {
                            continue;
                        }

                        bool intersect = Extensions.IsPointInPolygon(points, x + 0.5f, y - 0.5f);
                        if (!intersect)
                        {
                            continue;
                        }

                        int ty = y - tiy * detailResolution;

                        if (GrassPrefabs.Count == 1)
                        {
                            details[tIndex][ty, tx] = (int)density;
                        }
                        else
                        {
                            float totalInPoint = 0;

                            int tIndex2 = tIndex * GrassPrefabs.Count;

                            for (int k = 0; k < GrassPrefabs.Count; k++)
                            {
                                float v = Random.Range(0f, 1f);
                                detailsInPoint[k] = v;
                                totalInPoint     += v;
                            }

                            for (int k = 0; k < GrassPrefabs.Count; k++)
                            {
                                int v = (int)(detailsInPoint[k] / totalInPoint * density);
                                if (v > 255)
                                {
                                    v = 255;
                                }
                                details[tIndex2 + k][ty, tx] = v;
                            }
                        }
                    }
                }
            }


            for (int x = 0; x < container.terrainCount.x; x++)
            {
                for (int y = 0; y < container.terrainCount.y; y++)
                {
                    for (int prefabIndex = 0; prefabIndex < GrassPrefabs.Count; prefabIndex++)
                    {
                        int tIndex = y * container.terrainCount.x + x;

                        container.terrains[x, y].terrainData.SetDetailLayer(0, 0, prefabIndex,
                                                                            details[tIndex * GrassPrefabs.Count + prefabIndex]);
                    }
                }
            }
        }