I started to find a way, I will update and clean up this answer as I go.
CombineInstance can take a transform matrix to set the transform on the mesh you want to combine. Unfortunately new Transform is not possible but luckily creating a transform matrix from scratch is as easy.
Matrix4x4 transformMatrix = new Matrix4x4();
//transformMatrix.SetTRS(position, quaternion, scale)
transformMatrix.SetTRS(new Vector3(0, 10, 0), Quaternion.Euler(-90, 0, 0), new Vector3(1, 1, 1));
To get the materials right we need to add the same mesh to the next CombineInstance index in the array for each subMesh with different materials.
for (int i = 0; i < customMesh.subMeshCount; i++)
{
combine[currentIndex + i].mesh = Instantiate(customMesh);
combine[currentIndex + i].transform = transformMatrix;
combine[currentIndex + i].subMeshIndex = i;
}
However, this means for each submesh we need to grow our materials list, even if the submeshes use the same materials. In my case, all my meshes share materials and I will end up with an array with many thousands of elements for each chunck this way.
The way I will probably fix/circumvent it is just use a texture to define different parts of the road so it has only one texture and one material. Same for tree's and for each chunck load all roads, then all tree's, etc. This does raise some issues:
- If I give each different road piece it's own texture I need to first place all road[0] then all road[1] etc. for each chunk.
- If I give each face it's unique texture space and later want to add an extra piece I need to shove my UV space around or add an additional material for that single piece.
Neither option is ideal.
Another way I can think of is doing shared material elements first. Like roads use concrete material for the sidewalks and asphalt material for the center. Now first do a run for all first (concrete) submesh roads then another run for second submeshes. But this is very ugly/hacky, not only you need to make sure all submesh indices share the same material. If you want to use the concrete material for buildings as well you either get a duplicate material entry again or somehow need to run that building (concrete) submesh right after the road (concrete) submesh.
Since it's very nice and common to work with large tileable materials or even just flat shaded colors without texture and reuse these textures/materials whenever you want I'm still looking for a solution for this.
The following would be nice, it does require some custom tweeking for some meshes.
material[0] = asphalt;
material[1] = concrete;
material[2] = wood;
//Roads
int matIndex = 0;
for (int i = 0; i < customMesh.subMeshCount; i++)
{
combine[currentIndex + i].mesh = Instantiate(customMesh);
combine[currentIndex + i].transform = transformMatrix;
//combine[currentIndex + i].subMeshIndex = i;
//Instead assign a material index.
combine[currentIndex + i].materialIndex = matIndex + i;
}
//building
int matIndex = 1;
for (int i = 0; i < customMesh.subMeshCount; i++)
{
combine[currentIndex + i].mesh = Instantiate(customMesh);
combine[currentIndex + i].transform = transformMatrix;
combine[currentIndex + i].materialIndex = matIndex + i;
}