implement FreezeScaling

This commit is contained in:
ousttrue 2023-10-25 21:50:06 +09:00
parent 476c35433a
commit ced5dc8918
4 changed files with 99 additions and 50 deletions

View File

@ -11,36 +11,35 @@ namespace UniGLTF.MeshUtility
{
public delegate Avatar CreateAvatarFunc(GameObject original, GameObject normalized, Dictionary<Transform, Transform> boneMap);
static (GameObject, Dictionary<Transform, Transform>) NormalizeHierarchy(GameObject go, CreateAvatarFunc createAvatar)
public static (GameObject, Dictionary<Transform, Transform>) CreateNormalizedHierarchy(GameObject go,
bool removeScaling = true,
bool removeRotation = true)
{
var boneMap = new Dictionary<Transform, Transform>();
//
// 回転・スケールの無いヒエラルキーをコピーする
//
var normalized = new GameObject(go.name + "(normalized)");
normalized.transform.position = go.transform.position;
CopyAndBuild(go.transform, normalized.transform, boneMap);
//
// 新しいヒエラルキーからAvatarを作る
//
if (removeScaling && removeRotation)
{
var animator = normalized.AddComponent<Animator>();
var avatar = createAvatar(go, normalized, boneMap);
avatar.name = go.name + ".normalized";
animator.avatar = avatar;
RemoveScaleAndRotationRecursive(go.transform, normalized.transform, boneMap);
}
else if (removeScaling)
{
RemoveScaleAndRotationRecursive(go.transform, normalized.transform, boneMap);
}
else if (removeRotation)
{
throw new NotImplementedException();
}
else
{
throw new ArgumentNullException();
}
return (normalized, boneMap);
}
/// <summary>
/// 回転とスケールを除去したヒエラルキーをコピーする。
/// </summary>
/// <param name="src"></param>
/// <param name="dst"></param>
static void CopyAndBuild(Transform src, Transform dst, Dictionary<Transform, Transform> boneMap)
static void RemoveScaleRecursive(Transform src, Transform dst, Dictionary<Transform, Transform> boneMap)
{
boneMap[src] = dst;
@ -50,9 +49,27 @@ namespace UniGLTF.MeshUtility
{
var dstChild = new GameObject(child.name);
dstChild.transform.SetParent(dst);
dstChild.transform.position = child.position; // copy position only
dstChild.transform.position = child.position; // copy world position
dstChild.transform.rotation = child.localToWorldMatrix.rotation; // copy world rotation
// scale is removed
RemoveScaleRecursive(child, dstChild.transform, boneMap);
}
}
}
CopyAndBuild(child, dstChild.transform, boneMap);
static void RemoveScaleAndRotationRecursive(Transform src, Transform dst, Dictionary<Transform, Transform> boneMap)
{
boneMap[src] = dst;
foreach (Transform child in src)
{
if (child.gameObject.activeSelf)
{
var dstChild = new GameObject(child.name);
dstChild.transform.SetParent(dst);
dstChild.transform.position = child.position; // copy world position
RemoveScaleAndRotationRecursive(child, dstChild.transform, boneMap);
}
}
}
@ -489,12 +506,12 @@ namespace UniGLTF.MeshUtility
/// <param name="bakeCurrentBlendShape">BlendShapeを0クリアするか否か。false の場合 BlendShape の現状を Bake する</param>
/// <param name="createAvatar">Avatarを作る関数</param>
/// <returns></returns>
public static (GameObject, Dictionary<Transform, Transform>) Execute(GameObject go, CreateAvatarFunc createAvatar)
public static (GameObject, Dictionary<Transform, Transform>) Execute(GameObject go)
{
//
// 正規化されたヒエラルキーを作る
//
var (normalized, boneMap) = NormalizeHierarchy(go, createAvatar);
var (normalized, boneMap) = CreateNormalizedHierarchy(go);
//
// 各メッシュから回転・スケールを取り除いてBinding行列を再計算する

View File

@ -5,6 +5,7 @@ using UnityEngine;
using System;
using System.Linq;
using System.Collections.Generic;
using UniGLTF.Utils;
namespace UniHumanoid
@ -271,5 +272,42 @@ namespace UniHumanoid
return false;
}
#endif
public static void AddAnimator(GameObject _src,
GameObject dst,
IDictionary<Transform, Transform> boneMap,
Action<AvatarDescription> modAvatarDesc = null)
{
var src = _src.GetComponent<Animator>();
var srcHumanBones = CachedEnum.GetValues<HumanBodyBones>()
.Where(x => x != HumanBodyBones.LastBone)
.Select(x => new { Key = x, Value = src.GetBoneTransform(x) })
.Where(x => x.Value != null)
;
var map =
srcHumanBones
.Where(x => boneMap.ContainsKey(x.Value))
.ToDictionary(x => x.Key, x => boneMap[x.Value])
;
var animator = dst.AddComponent<Animator>();
if (animator == null)
{
animator = dst.AddComponent<Animator>();
}
var avatarDescription = UniHumanoid.AvatarDescription.Create();
if (modAvatarDesc != null)
{
modAvatarDesc(avatarDescription);
}
avatarDescription.SetHumanBones(map);
var avatar = avatarDescription.CreateAvatar(dst.transform);
avatar.name = dst.name;
animator.avatar = avatar;
}
}
}

View File

@ -65,31 +65,13 @@ namespace VRM
}
}
//
// 正規化されたヒエラルキーを作る
//
var (normalized, bMap) = BoneNormalizer.Execute(go, (_src, dst, boneMap) =>
var (normalized, bMap) = BoneNormalizer.Execute(go);
// 新しいヒエラルキーからAvatarを作る
UniHumanoid.AvatarDescription.AddAnimator(go, normalized, bMap, avatarDescription =>
{
var src = _src.GetComponent<Animator>();
var srcHumanBones = CachedEnum.GetValues<HumanBodyBones>()
.Where(x => x != HumanBodyBones.LastBone)
.Select(x => new { Key = x, Value = src.GetBoneTransform(x) })
.Where(x => x.Value != null)
;
var map =
srcHumanBones
.Where(x => boneMap.ContainsKey(x.Value))
.ToDictionary(x => x.Key, x => boneMap[x.Value])
;
if (dst.GetComponent<Animator>() == null)
{
var animator = dst.AddComponent<Animator>();
}
var vrmHuman = go.GetComponent<VRMHumanoidDescription>();
var avatarDescription = AvatarDescription.Create();
if (vrmHuman != null && vrmHuman.Description != null)
{
avatarDescription.armStretch = vrmHuman.Description.armStretch;
@ -101,9 +83,6 @@ namespace VRM
avatarDescription.feetSpacing = vrmHuman.Description.feetSpacing;
avatarDescription.hasTranslationDoF = vrmHuman.Description.hasTranslationDoF;
}
avatarDescription.SetHumanBones(map);
var avatar = avatarDescription.CreateAvatar(dst.transform);
return avatar;
});
CopyVRMComponents(go, normalized, bMap);

View File

@ -1,5 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using UniGLTF.MeshUtility;
using UniHumanoid;
using UnityEngine;
namespace UniVRM10
@ -118,9 +120,22 @@ namespace UniVRM10
}
}
public void Process()
public void Process(GameObject go)
{
Debug.Log("Process !");
// TODO: UNDO
// 正規化されたヒエラルキーを作る
var (normalized, boneMap) = BoneNormalizer.CreateNormalizedHierarchy(go,
removeScaling: FreezeScaling,
removeRotation: FreezeRotation);
// TODO: update: spring
// TODO: update: constraint
// TODO: update: firstPoint offset
AvatarDescription.AddAnimator(go, normalized, boneMap);
// TODO: write back normalized transform to boneMap
}
}
}