using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using UnityEditor; using UnityEngine; public class SkinnedMeshFix : EditorWindow { private const char _splitChar = '/'; [MenuItem("ProTool/Skinned Mesh Fix")] public static void ShowWindow() { GetWindow(); } private GameObject _source; private GameObject _target; private void OnGUI() { GameObjectField("Correct Sample", ref _source); GUILayout.Space(5f); GameObjectField("To Fix", ref _target); GUILayout.Space(5f); if (GUILayout.Button("Fix Item", GUILayout.Width(200f))) { if (_source == null || _target == null) Debug.LogError("No gameObject to fix or the source is not set!"); else { var sourceRenderer = _source.GetComponentInChildren(); var targetRenderer = _target.GetComponentInChildren(); var targetMesh = targetRenderer.sharedMesh; if (sourceRenderer == null || targetRenderer == null) Debug.LogError("No SkinnedMeshRenderer found on one of the gameObjects!"); else if (targetMesh == null) Debug.LogError("Target gameObject has no mesh!"); else { var boneIndices = new List(); var error = false; var boneNames = new string[sourceRenderer.bones.Length]; for (var i = 0; i < boneNames.Length; i++) { var path = GetRelativeName(_source.transform, sourceRenderer.bones[i]); Debug.LogWarning(path); var targetBone = FindBone(_target.transform, path); if (targetBone == null) { Debug.LogWarning("Target doesn't contain the bone " + path); error = true; } else { int? targetId = null; for (var j = 0; j < targetRenderer.bones.Length; j++) { if (targetRenderer.bones[j] == targetBone) { targetId = j; break; } } if (targetId == null) { Debug.LogError( string.Format("Target doesn't attach the bone {0} in SkinnedMeshRenderer!", path)); error = true; } else { Debug.LogWarning("Bone Switch To " + i + " to " + targetId.Value); boneIndices.Add(new BoneIndex(i, targetId.Value)); } } if (error) break; } if (!error) { // Fix bones var bones = new Transform[boneIndices.Count]; var bindposes = new Matrix4x4[boneIndices.Count]; for (var i = 0; i < bones.Length; i++) { var id = boneIndices[i].target; bones[i] = targetRenderer.bones[id]; bindposes[i] = targetMesh.bindposes[id]; } targetRenderer.bones = bones; foreach (var bone in targetRenderer.bones) { Debug.LogWarning(bone.GetHierarchyName()); } // Fix Mesh var newMesh = new Mesh { vertices = targetMesh.vertices, uv = targetMesh.uv, uv2 = targetMesh.uv2, uv3 = targetMesh.uv3, uv4 = targetMesh.uv4, normals = targetMesh.normals, tangents = targetMesh.tangents, indexFormat = targetMesh.indexFormat, bindposes = bindposes, }; for (var i = 0; i < targetMesh.subMeshCount; i++) { newMesh.SetTriangles(targetMesh.GetTriangles(i), i); } var boneWeights = targetMesh.boneWeights; for (var i = 0; i < boneWeights.Length; i++) { var boneWeight = boneWeights[i]; if (boneWeight.weight0 > 0) { var id = GetConvertedIndex(boneWeight.boneIndex0, boneIndices); if (id == null) { boneWeight.weight0 = 0; boneWeight.boneIndex0 = 0; } else { boneWeight.boneIndex0 = id.Value; } } if (boneWeight.weight1 > 0) { var id = GetConvertedIndex(boneWeight.boneIndex1, boneIndices); if (id == null) { boneWeight.weight1 = 0; boneWeight.boneIndex1 = 0; } else { boneWeight.boneIndex1 = id.Value; } } if (boneWeight.weight2 > 0) { var id = GetConvertedIndex(boneWeight.boneIndex2, boneIndices); if (id == null) { boneWeight.weight2 = 0; boneWeight.boneIndex2 = 0; } else { boneWeight.boneIndex2 = id.Value; } } if (boneWeight.weight3 > 0) { var id = GetConvertedIndex(boneWeight.boneIndex3, boneIndices); if (id == null) { boneWeight.weight3 = 0; boneWeight.boneIndex3 = 0; } else { boneWeight.boneIndex3 = id.Value; } } boneWeights[i] = boneWeight; } newMesh.boneWeights = boneWeights; newMesh.UploadMeshData(true); var path = AssetDatabase.GetAssetPath(targetMesh); if (string.IsNullOrEmpty(path)) { error = true; Debug.LogError("Target mesh is not an asset in project!"); } else { path = path.MoveUp().Open(Path.GetFileNameWithoutExtension(targetMesh.name) + ".asset"); AssetDatabase.CreateAsset(newMesh, path); AssetDatabase.Refresh(); } if (!error) { targetRenderer.sharedMesh = newMesh; // Prefab Utility } } } } } } private int? GetConvertedIndex(int index, List indexList) { var boneIndex = indexList.Find(a => a.target == index); if (boneIndex == null) return null; else return boneIndex.source; } private void GameObjectField(string label, ref GameObject field) { field = EditorGUILayout.ObjectField(label, field, typeof(GameObject), true) as GameObject; } // ReSharper disable once SuggestBaseTypeForParameter private string GetRelativeName(Transform root, Transform target) { var builder = new StringBuilder(); builder.Append(target.name); while (target.parent != root) { target = target.parent; builder.Insert(0, target.name + _splitChar); } return builder.ToString(); } private Transform FindBone(Transform root, string relativePath) { var segments = relativePath.Split(_splitChar); for (var i = 0; i < segments.Length; i++) { root = root.Find(segments[i]); if (root == null) break; } return root; } private class BoneIndex { public readonly int source; public readonly int target; public BoneIndex(int source, int target) { this.source = source; this.target = target; } } }