Skip to content

Instantly share code, notes, and snippets.

@kiosion
Last active December 22, 2023 23:31
Show Gist options
  • Save kiosion/9cac71f965fc560e1342724005a59d87 to your computer and use it in GitHub Desktop.
Save kiosion/9cac71f965fc560e1342724005a59d87 to your computer and use it in GitHub Desktop.
Unity script to reassign mesh weights to new armature
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
public class ArmatureAssignment: EditorWindow
{
private int MeshCount = 1;
private List<SkinnedMeshRenderer> Meshes = new List<SkinnedMeshRenderer>();
private Transform NewArmature;
private bool IncludeInactiveBones = true;
private bool ContinueOnMissingBones = true;
private string RootBoneName = "Hips";
private string Status = "Waiting for input";
[MenuItem("Kio/ArmatureAssignment")]
static void Init()
{
ArmatureAssignment window = EditorWindow.GetWindow(typeof(ArmatureAssignment)) as ArmatureAssignment;
window?.Show();
}
void OnGUI()
{
GUILayout.Label("Reassign mesh bones to the selected Armature (Create a backup first!)");
GUILayout.Box("", new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.Height(1) });
this.MeshCount = EditorGUILayout.IntField("Mesh Count ", this.MeshCount);
while (this.MeshCount > this.Meshes.Count)
{
this.Meshes.Add(null);
}
while (this.MeshCount < this.Meshes.Count)
{
this.Meshes.RemoveAt(this.Meshes.Count - 1);
}
for (int i = 0; i < this.MeshCount; ++i)
{
this.Meshes[i] = EditorGUILayout.ObjectField($"Mesh {i}", this.Meshes[i], typeof(SkinnedMeshRenderer), true) as SkinnedMeshRenderer;
}
this.NewArmature = EditorGUILayout.ObjectField("New Armature", this.NewArmature, typeof(Transform), true) as Transform;
this.RootBoneName = EditorGUILayout.TextField("Root Bone Name", this.RootBoneName);
this.IncludeInactiveBones = EditorGUILayout.Toggle("Include inactive bones", this.IncludeInactiveBones);
this.ContinueOnMissingBones = EditorGUILayout.Toggle("Continue on missing bones", this.ContinueOnMissingBones);
if (GUILayout.Button("Execute"))
{
if (this.NewArmature != null && this.Meshes != null && !string.IsNullOrWhiteSpace(this.RootBoneName))
{
this.Status = "OK";
for (int i = 0; i < this.MeshCount; ++i)
{
Reassign(this.Meshes[i]);
}
if (this.Status == "OK")
{
this.Status = "Done";
}
}
else
{
this.Status = "Missing arguments";
}
NewArmature = null;
}
EditorGUILayout.Separator();
EditorGUILayout.TextField("Status", this.Status);
}
private void Reassign(SkinnedMeshRenderer mesh)
{
if (this.NewArmature.Find(this.RootBoneName) == null)
{
this.Status = "Root bone not found";
return;
}
bool hasMissingBones = false;
Transform originalRootBone = mesh.rootBone;
Transform[] originalBones = mesh.bones;
Transform[] newBones = mesh.bones;
Transform[] children = this.NewArmature.GetComponentsInChildren<Transform>(this.IncludeInactiveBones);
mesh.rootBone = this.NewArmature.Find(this.RootBoneName);
for (int i = 0; i < newBones.Length; ++i)
{
Transform foundBone = children.FirstOrDefault(c => c.name == newBones[i].name);
if (foundBone == null)
{
hasMissingBones = true;
if (!this.ContinueOnMissingBones)
{
Debug.LogError($"Bone {newBones[i].name} not found in new armature, aborting");
return;
}
Debug.LogWarning($"Bone {newBones[i].name} not found in new armature, removing from mesh");
newBones[i] = null;
}
newBones[i] = foundBone;
}
if (hasMissingBones && !this.ContinueOnMissingBones)
{
this.Status = "Bone not found";
mesh.bones = originalBones;
mesh.rootBone = originalRootBone;
return;
}
mesh.bones = newBones;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment