mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-07-19 16:51:55 -05:00
Merge branch 'master' into fix/springbone_runtime_init_null
This commit is contained in:
commit
b7b44a2af5
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ namespace VRM
|
|||
if (settings.PoseFreeze)
|
||||
{
|
||||
// 正規化
|
||||
VRMBoneNormalizer.Execute(target, settings.ForceTPose);
|
||||
VRMBoneNormalizer.Execute(target, settings.ForceTPose, settings.FreezeMeshUseCurrentBlendShapeWeight);
|
||||
}
|
||||
|
||||
// 元のBlendShapeClipに変更を加えないように複製
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user