Convert Prototypes To Grass Meshes

Dictionary<int, Mesh[]> ConvertPrototypesToGrassMeshes(TerrainToMeshPrototype[] data, TerrainToMeshEnum.GrassCombineType grassCombineType, TerrainToMeshEnum.GrassMeshTexcoord2 grassMeshTexcoord2, bool calculateHealthAndDryColor, Dictionary<Texture2D, Rect> atlasRect, float exportPercentage, int maxVertexCountPerCombinedMesh, int grassMeshSidesCount = 1, float grassMeshDistortion = 0, float yRotation = 360, float yRotationRandomize = 360, float followTerrainSurface = 0, bool followTerrainSurfaceRandomize = false)

Combines TerrainToMeshPrototypes grass objects into one or several meshes.

Returned dictionary key is the grass index inside TerrainData.detailPrototypes array and value holds the combined meshes associated to that index.

grassCombineType - Grass meshes combine type:

  • GrassCombineType.ByTexture - Grass meshes are combined based on the used grass texture.

  • GrassCombineType.ByTextureWithAtlas - Grass meshes are combined based on the used grass texture and mesh UV is generated based on the provided GrassAtlasTexture.

  • GrassCombineType.Everything - Combines all grass meshes into one file and for each mesh UV is generated based on the provided GrassAtlasTexture.

grassMeshTexcoord2 - Allows baking additional data inside combed meshes UV channel #2:

  • GrassMeshTexcoord2.None - Nothing is baked.

  • GrassMeshTexcoord2.PivotPoint - Bakes current grass quad mesh's pivot point's local position.

  • GrassMeshTexcoord2.BaseUV - Bakes current grass quad mesh's initial UV coordinates that will be overwritten in the case of using GrassAtlasTexture.

calculateHealthAndDryColor - Bakes prototype's health and dry colors.

Dictionary<Texture2D, Rect> atlasRect - In the case of using GrassAtlasTexture, this property should provide collection of GrassTextures and UV coordinates associated with this texture inside GrassAtlasTexture.

exportPercentage - Percentage of the combined grass objects in the range of [0.01, 100]

maxVertexCountPerCombinedMesh - Defines how much vertices combined mesh(es) will contain.

Theoretically Unity can create mesh with 4 billion vertices, but for run-time use it is better to use more logical values. Based on the used vertex count, generated meshes will be in 16 or 32 bits index format.

int grassMeshSidesCount, float grassMeshDistortion - Specifies how much sides each grass quad mesh will contain and how much offset distortion they will have.

//Example of exporting grass from TerrainData 
//and generating combined meshes by used texture

//Exporting terrain mesh
Mesh terrainMesh = terrainData.TerrainToMesh().ExportMesh(100, 100);

//Creaing GameObject using terrain mesh
GameObject terrainGO = new GameObject("Terrain");
terrainGO.AddComponent<MeshFilter>().sharedMesh = terrainMesh;
terrainGO.AddComponent<MeshRenderer>().sharedMaterial = new Material(TerrainToMeshUtilities.GetDefaultShader());


//Exporting grass from TerrainData
TerrainToMeshPrototype[] grassPrototypes = terrainData.TerrainToMesh().ExportPrototypes(TerrainToMeshEnum.Prototype.Grass);

//Combining 100% of grassPrototypes into meshes with each one with 65K vertices
Dictionary<int, Mesh[]> grassMeshes = TerrainToMeshUtilities.ConvertPrototypesToGrassMeshes(grassPrototypes,
                                                                                            TerrainToMeshEnum.GrassCombineType.ByTexture,
                                                                                            TerrainToMeshEnum.GrassMeshTexcoord2.None,
                                                                                            true,
                                                                                            null,
                                                                                            100,
                                                                                            65000);


//Creating materials for each layer
Dictionary<int, Material> grassMaterials = new Dictionary<int, Material>();
foreach (var item in grassMeshes)
{
    Texture2D grassTexture = terrainData.detailPrototypes[item.Key].prototypeTexture;

    Material material = new Material(TerrainToMeshUtilities.GetDefaultShader());
    
    //Setting up material to use grass texture for '_MainTex' and enabling Alpha Cutout
    TerrainToMeshUtilities.SetupDefaultMaterial(material, grassTexture, true, null, null, null);

    material.name = grassTexture.name;


    grassMaterials.Add(item.Key, material);
}

//Instantiating gameObject with grass meshes
foreach (var item in grassMeshes)
{
    Mesh[] meshes = item.Value;
    for (int i = 0; i < meshes.Length; i++)
    {
        GameObject grassGO = new GameObject($"Grass (Layer : {item.Key}) {grassMaterials[item.Key].name}");

        grassGO.AddComponent<MeshFilter>().sharedMesh = meshes[i];
        grassGO.AddComponent<MeshRenderer>().sharedMaterial = grassMaterials[item.Key];

        grassGO.transform.SetParent(terrainGO.transform);
    }
}

Last updated