Skip to content

Instantly share code, notes, and snippets.

@xwipeoutx
Last active September 5, 2024 05:41
Show Gist options
  • Save xwipeoutx/79451ccf465e513a196a8602bf01c14c to your computer and use it in GitHub Desktop.
Save xwipeoutx/79451ccf465e513a196a8602bf01c14c to your computer and use it in GitHub Desktop.
When working with FBX files, sometimes meshes inside them have the same name - which Unity will import in an undefined order/guid mapping. This causes all sorts of problems between platforms especially. This script applies a deterministic order (based on vert positions, triangles, etc.) to those as a post-processor step.
using System.Linq;
using UnityEditor;
using UnityEngine;
public class SaneMeshes : AssetPostprocessor
{
private void OnPostprocessModel(GameObject go)
{
Debug.Log("Post processing a model!");
var meshFilters = go.GetComponentsInChildren<MeshFilter>();
var meshesFiltersByMeshName = meshFilters.GroupBy(f => f.sharedMesh.name);
foreach (var grp in meshesFiltersByMeshName.Where(g => g.Count() > 1))
{
var sourceMeshFilters = grp.ToList();
var targetMeshFilters = sourceMeshFilters
.OrderBy(f => MeshHash(f.sharedMesh))
.Select(f =>
{
var copy = new Mesh();
CopyInto(copy, f.sharedMesh);
return new
{
Pos = f.transform.localPosition,
Rot = f.transform.localRotation,
Scale = f.transform.localScale,
Mesh = copy,
Original = f
};
})
.ToList();
var log = "Incides are now ";
foreach (var f in sourceMeshFilters)
{
log += targetMeshFilters.FindIndex(f2 => f2.Original == f) + ",";
}
Debug.Log(log);
for (var i = 0; i < sourceMeshFilters.Count; i++)
{
var sourceFilter = sourceMeshFilters[i];
var targetFilter = targetMeshFilters[i];
CopyInto(sourceFilter.sharedMesh, targetFilter.Mesh);
sourceFilter.transform.localPosition = targetFilter.Pos;
sourceFilter.transform.localRotation = targetFilter.Rot;
sourceFilter.transform.localScale = targetFilter.Scale;
}
}
}
private static void CopyInto(Mesh target, Mesh source)
{
target.CombineMeshes(new[]
{
new CombineInstance()
{
mesh = source
}
}, false, false, false);
target.RecalculateBounds();
}
private float MeshHash(Mesh mesh)
{
var hash = 0;
foreach (var vert in mesh.vertices)
{
var xNorm = Mathf.FloorToInt(vert.x * 1001);
var yNorm = Mathf.FloorToInt(-vert.y * 1007);
var zNorm = Mathf.FloorToInt(vert.z * 1013);
hash ^= xNorm ^ yNorm ^ zNorm;
}
foreach (var tri in mesh.triangles) hash ^= tri;
return hash;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment