Merge branch 'master' into fix/springbone_runtime_init_null

This commit is contained in:
ousttrue 2024-10-22 14:31:47 +09:00 committed by GitHub
commit b7b44a2af5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 115 additions and 69 deletions

View File

@ -300,7 +300,10 @@ namespace UniGLTF.MeshUtility
bool MeshFreezeGui()
{
return ToggleIsModified("BlendShapeRotationScaling", ref MeshUtility.FreezeBlendShapeRotationAndScaling);
var meshFreeze = ToggleIsModified("FreezeMesh", ref MeshUtility.FreezeMesh);
var meshFreezeKeepRotation = ToggleIsModified("FreezeMeshKeeprotation", ref MeshUtility.FreezeMeshKeepRotation);
var meshFreezeUseCurrentWeight = ToggleIsModified("FreezeMeshCurrentBlendShapeWeight", ref MeshUtility.FreezeMeshCurrentBlendShapeWeight);
return meshFreeze || meshFreezeKeepRotation || meshFreezeUseCurrentWeight;
}
protected virtual bool MeshIntegrateGui()

View File

@ -9,12 +9,12 @@ namespace UniGLTF.MeshUtility
{
public static class BoneNormalizer
{
private static MeshAttachInfo CreateMeshInfo(Transform src)
private static MeshAttachInfo CreateMeshInfo(Transform src, bool bakeCurrentBlendShape)
{
// SkinnedMeshRenderer
if (src.TryGetComponent<SkinnedMeshRenderer>(out var smr))
{
var mesh = MeshFreezer.NormalizeSkinnedMesh(smr);
var mesh = MeshFreezer.NormalizeSkinnedMesh(smr, bakeCurrentBlendShape);
if (mesh != null)
{
return new MeshAttachInfo
@ -50,12 +50,12 @@ namespace UniGLTF.MeshUtility
/// 回転とスケールを除去し、BlendShape の現状を焼き付けた版を作成する(まだ、アタッチしない)
/// </summary>
public static Dictionary<Transform, MeshAttachInfo> NormalizeHierarchyFreezeMesh(
GameObject go)
GameObject go, bool bakeCurrentBlendShape)
{
var result = new Dictionary<Transform, MeshAttachInfo>();
foreach (var src in go.transform.Traverse())
{
var info = CreateMeshInfo(src);
var info = CreateMeshInfo(src, bakeCurrentBlendShape);
if (info != null)
{
result.Add(src, info);
@ -65,7 +65,7 @@ namespace UniGLTF.MeshUtility
}
public static void Replace(GameObject go, Dictionary<Transform, MeshAttachInfo> meshMap,
bool FreezeRotation, bool FreezeScaling)
bool KeepRotation)
{
var boneMap = go.transform.Traverse().ToDictionary(x => x, x => new EuclideanTransform(x.rotation, x.position));
@ -73,23 +73,16 @@ namespace UniGLTF.MeshUtility
foreach (var src in go.transform.Traverse())
{
var tr = boneMap[src];
if (FreezeScaling)
{
src.localScale = Vector3.one;
}
else
{
throw new NotImplementedException();
}
src.localScale = Vector3.one;
if (FreezeRotation)
{
src.rotation = Quaternion.identity;
}
else
if (KeepRotation)
{
src.rotation = tr.Rotation;
}
else
{
src.rotation = Quaternion.identity;
}
src.position = tr.Translation;
}

View File

@ -18,12 +18,22 @@ namespace UniGLTF.MeshUtility
public class GltfMeshUtility
{
/// <summary>
/// Same as VRM-0 normalization
/// - Mesh
/// - Node
/// - InverseBindMatrices
/// v0.127.2
/// Mesh の bake。Hierarhcy の改変(scale/rotationの除去)。Binding行列の再作成
/// </summary>
public bool FreezeBlendShapeRotationAndScaling = false;
public bool FreezeMesh = false;
/// <summary>
/// v0.127.2
/// if false Same as VRM-0 normalization
/// </summary>
public bool FreezeMeshKeepRotation = false;
/// <summary>
/// v0.127.2
/// BlendShape の現状を base にする
/// </summary>
public bool FreezeMeshCurrentBlendShapeWeight = false;
public List<MeshIntegrationGroup> MeshIntegrationGroups = new List<MeshIntegrationGroup>();
@ -156,15 +166,15 @@ namespace UniGLTF.MeshUtility
public virtual (List<MeshIntegrationResult>, List<GameObject>) Process(
GameObject target, IEnumerable<MeshIntegrationGroup> groupCopy)
{
if (FreezeBlendShapeRotationAndScaling)
if (FreezeMesh)
{
// MeshをBakeする
var meshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(target);
var meshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(target, FreezeMeshCurrentBlendShapeWeight);
// - ヒエラルキーから回転・拡縮を除去する
// - BakeされたMeshで置き換える
// - bindPoses を再計算する
BoneNormalizer.Replace(target, meshMap, true, true);
BoneNormalizer.Replace(target, meshMap, FreezeMeshKeepRotation);
}
var newList = new List<GameObject>();

View File

@ -120,7 +120,7 @@ namespace UniGLTF.MeshUtility
return newBoneWeights;
}
public static Mesh NormalizeSkinnedMesh(SkinnedMeshRenderer src)
public static Mesh NormalizeSkinnedMesh(SkinnedMeshRenderer src, bool bakeCurrentBlendShape)
{
if (src == null
|| !src.enabled
@ -140,14 +140,41 @@ namespace UniGLTF.MeshUtility
AssignSingleBoneWeight(src);
}
var backcup = new List<float>();
for (int i = 0; i < src.sharedMesh.blendShapeCount; ++i)
{
backcup.Add(src.GetBlendShapeWeight(i));
}
// BakeMesh
var mesh = new Mesh
{
name = src.sharedMesh.name + ".baked"
};
// memo: BakeMesh(mesh, useScale) という第2引数がある
src.BakeMesh(mesh);
BakeBlendShapes(src, mesh);
if (bakeCurrentBlendShape)
{
// blendShape weight の現状を使用する
src.BakeMesh(mesh);
BakeBlendShapes(src, mesh, backcup);
}
else
{
// blendShape weight をすべて 0 clear する
for (int i = 0; i < src.sharedMesh.blendShapeCount; ++i)
{
src.SetBlendShapeWeight(i, 0.0f);
}
src.BakeMesh(mesh);
BakeBlendShapes(src, mesh, null);
}
// restore blendshape weights
for (int i = 0; i < backcup.Count; ++i)
{
src.SetBlendShapeWeight(i, backcup[i]);
}
mesh.boneWeights = src.sharedMesh.boneWeights;
// apply SkinnedMesh.transform rotation
@ -185,18 +212,11 @@ namespace UniGLTF.MeshUtility
src.sharedMesh = srcMesh;
}
private static void BakeBlendShapes(SkinnedMeshRenderer src, Mesh mesh)
/// <param name="blendShapeBase">basemesh の blendshape 状態</param>
private static void BakeBlendShapes(SkinnedMeshRenderer src, Mesh mesh, List<float> blendShapeBase)
{
var srcMesh = src.sharedMesh;
// clear blendShape always
var backcup = new List<float>();
for (int i = 0; i < srcMesh.blendShapeCount; ++i)
{
backcup.Add(src.GetBlendShapeWeight(i));
src.SetBlendShapeWeight(i, 0);
}
var meshVertices = mesh.vertices;
var meshNormals = mesh.normals;
var meshTangents = Array.Empty<Vector3>();
@ -237,7 +257,7 @@ namespace UniGLTF.MeshUtility
throw new Exception("different vertex count");
}
src.SetBlendShapeWeight(i, backcup[i]);
src.SetBlendShapeWeight(i, blendShapeBase == null ? 0 : blendShapeBase[i]);
Vector3[] vertices = blendShapeMesh.vertices;
@ -286,12 +306,6 @@ namespace UniGLTF.MeshUtility
}
}
}
// restore blendshape weights
for (int i = 0; i < backcup.Count; ++i)
{
src.SetBlendShapeWeight(i, backcup[i]);
}
}
public static Mesh NormalizeNoneSkinnedMesh(MeshRenderer srcRenderer, bool freezeRotation)

View File

@ -54,10 +54,16 @@ namespace UniGLTF
/// </summary>
public bool ExportUvSecondary;
[Tooltip("freeze mesh")]
public bool FreezeMesh = false;
[Tooltip("when freeze mesh, keep rotation")]
public bool FreezeMeshKeepRotation = false;
/// <summary>
/// FreezeBlendShape
/// </summary>
[Tooltip("freeze rotation and scale and blendshape")]
public bool FreezeMesh = false;
[Tooltip("when freeze mesh, blendShpae base use current weight")]
public bool FreezeMeshUseCurrentBlendShapeWeight = false;
}
}

View File

@ -237,10 +237,10 @@ namespace UniGLTF
// - BlendShape は現状がbakeされます
// - 回転とスケールが反映された新しい Mesh が作成されます
// - Transform の回転とスケールはクリアされます。world position を維持します
var newMeshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(Copy);
var newMeshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(Copy, m_settings.FreezeMeshUseCurrentBlendShapeWeight);
// SkinnedMeshRenderer.sharedMesh と MeshFilter.sharedMesh を新しいMeshで置き換える
BoneNormalizer.Replace(Copy, newMeshMap, true, true);
BoneNormalizer.Replace(Copy, newMeshMap, m_settings.FreezeMeshKeepRotation);
}
Nodes = Copy.transform.Traverse()

View File

@ -209,7 +209,7 @@ namespace VRM
if (settings.PoseFreeze)
{
// 正規化
VRMBoneNormalizer.Execute(target, settings.ForceTPose);
VRMBoneNormalizer.Execute(target, settings.ForceTPose, settings.FreezeMeshUseCurrentBlendShapeWeight);
}
// 元のBlendShapeClipに変更を加えないように複製

View File

@ -19,6 +19,12 @@ namespace VRM
[Tooltip("Require only first time")]
public bool PoseFreeze = true;
/// <summary>
/// FreezeBlendShape
/// </summary>
[Tooltip("when freeze mesh, blendShpae base use current weight")]
public bool FreezeMeshUseCurrentBlendShapeWeight = false;
/// <summary>
/// BlendShapeのシリアライズにSparseAccessorを使う
/// </summary>

View File

@ -43,11 +43,11 @@ namespace VRM
}
}
public static void Normalize()
public static void Normalize(bool bakeCurrentBlendShape)
{
var go = Selection.activeObject as GameObject;
VRMBoneNormalizer.Execute(go, true);
VRMBoneNormalizer.Execute(go, true, bakeCurrentBlendShape);
}
}
}

View File

@ -31,7 +31,7 @@ namespace VRM
[MenuItem(UserMenuPrefix + "/" + VRMHumanoidNormalizerMenu.MENU_NAME, true, 52)]
private static bool FreezeTPoseValidation() => VRMHumanoidNormalizerMenu.NormalizeValidation();
[MenuItem(UserMenuPrefix + "/" + VRMHumanoidNormalizerMenu.MENU_NAME, false, 52)]
private static void FreezeTPose() => VRMHumanoidNormalizerMenu.Normalize();
private static void FreezeTPose() => VRMHumanoidNormalizerMenu.Normalize(bakeCurrentBlendShape: true);
[MenuItem(UserMenuPrefix + "/" + VRMSpringBoneUtilityEditor.SAVE_MENU_NAME, true, 53)]

View File

@ -52,7 +52,8 @@ namespace VRM
/// </summary>
/// <param name="go">対象モデルのルート</param>
/// <param name="forceTPose">強制的にT-Pose化するか</param>
public static void Execute(GameObject go, bool forceTPose)
/// <param name="useCurrentBlendShapeWeight">BlendShape の現状をbakeするか</param>
public static void Execute(GameObject go, bool forceTPose, bool useCurrentBlendShapeWeight)
{
if (forceTPose)
{
@ -72,13 +73,12 @@ namespace VRM
}
// Transform の回転とスケールを Mesh に適用します。
// - BlendShape は現状がbakeされます
// - 回転とスケールが反映された新しい Mesh が作成されます
// - Transform の回転とスケールはクリアされます。world position を維持します
var newMeshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(go);
var newMeshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(go, useCurrentBlendShapeWeight);
// SkinnedMeshRenderer.sharedMesh と MeshFilter.sharedMesh を新しいMeshで置き換える
BoneNormalizer.Replace(go, newMeshMap, true, true);
BoneNormalizer.Replace(go, newMeshMap, false);
// 回転とスケールが除去された新しいヒエラルキーからAvatarを作る
Avatar newAvatar = default;

View File

@ -105,7 +105,7 @@ namespace VRM
// TODO: update: firstPerson offset
var (list, newList) = base.Process(target, copyGroup);
if (FreezeBlendShapeRotationAndScaling)
if (FreezeMesh)
{
Avatar newAvatar = null;
if (target.TryGetComponent<Animator>(out var animator))

View File

@ -30,6 +30,15 @@ namespace UniVRM10
[Tooltip("freeze rotation and scale and blendshape")]
public bool FreezeMesh = false;
[Tooltip("when freeze mesh, keep rotation")]
public bool FreezeMeshKeepRotation = false;
/// <summary>
/// FreezeBlendShape
/// </summary>
[Tooltip("when freeze mesh, blendShpae base use current weight")]
public bool FreezeMeshUseCurrentBlendShapeWeight = false;
public GltfExportSettings MeshExportSettings => new GltfExportSettings
{
UseSparseAccessorForMorphTarget = MorphTargetUseSparse,

View File

@ -297,10 +297,10 @@ namespace UniVRM10
// - BlendShape は現状がbakeされます
// - 回転とスケールが反映された新しい Mesh が作成されます
// - Transform の回転とスケールはクリアされます。world position を維持します
var newMeshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(root);
var newMeshMap = BoneNormalizer.NormalizeHierarchyFreezeMesh(root, m_settings.FreezeMeshUseCurrentBlendShapeWeight);
// SkinnedMeshRenderer.sharedMesh と MeshFilter.sharedMesh を新しいMeshで置き換える
BoneNormalizer.Replace(root, newMeshMap, true, true);
BoneNormalizer.Replace(root, newMeshMap, m_settings.FreezeMeshKeepRotation);
}
var converter = new UniVRM10.ModelExporter();

View File

@ -12,7 +12,9 @@ namespace UniVRM10
{
public Vrm10MeshUtility()
{
FreezeBlendShapeRotationAndScaling = true;
FreezeMesh = true;
FreezeMeshKeepRotation = true;
FreezeMeshCurrentBlendShapeWeight = true;
}
bool _generateFirstPerson = false;
@ -112,7 +114,7 @@ namespace UniVRM10
// TODO: update: firstPerson offset
var (list, newList) = base.Process(target, groupCopy);
if (FreezeBlendShapeRotationAndScaling)
if (FreezeMesh)
{
Avatar newAvatar = default;
if (target.TryGetComponent<Animator>(out var animator))

View File

@ -10,6 +10,9 @@ namespace VRM.RuntimeExporterSample
[SerializeField]
public bool UseNormalize = true;
[SerializeField]
public bool BakeBlendShapes = false;
GameObject m_model;
void OnGUI()
@ -29,7 +32,7 @@ namespace VRM.RuntimeExporterSample
if (GUILayout.Button("Export"))
{
Export(m_model, UseNormalize);
Export(m_model, UseNormalize, BakeBlendShapes);
}
}
@ -112,7 +115,7 @@ namespace VRM.RuntimeExporterSample
}
static void Export(GameObject model, bool useNormalize)
static void Export(GameObject model, bool useNormalize, bool bakeBlendShape)
{
//#if UNITY_STANDALONE_WIN
#if false
@ -125,7 +128,7 @@ namespace VRM.RuntimeExporterSample
return;
}
var bytes = useNormalize ? ExportCustom(model) : ExportSimple(model);
var bytes = useNormalize ? ExportCustom(model, false, bakeBlendShape) : ExportSimple(model);
File.WriteAllBytes(path, bytes);
Debug.LogFormat("export to {0}", path);
@ -138,10 +141,10 @@ namespace VRM.RuntimeExporterSample
return bytes;
}
static byte[] ExportCustom(GameObject exportRoot, bool forceTPose = false)
static byte[] ExportCustom(GameObject exportRoot, bool forceTPose, bool bakeBlendShape)
{
// normalize
VRMBoneNormalizer.Execute(exportRoot, forceTPose);
VRMBoneNormalizer.Execute(exportRoot, forceTPose, bakeBlendShape);
return ExportSimple(exportRoot);
}