I'm working on a voxel based game, where destructible structures are made out of cubes. (Some of them has 3000 voxels)
I solved the framerate issues by combining them, but after making it able to handle multiple materials, calling the method causes a framerate drop.
- And it's annoying during runtime, because currently it recombines the whole structure when a voxel is changed (changed material, destroyed voxel, etc).
One plan of mine is to decomposite the structures into smaller chunks, and only recombine the affected chunks instead of the whole structure.
- This increases drawcalls, but decreases framerate drops. By finding a good chunk size and chunk "making" heuristic, it would work I think.
My other plan is to modify the combined mesh based on the affected voxels.
For example when a voxel is destroyed, find its vertices in the combined mesh, and remove them. Or change those faces' material, etc.
But I don't know how to do this.
The bottleneck of my mesh combining algorithm is this:
private static Mesh CombineMeshes(MeshFilter[] meshFilters, List<Material> materials)
{
// Each material will have a mesh for it.
var subMeshes = new List<Mesh>();
foreach (var material in materials)
{
// Make a combiner for each (sub)mesh that is mapped to the right material.
var combiners = new List<CombineInstance>();
foreach (var meshFilter in meshFilters)
{
// The filter doesn't know what materials are involved, get the renderer.
var renderer = meshFilter.GetComponent<MeshRenderer>(); // <-- (Easy optimization is possible here, give it a try!)
// Let's see if their materials are the one we want right now.
var sharedMaterials = renderer.sharedMaterials;
for (int i = 0; i < sharedMaterials.Length; i++)
{
var sharedMaterial = sharedMaterials[i];
if (sharedMaterial != material || sharedMaterial == null)
continue;
// This submesh is the material we're looking for right now.
CombineInstance ci = new CombineInstance();
ci.mesh = meshFilter.sharedMesh;
ci.subMeshIndex = 0; //With zero it works; with "i", every voxel in the structure will have every damagelayer.
ci.transform = meshFilter.transform.localToWorldMatrix;
combiners.Add(ci);
}
}
// Flatten into a single mesh.
var mesh = new Mesh();
mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
mesh.CombineMeshes(combiners.ToArray(), true);
subMeshes.Add(mesh);
}
foreach (var meshFilter in meshFilters)
{
meshFilter.GetComponent<MeshRenderer>().enabled = false;
}
// The final mesh: combine all the material-specific meshes as independent submeshes.
var finalCombiners = new List<CombineInstance>();
foreach (var mesh in subMeshes)
{
CombineInstance ci = new CombineInstance();
ci.mesh = mesh;
ci.subMeshIndex = 0;
ci.transform = Matrix4x4.identity;
finalCombiners.Add(ci);
}
var finalMesh = new Mesh();
finalMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
finalMesh.CombineMeshes(finalCombiners.ToArray(), false);
return finalMesh;
}
Could you recommend something? Thanks!