2025-04-25 21:14:54 +09:00

107 lines
3.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF.Utils;
using UnityEngine;
namespace UniGLTF.MeshUtility
{
public static class BoneNormalizer
{
private static MeshAttachInfo CreateMeshInfo(Transform src)
{
// SkinnedMeshRenderer
var smr = src.GetComponent<SkinnedMeshRenderer>();
var mesh = MeshFreezer.NormalizeSkinnedMesh(smr);
if (mesh != null)
{
return new MeshAttachInfo
{
Mesh = mesh,
Materials = smr.sharedMaterials,
Bones = smr.bones,
RootBone = smr.rootBone,
};
}
// MeshRenderer
var mr = src.GetComponent<MeshRenderer>();
if (mr != null)
{
var dstMesh = MeshFreezer.NormalizeNoneSkinnedMesh(mr, true);
if (dstMesh != null)
{
return new MeshAttachInfo
{
Mesh = dstMesh,
Materials = mr.sharedMaterials,
};
}
}
return default;
}
/// <summary>
/// 各レンダラー(SkinnedMeshRenderer と MeshRenderer)にアタッチされた sharedMesh に対して
/// 回転とスケールを除去し、BlendShape の現状を焼き付けた版を作成する(まだ、アタッチしない)
/// </summary>
public static Dictionary<Transform, MeshAttachInfo> NormalizeHierarchyFreezeMesh(
GameObject go)
{
var result = new Dictionary<Transform, MeshAttachInfo>();
foreach (var src in go.transform.Traverse())
{
var info = CreateMeshInfo(src);
if (info != null)
{
result.Add(src, info);
}
}
return result;
}
public static void Replace(GameObject go, Dictionary<Transform, MeshAttachInfo> meshMap,
bool FreezeRotation, bool FreezeScaling)
{
var boneMap = go.transform.Traverse().ToDictionary(x => x, x => new EuclideanTransform(x.rotation, x.position));
// first, update hierarchy
foreach (var src in go.transform.Traverse())
{
var tr = boneMap[src];
if (FreezeScaling)
{
src.localScale = Vector3.one;
}
else
{
throw new NotImplementedException();
}
if (FreezeRotation)
{
src.rotation = Quaternion.identity;
}
else
{
src.rotation = tr.Rotation;
}
src.position = tr.Translation;
}
// second, replace mesh
foreach (var (src, tr) in boneMap)
{
if (meshMap.TryGetValue(src, out var info))
{
info.ReplaceMesh(src.gameObject);
}
}
}
}
}