Last active
December 9, 2020 00:11
-
-
Save gamemachine/77b57323e97d46512461a0791e79d0e5 to your computer and use it in GitHub Desktop.
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; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace AiGame | |
{ | |
// Design is that you have a target with a SkinnedMeshRenderer and bone hierarchy. | |
// You provide a list of input SkinnedMeshRenderer's that use the same bone hierarchy as the target | |
// Bones and bone weights will be mapped to the target. | |
[Serializable] | |
public class AvatarMeshCombiner | |
{ | |
public SkinnedMeshRenderer Target; | |
public Transform TargetRig; | |
public List<SkinnedMeshRenderer> Inputs = new List<SkinnedMeshRenderer>(); | |
private Dictionary<string, int> BoneIndexMap = new Dictionary<string, int>(); | |
private List<Transform> BonesList = new List<Transform>(); | |
private List<BoneWeight> BoneWeights = new List<BoneWeight>(); | |
private List<CombineInstance> CombineInstances = new List<CombineInstance>(); | |
private List<Matrix4x4> BindPoses = new List<Matrix4x4>(); | |
public void Build() | |
{ | |
BoneIndexMap.Clear(); | |
BonesList.Clear(); | |
BoneWeights.Clear(); | |
CombineInstances.Clear(); | |
BindPoses.Clear(); | |
BuildBones(); | |
for (int i = 0; i < Inputs.Count; i++) | |
{ | |
SkinnedMeshRenderer smr = Inputs[i]; | |
if (!smr.gameObject.activeSelf) | |
{ | |
continue; | |
} | |
Transform[] meshBones = smr.bones; | |
BoneWeight[] meshBoneweight = smr.sharedMesh.boneWeights; | |
for (int j = 0; j < meshBoneweight.Length; ++j) | |
{ | |
BoneWeight bWeight = meshBoneweight[j]; | |
bWeight.boneIndex0 = GetBoneIndex(meshBones[bWeight.boneIndex0].name); | |
bWeight.boneIndex1 = GetBoneIndex(meshBones[bWeight.boneIndex1].name); | |
bWeight.boneIndex2 = GetBoneIndex(meshBones[bWeight.boneIndex2].name); | |
bWeight.boneIndex3 = GetBoneIndex(meshBones[bWeight.boneIndex3].name); | |
BoneWeights.Add(bWeight); | |
} | |
for(int j=0;j<smr.sharedMesh.subMeshCount;j++) | |
{ | |
CombineInstance ci = new CombineInstance(); | |
ci.mesh = smr.sharedMesh; | |
ci.subMeshIndex = j; | |
ci.transform = smr.transform.localToWorldMatrix; | |
CombineInstances.Add(ci); | |
} | |
} | |
foreach(var bone in BonesList) | |
{ | |
BindPoses.Add(bone.worldToLocalMatrix * Target.transform.worldToLocalMatrix); | |
} | |
Target.sharedMesh = new Mesh(); | |
Target.sharedMesh.CombineMeshes(CombineInstances.ToArray(), true, true); | |
//Debug.LogFormat("boneweights {0} vertices {1} bones {2}", boneWeights.Count, Target.sharedMesh.vertices.Length, BonesList.Count); | |
Target.bones = BonesList.ToArray(); | |
Target.sharedMesh.boneWeights = BoneWeights.ToArray(); | |
Target.sharedMesh.bindposes = BindPoses.ToArray(); | |
Target.sharedMesh.RecalculateBounds(); | |
} | |
// Create a unique bone list and a map of bone names to their index. Using the target rig. | |
// Then for the combined mesh we remap the boneweight bone indexes to the target bones. | |
private void BuildBones() | |
{ | |
var targetBones = TargetRig.GetComponentsInChildren<Transform>(); | |
Dictionary<string, Transform> targetMap = new Dictionary<string, Transform>(); | |
foreach (var targetBone in targetBones) | |
{ | |
targetMap[targetBone.name] = targetBone; | |
} | |
int boneIndex = 0; | |
foreach (var smr in Inputs) | |
{ | |
var bones = smr.bones; | |
foreach (var bone in bones) | |
{ | |
if (!BoneIndexMap.ContainsKey(bone.name)) | |
{ | |
Transform targetBone = targetMap[bone.name]; | |
BonesList.Add(targetBone); | |
BoneIndexMap[bone.name] = boneIndex; | |
boneIndex++; | |
} | |
} | |
} | |
} | |
private int GetBoneIndex(string bone) | |
{ | |
if (BoneIndexMap.TryGetValue(bone, out int index)) | |
{ | |
return index; | |
} | |
else | |
{ | |
return 0; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment