So , i had this simple idea of using the terrain textures to pool grass and tress… ect
and use them over and over again . the goal is to have less draw calls and reuse the same prefabs to save cpu on mobile , since the game i’m making is for mobile .
how it works :
when i press trhe button it will call Grassmaker in the script attached.(to be changed to player movement event or loading screen) .
the scrip will make a grid where the player is the center and will add 1 unit step till it reach the limit of the grid like 10 units (you can change this to have more details)
then it will check the main texture used in the terrain once it has that it will check if the texutre name contains Grass or mud or rocks , or tree leafs … ect
and pick the prefab suited for the texture and instantiate it on the terrain in a random position around the sub grid cell center.
so here is my script and i will be adding more soon , feel free to add your ideas . or if you know that some one have done this before so i can stop reinventing the wheel :). , and save time and effort .
again this is a simple code , with little time put into it . i used foot steps terrain script as a start that i have found on github.
*my next goal is to make the pooling system works , make multiple variations of Grass and trees rocks … ect … and change the size and rotation to make it feel natural.
- Test the performance on multiple phones .
My main problem is that i’m gonna use mesh terrain for my mobile game if any one knows how to pick up the used texture in a giving position without the terrain , i would be so happy .(let me know if you need the shader for the mesh terrain)
Script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NatureManager : MonoBehaviour {
public Transform PlayerPos;
public Terrain terrain ;
public GameObject Grass;
public int GridXYlimit =10 ;
public int SubGridXYlimit =1 ;
public void Grassmaker (){
for ( int x = Mathf.RoundToInt(PlayerPos.position.x) - GridXYlimit ; x <= GridXYlimit +Mathf.RoundToInt(PlayerPos.position.x) ; x++) {
for ( int z = Mathf.RoundToInt(PlayerPos.position.z) - GridXYlimit ; z <= GridXYlimit+ Mathf.RoundToInt(PlayerPos.position.z) ; z++) {
Debug.Log (x);
Vector3 pos = new Vector3 (x, 0, z);
pos.y = terrain.SampleHeight(pos);
int index = GetMainTexture( pos) ;
Debug.Log (index);
if ( terrain.terrainData.splatPrototypes[ index].texture.name.Contains("Grass"))
{
int icount = 0;
for ( int i = 0; i < SubGridXYlimit; i ++ )
{
var random = Random.insideUnitCircle ;
Vector3 Grasspos = new Vector3 (pos.x + random.x, pos.y , pos.z + random.y );
Grasspos .y = terrain.SampleHeight(Grasspos);
Instantiate(Grass, Grasspos, Quaternion.identity);
}
}
}
}
}
public Vector2 GetTerrainPosition(Vector3 worldPos) {
TerrainData terrainData = terrain.terrainData;
Vector3 terrainPos = terrain.transform.position;
int mapX = (int) (((worldPos.x - terrainPos.x) / terrainData.size.x) * terrainData.alphamapWidth);
int mapZ = (int) (((worldPos.z - terrainPos.z) / terrainData.size.z) * terrainData.alphamapHeight);
return new Vector2(mapX, mapZ);
}
private float[, ,] GetAlphaMapsForPosition(Vector3 worldPos, int size) {
// get the splat data for this cell as a 1x1xN 3d array (where N = number of textures)
TerrainData terrainData = terrain.terrainData;
Vector2 converted = GetTerrainPosition(worldPos);
return terrainData.GetAlphamaps((int) converted.x - size / 2, (int) converted.y - size / 2, size, size);
}
public float[] GetTextureMix(Vector3 worldPos) {
// returns an array containing the relative mix of textures
// on the main terrain at this world position.
// The number of values in the array will equal the number
// of textures added to the terrain.
float[, ,] splatmapData = GetAlphaMapsForPosition(worldPos, 1);
// extract the 3D array data to a 1D array:
float[] cellMix = new float[splatmapData.GetUpperBound(2) + 1];
for (int n = 0; n < cellMix.Length; ++n) {
cellMix[n] = splatmapData[0, 0, n];
}
return cellMix;
}
public int GetMainTexture(Vector3 worldPos) {
// returns the zero-based index of the most dominant texture
// on the main terrain at this world position.
float[] mix = GetTextureMix(worldPos);
float maxMix = 0;
int maxIndex = 0;
// loop through each mix value and find the maximum
for (int n = 0; n < mix.Length; ++n) {
if (mix[n] > maxMix) {
maxIndex = n;
maxMix = mix[n];
}
}
return maxIndex;
}
}