I was wondering if there is anyone who has built a script for combining meshes and their textures into atlases while also modifying the UVs to fit the atlas.
In this way I could build meshes and have they use their own textures (one texture per mesh) and then in Unity combine all textures and meshes that uses the same type of shader into one. Would just be easier to work in that way while also keeping the optimizations of texture altasing.
So the script would have to be able to combine meshes, their textures and modify their UVs and change all meshes to use the same material.
Maybe this is just a stupid idea, just something I thought might be nice.
I did something like this for our character creator. There’s a lot of moving parts involved, but I’ll try to show you the relevant parts:
Part is just an enum to determine which character part to use, which turns into an index into the texture atlas.
Any part potentially shows skin, so we have an edge case for those UV offsets.
Once you’ve offset all parts used you can do your CombineMeshes() call as normal. Make sure to pass true as the second argument so it flattens everything into a single material.
I hope this helps!
void OffsetUvs(SkinnedMeshRenderer partRenderer, Part part, TextureAtlas atlas) {
var uvOffsetMesh = (Mesh)Instantiate(partRenderer.sharedMesh);
var skinIndex = -1;
var materialIndex = 0;
foreach(var material in (Application.isPlaying ? partRenderer.materials : partRenderer.sharedMaterials)) {
if(material.name.ToLower().Contains("body")) {
skinIndex = materialIndex;
break;
}
++materialIndex;
}
var partIndex = -1;
switch(part) {
case Part.Head:
partIndex = 1;
break;
case Part.Torso:
partIndex = 2;
break;
case Part.Legs:
partIndex = 3;
break;
case Part.Feet:
partIndex = 4;
break;
}
var skinUvIndexes = new List<int>();
var uvs = uvOffsetMesh.uv;
0.UpTo(uvOffsetMesh.subMeshCount - 1, i => {
uvOffsetMesh.GetTriangles(i).Each(vertexIndex => {
if(i == skinIndex) skinUvIndexes.Add(vertexIndex);
});
});
var uvIndex = 0;
uvs = uvs.Select(uv => {
if(skinIndex > -1 && skinUvIndexes.Contains(uvIndex)) {
uv = new Vector2(uv.x.MapToRange(0f, 1f, atlas.Dimensions[skinIndex].xMin, atlas.Dimensions[skinIndex].xMax),
uv.y.MapToRange(0f, 1f, atlas.Dimensions[skinIndex].yMin, atlas.Dimensions[skinIndex].yMax));
}
else {
uv = new Vector2(uv.x.MapToRange(0f, 1f, atlas.Dimensions[partIndex].xMin, atlas.Dimensions[partIndex].xMax),
uv.y.MapToRange(0f, 1f, atlas.Dimensions[partIndex].yMin, atlas.Dimensions[partIndex].yMax));
}
++uvIndex;
return uv;
}).ToArray();
uvOffsetMesh.uv = uvs;
partRenderer.sharedMesh = uvOffsetMesh;
}
Thanks!
Also while checking over this one more time I found a tool on the asset store that does this, I haven’t tried it yet but I will. So if anyone wants the same tool check out,
It’s $55 but it might be worth it on larger projects.