is there a more optimal way of drawing multiple meshes?

Hi there,

I’ve been working on ways to “grass and tree” non terrain meshes for months now, and so far the winner is using DrawMesh(), but this has problems.
The most noticeable being that one drawcall is needed for every mesh that’s rendered (I’m talking around 300 minimum here), and these could theoretically be all done with one drawcall.
Is there a way to “batch” these meshes and positions at runtime (they change as you move around the lanscape, so it has to be fast).
Here’s my function that renders the meshes.

void UpdateMultiMesh(){
	Vector3 vFront=pPos+gCam.forward;
	
	//moo
	pBigMesh=null;
	Vector3 vGrass;
	Camera vCam=gCam.camera;
	MaterialPropertyBlock vBlock=new MaterialPropertyBlock();
	float vSqrMaxDist=pMaxDist*pMaxDist;
	if(pGLength>0){
		for (int vGrassNum=0 ;vGrassNum<pGLength;vGrassNum++){
			vGrass=pGrasses[vGrassNum];
			Vector3 vDelta =vGrass-vFront;
			if (vDelta.sqrMagnitude<vSqrMaxDist){
				Graphics.DrawMesh(pMeshes[vGrassNum % pMeshCount],vGrass,pIdentity,pMats[pMatIDs[vGrassNum]],5,vCam,0,vBlock,false,true);
			}
		}
	}
}

I also tried building more complex single meshes by hand by adding vertices normals etc, but the speed was certainly no better. Again the code is below.

	void UpdateBigMesh(){
		if(pBigMesh==null){
			BuildBigMesh();
		}
		if(pGLength>0){
			GetBillboardVerts();	
			int vVert=0;
			int vVertRatio=4;
			if(pTris){
				vVertRatio=3;
			}
			Vector3[] vVerts=new Vector3[pGrasses.Length*vVertRatio];
			Vector3[] vNors=new Vector3[pGrasses.Length*vVertRatio];
			if(vVerts.Length>65000){
				Debug.Log("Too big! unity doesn't allow this :(");
				return;
			}
			for (int vGrassNum=0 ;vGrassNum<pGLength;vGrassNum++){
				pTempMesh=pMeshes[vGrassNum % pMeshCount];
				Vector3 vGrass=pGrasses[vGrassNum];
				vVert=vGrassNum*vVertRatio;
				pTempMesh.vertices.CopyTo(vVerts,vVert);
				pNormals.CopyTo(vNors,vVert);
				for(int vNum=0;vNum<vVertRatio;vNum++){
					vVerts[vVert+vNum]+=vGrass;
				}
			}
			pBigMesh.normals=vNors;
			pBigMesh.vertices=vVerts;
			int vMat=0;
			if(pMatID<pMats.Length){
				vMat=pMatID;
			}
			Graphics.DrawMesh(pBigMesh,Vector3.zero,pIdentity, pMats[vMat], 0);
		}
	}

Any pointers as to how to speed this up would be great, but the obvious thing seems be a queueing of all multi-meshes for just one draw call.

[Update: just figured out a combine meshes equivalent of the big mesh builder, but it’s actually slower than building by hand as above]

sharing :

	void UpdateOtherBigMesh(){
		//if(pBigMesh==null){
	        List<CombineInstance> combine = new List<CombineInstance>();
			CombineInstance vCombo=new CombineInstance();
	       Matrix4x4 vTrans=transform.localToWorldMatrix;
			
			int vVerts=0;
			Vector3 vPos;
	        for (int vGrassNum=0 ;vGrassNum<pGLength;vGrassNum++){
				pTempMesh=pMeshes[vGrassNum % pMeshCount];
				vVerts+=pTempMesh.vertices.Length;
				if(vVerts<65000){
		            vCombo.mesh = pTempMesh;
					vPos=pPosterGrasses[vGrassNum].pos;
					vTrans[0,3]=vPos.x;
					vTrans[1,3]=vPos.y;
					vTrans[2,3]=vPos.z;
		            vCombo.transform =vTrans;
		           	combine.Add(vCombo);
				}
	        }
			CombineInstance [] vRealCombo=combine.ToArray();
	        pBigMesh = new Mesh();
	        pBigMesh.CombineMeshes(vRealCombo);
		//}
		int vMat=0;
		if(pMatID<pMats.Length){
			vMat=pMatID;
		}
		Graphics.DrawMesh(pBigMesh,Vector3.zero,pIdentity, pMats[vMat], 0);
	}

Depending on what you’re doing for grass and foliage, you might want to consider going down the vertex or geometry shader route. Maybe assign UV2 to something that can be used to procedurally animate the verts in shader.