diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index 73610670f..ed590ef40 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -2,6 +2,7 @@ using UnityEditor; using UnityEngine; using UniGLTF.M17N; +using UniGLTF; namespace VRM @@ -9,7 +10,6 @@ namespace VRM public class VrmMeshIntegratorWizard : UniGLTF.MeshUtility.MeshUtilityDialog { public new const string MENU_NAME = "VRM 0.x MeshUtility"; - public new static void OpenWindow() { var window = @@ -17,29 +17,36 @@ namespace VRM window.titleContent = new GUIContent(MENU_NAME); window.Show(); } + protected override void Validate() + { + base.Validate(); + if (_exportTarget.GetComponent() == null) + { + _validations.Add(Validation.Error("target is not vrm1")); + return; + } + } - // void Integrate() - // { - // // 統合 - // var excludes = m_excludes.Where(x => x.Exclude).Select(x => x.Mesh); - // var results = Integrate(copy, excludes, m_separateByBlendShape); + VrmMeshUtility _meshUtil; + VrmMeshUtility VrmMeshUtility + { + get + { + if (_meshUtil == null) + { + _meshUtil = new VrmMeshUtility(); + } + return _meshUtil; + } + } + protected override UniGLTF.MeshUtility.GltfMeshUtility MeshUtility => VrmMeshUtility; - // } - - // static List Integrate(GameObject root, IEnumerable excludes, bool separateByBlendShape) - // { - // var results = new List(); - // if (separateByBlendShape) - // { - // results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithoutBlendShape, excludes: excludes)); - // results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.OnlyWithBlendShape, excludes: excludes)); - // } - // else - // { - // results.Add(MeshIntegratorUtility.Integrate(root, onlyBlendShapeRenderers: MeshEnumerateOption.All, excludes: excludes)); - // } - // return results; - // } + protected override bool MeshIntegrateGui() + { + var firstPerson = ToggleIsModified("FirstPerson == AUTO の生成", ref MeshUtility.GenerateMeshForFirstPersonAuto); + var mod = base.MeshIntegrateGui(); + return firstPerson || mod; + } protected override void DialogMessage() { diff --git a/Assets/VRM/Runtime/FirstPerson/VRMFirstPerson.cs b/Assets/VRM/Runtime/FirstPerson/VRMFirstPerson.cs index 5f9e6a3fd..4bd4ff060 100644 --- a/Assets/VRM/Runtime/FirstPerson/VRMFirstPerson.cs +++ b/Assets/VRM/Runtime/FirstPerson/VRMFirstPerson.cs @@ -367,6 +367,17 @@ namespace VRM } } + /// + /// for MeshUtility interface + /// + public Mesh ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) + { + SetVisibilityFunc dummy = (Renderer renderer, bool firstPerson, bool thirdPerson) => + { + }; + return CreateHeadlessModel(smr, FirstPersonBone, dummy); + } + void OnDestroy() { foreach (var mesh in m_headlessMeshes) diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs new file mode 100644 index 000000000..62ffd4187 --- /dev/null +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniHumanoid; +using UnityEngine; + + +namespace VRM +{ + public class VrmMeshUtility : UniGLTF.MeshUtility.GltfMeshUtility + { + bool _generateFirstPerson = false; + protected override List CopyMeshIntegrationGroups() + { + var copy = new List(); + _generateFirstPerson = false; + if (GenerateMeshForFirstPersonAuto) + { + foreach (var g in MeshIntegrationGroups) + { + if (g.Name == "auto") + { + _generateFirstPerson = true; + // 元のメッシュを三人称に変更 + copy.Add(new UniGLTF.MeshUtility.MeshIntegrationGroup + { + Name = FirstPersonFlag.ThirdPersonOnly.ToString(), + Renderers = g.Renderers.ToList(), + }); + } + copy.Add(g); + } + } + else + { + copy.AddRange(MeshIntegrationGroups); + } + return copy; + } + + protected override + (UniGLTF.MeshUtility.MeshIntegrationResult, GameObject[]) Integrate( + GameObject empty, + UniGLTF.MeshUtility.MeshIntegrationGroup group) + { + var (result, newList) = base.Integrate(empty, group); + + if (_generateFirstPerson && group.Name == nameof(FirstPersonFlag.Auto)) + { + // Mesh 統合の後処理 + // FirstPerson == "auto" の場合に + // 頭部の無いモデルを追加で作成する + Debug.Log("generateFirstPerson"); + if (result.Integrated.Mesh != null) + { + // BlendShape 有り + _ProcessFirstPerson(_vrmInstance.FirstPersonBone, result.Integrated.IntegratedRenderer); + } + if (result.IntegratedNoBlendShape.Mesh != null) + { + // BlendShape 無しの方 + _ProcessFirstPerson(_vrmInstance.FirstPersonBone, result.IntegratedNoBlendShape.IntegratedRenderer); + } + } + + return (result, newList); + } + + private void _ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) + { + var mesh = _vrmInstance.ProcessFirstPerson(firstPersonBone, smr); + if (mesh != null) + { + smr.sharedMesh = mesh; + smr.name = "auto.headless"; + } + else + { + Debug.LogWarning("no result"); + } + } + + VRMFirstPerson _vrmInstance = null; + /// + /// glTF に比べて Humanoid や FirstPerson の処理が追加される + /// + public override (List, List) Process(GameObject go) + { + _vrmInstance = go.GetComponent(); + if (_vrmInstance == null) + { + throw new ArgumentException(); + } + + if (ForceUniqueName) + { + throw new NotImplementedException(); + + // 必用? + var animator = go.GetComponent(); + var newAvatar = AvatarDescription.RecreateAvatar(animator); + animator.avatar = newAvatar; + } + + // TODO: update: spring + // TODO: update: constraint + // TODO: update: firstPerson offset + var (list, newList) = base.Process(go); + + if (FreezeBlendShape || FreezeRotation || FreezeScaling) + { + var animator = go.GetComponent(); + var newAvatar = AvatarDescription.RecreateAvatar(animator); + animator.avatar = newAvatar; + } + + return (list, newList); + } + + public override void UpdateMeshIntegrationGroups(GameObject root) + { + if (root == null) + { + return; + } + var vrm1 = root.GetComponent(); + if (vrm1 == null) + { + return; + } + foreach (var a in vrm1.Renderers) + { + var g = _GetOrCreateGroup(a.FirstPersonFlag.ToString()); + g.Renderers.Add(a.Renderer); + } + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta new file mode 100644 index 000000000..851cb3e0c --- /dev/null +++ b/Assets/VRM/Runtime/SkinnedMeshUtility/VrmMeshUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb346da8b7688c74eb627bebe1b21060 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index d9e17f84a..2b8f039fb 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using UniGLTF.MeshUtility; using UniHumanoid; using UnityEngine; -using UnityEngine.Rendering; + namespace UniVRM10 { @@ -46,27 +45,51 @@ namespace UniVRM10 { var (result, newList) = base.Integrate(empty, group); - if (_generateFirstPerson && group.Name == "auto") + if (_generateFirstPerson && group.Name == nameof(UniGLTF.Extensions.VRMC_vrm.FirstPersonType.auto)) { + // Mesh 統合の後処理 + // FirstPerson == "auto" の場合に + // 頭部の無いモデルを追加で作成する Debug.Log("generateFirstPerson"); if (result.Integrated.Mesh != null) { - _ProcessFirstPerson(_vrmInstance, result.Integrated); + // BlendShape 有り + _ProcessFirstPerson(_vrmInstance.Humanoid.Head, result.Integrated.IntegratedRenderer); } if (result.IntegratedNoBlendShape.Mesh != null) { - _ProcessFirstPerson(_vrmInstance, result.IntegratedNoBlendShape); + // BlendShape 無しの方 + _ProcessFirstPerson(_vrmInstance.Humanoid.Head, result.IntegratedNoBlendShape.IntegratedRenderer); } } return (result, newList); } + private void _ProcessFirstPerson(Transform firstPersonBone, SkinnedMeshRenderer smr) + { + var task = VRM10ObjectFirstPerson.CreateErasedMeshAsync( + smr, + firstPersonBone, + new VRMShaders.ImmediateCaller()); + task.Wait(); + var mesh = task.Result; + if (mesh != null) + { + smr.sharedMesh = mesh; + smr.name = "auto.headless"; + } + else + { + Debug.LogWarning("no result"); + } + } + Vrm10Instance _vrmInstance = null; /// /// glTF に比べて Humanoid や FirstPerson の処理が追加される /// - public override (List, List) Process(GameObject go) + public override (List, List) Process(GameObject go) { _vrmInstance = go.GetComponent(); if (_vrmInstance == null) @@ -99,26 +122,6 @@ namespace UniVRM10 return (list, newList); } - void _ProcessFirstPerson(Vrm10Instance vrmInstance, UniGLTF.MeshUtility.MeshInfo info) - { - var firstPersonBone = vrmInstance.Humanoid.Head; - var task = VRM10ObjectFirstPerson.CreateErasedMeshAsync( - info.IntegratedRenderer, - firstPersonBone, - new VRMShaders.ImmediateCaller()); - task.Wait(); - - if (task.Result != null) - { - info.IntegratedRenderer.sharedMesh = task.Result; - info.IntegratedRenderer.name = "auto.headless"; - } - else - { - Debug.LogWarning("no result"); - } - } - public override void UpdateMeshIntegrationGroups(GameObject root) { if (root == null)