Пример #1
0
    public static void generateTerrain(Boolean treesEnabled, Boolean grassEnabled)
    {
        ImportAndGenerate.treesEnabled = treesEnabled;
        ImportAndGenerate.grassEnabled = grassEnabled;
        int   length = (int)((xmax - xmin) * scaleLength);
        int   width  = (int)((ymax - ymin) * scaleWidth);
        float x      = xmin - (xmax - xmin) / 2 - xmin;
        float y      = ymin - (ymax - ymin) / 2 - ymin;

        float height = (length < 250 || width < 250) ? 30 : 80;

        numPlants = (int)(length * width / 20);
        if (numPlants < 100)
        {
            numPlants = 500;
        }

        Texture2D FlatTexture  = AssetDatabase.LoadAssetAtPath <Texture2D>(PathConstants.pathGrassTexture2D);
        Texture2D SteepTexture = AssetDatabase.LoadAssetAtPath <Texture2D>(PathConstants.pathRockTexture2D);

        terrainData = new TerrainData();
        terrainData.heightmapResolution = 256;
        terrainData.alphamapResolution  = 256;

        var heightmap = new float[terrainData.heightmapResolution, terrainData.heightmapResolution];

        System.Random rand = new System.Random();

        for (var zRes = 0; zRes < terrainData.heightmapResolution; zRes++)
        {
            for (var xRes = 0; xRes < terrainData.heightmapResolution; xRes++)
            {
                // Reduce factor
                float distX        = 0;
                float distY        = 0;
                float marginStart  = 20;
                float marginEnd    = 50;
                float reduceFactor = 0;
                float constHeight  = 0.5f;

                if (Math.Abs(terrainData.heightmapResolution - xRes) < xRes)
                {
                    distX = Math.Abs(terrainData.heightmapResolution - xRes);
                }
                else
                {
                    distX = xRes;
                }
                if (Math.Abs(terrainData.heightmapResolution - zRes) < zRes)
                {
                    distY = Math.Abs(terrainData.heightmapResolution - zRes);
                }
                else
                {
                    distY = zRes;
                }

                if (distX > marginStart && distY > marginStart && distX <= marginEnd && distY <= marginEnd)
                {
                    reduceFactor          = 1 - (float)(((distX - marginStart) + (distY - marginStart)) / (2 * (marginEnd - marginStart)));
                    heightmap[zRes, xRes] = reduceFactor * constHeight;
                }
                else if (distY > marginStart && distY <= marginEnd && distX > marginEnd)
                {
                    reduceFactor          = 1 - ((distY - marginStart) / (marginEnd - marginStart));
                    heightmap[zRes, xRes] = reduceFactor * constHeight;
                }
                else if (distX > marginStart && distX <= marginEnd && distY > marginEnd)
                {
                    reduceFactor          = 1 - ((distX - marginStart) / (marginEnd - marginStart));
                    heightmap[zRes, xRes] = reduceFactor * constHeight;
                }
                else
                {
                    reduceFactor          = 1;
                    heightmap[zRes, xRes] = reduceFactor * constHeight;
                }

                // Actual height values from neighbours

                double randFactor = 0.1f;
                double selfFactor = 1.5;
                float  value      = 0;

                if (zRes > 0 && xRes > 0 && xRes < terrainData.heightmapResolution - 1 && zRes < terrainData.heightmapResolution - 1)
                {
                    value = (float)(
                        heightmap[zRes, xRes] * selfFactor +
                        rand.NextDouble() * randFactor +
                        heightmap[zRes - 1, xRes - 1] +
                        heightmap[zRes, xRes - 1] +
                        heightmap[zRes - 1, xRes] +
                        heightmap[zRes + 1, xRes - 1] +
                        heightmap[zRes - 1, xRes + 1] +
                        heightmap[zRes + 1, xRes + 1] +
                        heightmap[zRes + 1, xRes] +
                        heightmap[zRes, xRes + 1]) / 10;
                }
                else if (xRes == 0 && zRes == 0)
                {
                    value = (float)(
                        heightmap[zRes, xRes] * selfFactor +
                        rand.NextDouble() * randFactor +
                        heightmap[zRes + 1, xRes + 1] +
                        heightmap[zRes + 1, xRes] +
                        heightmap[zRes, xRes + 1]) / 5;
                }
                else if (xRes == 0 && zRes > 0 && zRes < terrainData.heightmapResolution - 1)
                {
                    value = (float)(
                        heightmap[zRes, xRes] * selfFactor +
                        rand.NextDouble() * randFactor +
                        heightmap[zRes - 1, xRes] +
                        heightmap[zRes - 1, xRes + 1] +
                        heightmap[zRes + 1, xRes + 1] +
                        heightmap[zRes + 1, xRes] +
                        heightmap[zRes, xRes + 1]) / 7;
                }
                else if (xRes == 0 && zRes == terrainData.heightmapResolution - 1)
                {
                    value = (float)(
                        heightmap[zRes, xRes] * selfFactor +
                        rand.NextDouble() * randFactor * randFactor +
                        heightmap[zRes - 1, xRes] +
                        heightmap[zRes - 1, xRes + 1] +
                        heightmap[zRes, xRes + 1]) / 5;
                }
                else if (xRes > 0 && xRes < terrainData.heightmapResolution - 1 && zRes == 0)
                {
                    value = (float)(
                        heightmap[zRes, xRes] * selfFactor +
                        rand.NextDouble() * randFactor +
                        heightmap[zRes, xRes - 1] +
                        heightmap[zRes + 1, xRes - 1] +
                        heightmap[zRes + 1, xRes + 1] +
                        heightmap[zRes + 1, xRes] +
                        heightmap[zRes, xRes + 1]) / 7;
                }
                else if (xRes == terrainData.heightmapResolution - 1 && zRes == 0)
                {
                    value = (float)(
                        heightmap[zRes, xRes] * selfFactor +
                        rand.NextDouble() * randFactor +
                        heightmap[zRes, xRes - 1] +
                        heightmap[zRes + 1, xRes - 1] +
                        heightmap[zRes + 1, xRes]) / 5;
                }
                else if (xRes == terrainData.heightmapResolution - 1 && zRes > 0 && zRes < terrainData.heightmapResolution - 1)
                {
                    value = (float)(
                        heightmap[zRes, xRes] * selfFactor +
                        rand.NextDouble() * randFactor +
                        heightmap[zRes - 1, xRes - 1] +
                        heightmap[zRes, xRes - 1] +
                        heightmap[zRes - 1, xRes] +
                        heightmap[zRes + 1, xRes - 1] +
                        heightmap[zRes + 1, xRes]) / 7;
                }
                else if (xRes == terrainData.heightmapResolution - 1 && zRes == terrainData.heightmapResolution - 1)
                {
                    value = (float)(
                        heightmap[zRes, xRes] * selfFactor +
                        rand.NextDouble() * randFactor +
                        heightmap[zRes - 1, xRes - 1] +
                        heightmap[zRes, xRes - 1] +
                        heightmap[zRes - 1, xRes]) / 5;
                }
                else if (xRes > 0 && xRes < terrainData.heightmapResolution - 1 && zRes == terrainData.heightmapResolution - 1)
                {
                    value = (float)(
                        heightmap[zRes, xRes] * selfFactor +
                        rand.NextDouble() * randFactor +
                        heightmap[zRes - 1, xRes - 1] +
                        heightmap[zRes, xRes - 1] +
                        heightmap[zRes - 1, xRes] +
                        heightmap[zRes - 1, xRes + 1] +
                        heightmap[zRes, xRes + 1]) / 7;
                }

                if (value < 0 || distX > marginEnd && distY > marginEnd)
                {
                    value = 0;
                }

                heightmap[zRes, xRes] = value;
            }
        }

        terrainData.SetHeights(0, 0, heightmap);

        var flatSplat  = new SplatPrototype();
        var steepSplat = new SplatPrototype();

        flatSplat.texture  = FlatTexture;
        steepSplat.texture = SteepTexture;

        terrainData.splatPrototypes = new SplatPrototype[]
        {
            flatSplat,
            steepSplat
        };

        terrainData.RefreshPrototypes();

        var splatMap = new float[terrainData.alphamapResolution, terrainData.alphamapResolution, 2];

        for (var zRes = 0; zRes < terrainData.alphamapHeight; zRes++)
        {
            for (var xRes = 0; xRes < terrainData.alphamapWidth; xRes++)
            {
                var normalizedX = (float)xRes / (terrainData.alphamapWidth - 1);
                var normalizedZ = (float)zRes / (terrainData.alphamapHeight - 1);

                var steepness           = terrainData.GetSteepness(normalizedX, normalizedZ);
                var steepnessNormalized = Mathf.Clamp(steepness / 1.5f, 0, 1f);

                splatMap[zRes, xRes, 0] = 1f - steepnessNormalized;
                splatMap[zRes, xRes, 1] = steepnessNormalized;
            }
        }

        terrainData.SetAlphamaps(0, 0, splatMap);

        terrainData.size = new Vector3(length, height, width);
        var newTerrainGameObject = Terrain.CreateTerrainGameObject(terrainData);

        newTerrainGameObject.transform.position = new Vector3(x, 0, y);

        Terrain = newTerrainGameObject.GetComponent <Terrain>();
        Terrain.heightmapPixelError  = 8;
        Terrain.materialType         = UnityEngine.Terrain.MaterialType.Custom;
        Terrain.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;

        // Insert Trees and Plants
        if (ImportAndGenerate.treesEnabled)
        {
            // (1) Trees:

            MonoBehaviour.print("Inserting 3d Plants");

            List <TreePrototype> tpa = new List <TreePrototype>();

            for (int i = 0; i < plants.Length; i++)
            {
                TreePrototype tp = new TreePrototype();
                tp.prefab = AssetDatabase.LoadMainAssetAtPath(PathConstants.pathPrefixPlants + plants[i] + ".prefab") as GameObject;
                tpa.Add(tp);
            }
            terrainData.treePrototypes = tpa.ToArray();

            for (int i = 0; i < numPlants; i++)
            {
                float xnRel = (float)rand.NextDouble();
                float xn    = terrainData.size.x * xnRel;
                float ynRel = (float)rand.NextDouble();
                float yn    = terrainData.size.z * ynRel;

                float xGlobal = Terrain.transform.TransformPoint(new Vector3(xn, 0, yn)).x;
                float yGlobal = Terrain.transform.TransformPoint(new Vector3(xn, 0, yn)).z;

                Boolean freeSpotFound = false;
                int     counter       = 0;

                while (!freeSpotFound && counter < 10)
                {
                    // Try 10 random positions, if all fail, then discard this plant
                    foreach (Vector3[] polygon in polygons)
                    {
                        freeSpotFound = !InPolyChecker.IsPointInPolygon(xGlobal, yGlobal, polygon);
                        if (!freeSpotFound)
                        {
                            break;
                        }
                    }
                    if (!freeSpotFound)
                    {
                        xnRel = (float)rand.NextDouble();
                        xn    = terrainData.size.x * xnRel;
                        ynRel = (float)rand.NextDouble();
                        yn    = terrainData.size.z * ynRel;

                        xGlobal = Terrain.transform.TransformPoint(new Vector3(xn, 0, yn)).x;
                        yGlobal = Terrain.transform.TransformPoint(new Vector3(xn, 0, yn)).z;

                        counter++;
                        break;
                    }
                }
                if (freeSpotFound)
                {
                    TreeInstance tree = new TreeInstance();
                    tree.position       = new Vector3(xnRel, 0, ynRel);
                    tree.color          = Color.white;
                    tree.lightmapColor  = Color.white;
                    tree.prototypeIndex = rand.Next(0, plants.Length);
                    tree.heightScale    = 1;
                    tree.widthScale     = 1;
                    Terrain.AddTreeInstance(tree);
                }
            }
        }

        // (2) Grass:
        if (ImportAndGenerate.grassEnabled)
        {
            DetailPrototype grass = new DetailPrototype();
            grass.prototypeTexture = (Texture2D)AssetDatabase.LoadAssetAtPath <Texture2D>(PathConstants.pathGrassPrototypeTexture2D);
            grass.minHeight        = 1;
            grass.minWidth         = 1;
            grass.maxHeight        = 2;
            grass.maxWidth         = 2;
            grass.noiseSpread      = 0.1f;
            grass.bendFactor       = 0.1f;
            grass.dryColor         = new Color(0.804f, 0.737f, 0.102f, 1.0f);
            grass.healthyColor     = new Color(0.263f, 0.976f, 0.165f, 1.0f);

            terrainData.detailPrototypes = new DetailPrototype[] { grass };
            terrainData.SetDetailResolution(256, 8);

            int detailCountPerDetailPixel = 6;
            int detailIndexToMassPlace    = 0;
            int alphamapWidth             = terrainData.alphamapWidth;
            int alphamapHeight            = terrainData.alphamapHeight;
            int detailWidth  = terrainData.detailResolution;
            int detailHeight = detailWidth;
            int[,] newDetailLayer = new int[detailWidth, detailHeight];
            int delta = 1;

            for (int j = 0; j < detailWidth; j++)
            {
                for (int k = 0; k < detailHeight; k++)
                {
                    float[] coord = getCornerCoordinatesFromPixel(j, k, detailWidth, detailHeight, Terrain.gameObject.transform.position.x, Terrain.gameObject.transform.position.z, terrainData.size.x, terrainData.size.z);
                    // Check if there is a street/junction at the coordinate
                    Boolean occupied = false;
                    foreach (Vector3[] polygon in polygons)
                    {
                        // Check sorrounding of coordinate
                        occupied = InPolyChecker.IsPointInPolygon(coord[0], coord[1], polygon) ||
                                   InPolyChecker.IsPointInPolygon(coord[0] - delta, coord[1] - delta, polygon) ||
                                   InPolyChecker.IsPointInPolygon(coord[0] - delta, coord[1], polygon) ||
                                   InPolyChecker.IsPointInPolygon(coord[0] - delta, coord[1] + delta, polygon) ||
                                   InPolyChecker.IsPointInPolygon(coord[0] + delta, coord[1] - delta, polygon) ||
                                   InPolyChecker.IsPointInPolygon(coord[0] + delta, coord[1], polygon) ||
                                   InPolyChecker.IsPointInPolygon(coord[0] + delta, coord[1] + delta, polygon);
                        if (occupied)
                        {
                            break;
                        }
                    }
                    if (!occupied)
                    {
                        newDetailLayer[j, k] = detailCountPerDetailPixel;
                    }
                }
            }
            terrainData.SetDetailLayer(0, 0, detailIndexToMassPlace, newDetailLayer);
        }

        // Finish
        Terrain.Flush();
    }
Пример #2
0
    internal static void generatingBuildings(int count)
    {
        GameObject buildingsContainer = new GameObject("Buildings");

        for (int i = 0; i < count; i++)
        {
            int        randomBuildingIndex = UnityEngine.Random.Range(0, PathConstants.pathBuildings.Length - 1);
            GameObject building            = AssetDatabase.LoadMainAssetAtPath(PathConstants.pathBuildings[randomBuildingIndex]) as GameObject;

            Component[] renderers = building.GetComponentsInChildren <Renderer>();
            float       maxLength = 0;
            float       maxWidth  = 0;
            foreach (Component renderer in renderers)
            {
                float currentLength = ((Renderer)renderer).bounds.size.x - xmin;
                float currentWidth  = ((Renderer)renderer).bounds.size.z - ymin;
                if (currentLength > maxLength)
                {
                    maxLength = currentLength;
                }
                if (currentWidth > maxWidth)
                {
                    maxWidth = currentWidth;
                }
            }

            maxLength = Math.Max(maxLength, maxWidth) * 2f;
            maxWidth  = maxLength;

            float randomXPosition   = UnityEngine.Random.Range(Terrain.transform.position.x, Terrain.transform.position.x + terrainData.size.x);
            float randomYPosition   = UnityEngine.Random.Range(Terrain.transform.position.z, Terrain.transform.position.z + terrainData.size.z);
            float randomOrientation = UnityEngine.Random.Range(0f, 360f);

            Boolean freeSpotFound = false;
            int     counter       = 0;

            while (!freeSpotFound && counter < 10)
            {
                // Try 10 random positions, if all fail, then discard this building
                int discretePointsCount = 8;
                foreach (Vector3[] polygon in polygons)
                {
                    freeSpotFound = true;
                    // Split the ground face into discretePointsCount^2 points to check
                    for (int x = 0; x < discretePointsCount; x++)
                    {
                        for (int y = 0; y < discretePointsCount; y++)
                        {
                            freeSpotFound &= !InPolyChecker.IsPointInPolygon(randomXPosition + x * maxLength / discretePointsCount, randomYPosition + y * maxLength / discretePointsCount, polygon);
                            if (!freeSpotFound)
                            {
                                break;
                            }
                        }
                    }
                    if (!freeSpotFound)
                    {
                        break;
                    }
                }
                if (!freeSpotFound)
                {
                    randomXPosition   = UnityEngine.Random.Range(Terrain.transform.position.x, Terrain.transform.position.x + terrainData.size.x);
                    randomYPosition   = UnityEngine.Random.Range(Terrain.transform.position.z, Terrain.transform.position.z + terrainData.size.z);
                    randomOrientation = UnityEngine.Random.Range(0f, 360f);
                    counter++;
                    continue;
                }
            }
            if (freeSpotFound)
            {
                GameObject instantiatedBuilding = GameObject.Instantiate(building, new Vector3(randomXPosition, 0, randomYPosition), Quaternion.Euler(new Vector3(0, randomOrientation, 0)));
                instantiatedBuilding.transform.SetParent(buildingsContainer.transform);
                Vector3[] vertices = new Vector3[] {
                    new Vector3(randomXPosition, 0, randomYPosition),
                    new Vector3(randomXPosition + maxLength, 0, randomYPosition),
                    new Vector3(randomXPosition + maxLength, 0, randomYPosition + maxWidth),
                    new Vector3(randomXPosition, 0, randomYPosition + maxWidth)
                };
                polygons.Add(vertices);
            }
        }
    }