Skip to content

Instantly share code, notes, and snippets.

@megalon
Created November 12, 2023 06:23
Show Gist options
  • Select an option

  • Save megalon/c1fbeec94f0799c820e4c7b1503ba891 to your computer and use it in GitHub Desktop.

Select an option

Save megalon/c1fbeec94f0799c820e4c7b1503ba891 to your computer and use it in GitHub Desktop.
Unity custom model importing scripts for mods
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
//sorts transform bone indexes in skinned mesh renderers so that we can swap skinned meshes at runtime
public class AssetPostProcessorReorderBonesEditor : AssetPostprocessor
{
private string targetObjectName = "object-name-here";
private List<string> CorrectBoneOrder = new List<string> {
"root",
"superbody",
"body",
"L_arm",
// etc
};
void OnPostprocessModel(GameObject g)
{
if (!g.name.Equals(targetObjectName)) return;
Debug.Log("Changing bones for " + targetObjectName);
Process(g);
}
void Process(GameObject g)
{
SkinnedMeshRenderer rend = g.GetComponentInChildren<SkinnedMeshRenderer>();
if (rend == null)
{
Debug.LogWarning("Unable to find Renderer" + rend.name);
return;
}
var bones = new List<Transform>( new Transform[CorrectBoneOrder.Count]);
for (int i = 0; i < bones.Count; i++)
{
var bone = rend.bones[i];
bones[CorrectBoneOrder.IndexOf(bone.name)] = bone;
}
//record bone index mappings (richardf advice)
//build a Dictionary<int, int> that records the old bone index => new bone index mappings,
//then run through every vertex and just do boneIndexN = dict[boneIndexN] for each weight on each vertex.
Dictionary<int, int> remap = new Dictionary<int, int>();
for (int i = 0; i < rend.bones.Length; i++)
{
remap[i] = bones.IndexOf(rend.bones[i]);
}
//remap bone weight indexes
BoneWeight[] bw = rend.sharedMesh.boneWeights;
for (int i = 0; i < bw.Length; i++)
{
bw[i].boneIndex0 = remap[bw[i].boneIndex0];
bw[i].boneIndex1 = remap[bw[i].boneIndex1];
bw[i].boneIndex2 = remap[bw[i].boneIndex2];
bw[i].boneIndex3 = remap[bw[i].boneIndex3];
}
//remap bindposes
Matrix4x4[] bp = new Matrix4x4[rend.sharedMesh.bindposes.Length];
for (int i = 0; i < bp.Length; i++)
{
bp[remap[i]] = rend.sharedMesh.bindposes[i];
}
//assign new data
rend.bones = bones.ToArray();
rend.sharedMesh.boneWeights = bw;
rend.sharedMesh.bindposes = bp;
}
private static int CompareTransform(Transform A, Transform B)
{
return A.name.CompareTo(B.name);
}
}
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(SkinnedMeshRenderer))]
public class BoneViewerEditor : Editor
{
private SkinnedMeshRenderer skinnedMeshRenderer;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
skinnedMeshRenderer = (SkinnedMeshRenderer)target;
EditorGUILayout.Space();
EditorGUILayout.LabelField($"{skinnedMeshRenderer.bones.Length} Bones", EditorStyles.boldLabel);
// Display the bone names
foreach (Transform bone in skinnedMeshRenderer.bones)
{
EditorGUILayout.LabelField(bone.name);
}
EditorGUILayout.Space();
if (GUILayout.Button("Copy Bones to Clipboard"))
{
CopyBonesToClipboard();
}
}
private void CopyBonesToClipboard()
{
string boneList = "";
// Concatenate bone names
foreach (Transform bone in skinnedMeshRenderer.bones)
{
boneList += $"\"{bone.name}\",\n";
}
// Copy to clipboard
EditorGUIUtility.systemCopyBuffer = boneList;
Debug.Log("Bone list copied to clipboard.");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment