Help with Procedural Grass System

I’m trying to develop a procedural grass mesh script, I’m probably going about this the wrong way but here is what I have so far.

As you can see it’s far from perfect, I was trying to get the grass meshes created in a grid first so that I could work on the random rotations/placement later. The script is far too slow though.

I’m trying to make this so that I can have more control over the grass placement etc. in my game.

I’m a very amateur programmer so please excuse any stupid mistakes!

If anybody can give me some help or advice it would be greatly appreciated.

var grassRadius = 50;

MeshUpdate();

function Start () {
	var terrainSize = Terrain.activeTerrain.terrainData.size;

	// Code that generates the random placement thingy goes here
}

function Update () {

	// This code is for the material that makes the grass wave
	var time = Time.time * 0.02 + transform.localPosition.x * 0.02 - transform.localPosition.z * 0.02;
	var wind = Vector4(time, 1.0, 0.8, 1.0);
	renderer.material.SetVector("_WaveAndDistance", wind);
}

function MeshUpdate () {
	
	while(true){
	
	yield WaitForSeconds (1);

	var cameraTransform = Camera.main.transform;
	var arr = Array ();
	
	for (x = cameraTransform.position.x - grassRadius;x < cameraTransform.position.x + grassRadius;x++) {
	for (z = cameraTransform.position.z - grassRadius;z < cameraTransform.position.z + grassRadius;z++) {
		// Finding grass positions and adding to the array
		var y = Terrain.activeTerrain.SampleHeight(Vector3(x,0,z));
		var dist = Vector3.Distance(Vector3(x,y,z), cameraTransform.position);
		//Debug.DrawLine (Vector3(x,y,z), cameraTransform.position, Color.red);
		//print(cameraTransform.position);
		if (dist < grassRadius)
		{
			arr.Add(Vector3(x,y,z));

		}	
	}
	}
	print(arr.length);
	//var builtInArr : Vector3[] = arr.ToBuiltin(Vector3);
	verts = new Vector3[arr.length * 4];
	uvs = new Vector2[arr.length * 4];
	tris = new int[arr.length * 6];

	for (g=0; g < arr.length; g++)
	{
		var pos = arr[g];
		
		var right = Vector3.right;
		var up = Vector3.up;
		

	// Code that generates the vertex, uv and triangle data for the mesh goes here

	// This code takes the data and puts it into the arrays 
		verts[g * 4] = pos + right;
		verts[g * 4 + 1] = pos - right;
		verts[g * 4 + 2] = pos + right + up;
		verts[g * 4 + 3] = pos - right + up;

		uvs[g * 4] = Vector2.zero;
		uvs[g * 4 + 1] = Vector2.right;
		uvs[g * 4 + 2] = Vector2.up;
		uvs[g * 4 + 3] = Vector2.right + Vector2.up;

		tris[g * 6] = g * 4;
		tris[g * 6 + 1] = g * 4 + 1;
		tris[g * 6 + 2] = g * 4 + 2;

		tris[g * 6 + 3] = g * 4 + 2;
		tris[g * 6 + 4] = g * 4 + 1;
		tris[g * 6 + 5] = g * 4 + 3;
	}


	// This code takes the arrays and builds the mesh
	grassMeshFilter = gameObject.GetComponent(typeof(MeshFilter)) as MeshFilter;

	grassMeshFilter.mesh.vertices = verts;
	grassMeshFilter.mesh.triangles = tris;
	grassMeshFilter.mesh.uv = uvs;
	}
}

[/code]

OK, I’m not too sure exactly how this code will be used, but here are a few suggestions.

Very often, when updating a mesh, the triangle data and sometimes the UVs and normals don’t change when the verts move. Don’t update the data which doesn’t change and you’ll save some work in each loop iteration.

Rather than call GetComponent each frame (if that is what you are doing), just call it once in the start method and store the result. This function is surprisingly slow.

You are using Vector3.Distance to calculate the distance of a vert from the camera, but you only use that distance as a comparison against grassRadius. When you need to compare two point-to-point distances, it is actually better if you compare the squares of the distances instead:-

var sqDist: float = (Vector3(x,y,z) - cameraTransform.position).sqrMagnitude;
var sqGrassRadius = grassRadius * grassRadius;

if (sqDist < sqGrassRadius) {
   ...
}

The reason for this is that calculating the distance involves an expensive square root calculation that you can avoid if you use squared distances instead.

Intuitively, I would say the squared distance thing would help the most, but any of these things will probably improve the speed somewhat.

Thanks for all the advice, it’ll be very useful to know.

I’ve decided to use the inbuilt grass system now though. I just wish I could work out how the grass placement is stored so I could place it using a map.