Last active
September 5, 2024 05:41
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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