diff --git a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs index 7bf5c4a5e..d6b1afdde 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Instance/Vrm10Instance.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Linq; using UniGLTF; +using UniGLTF.Utils; using UnityEngine; using UnityEngine.Serialization; @@ -66,12 +68,36 @@ namespace UniVRM10 private UniHumanoid.Humanoid m_humanoid; private Vrm10Runtime m_runtime; + public IVrm10SpringBoneRuntime m_springBoneRuntime { get; set; } + private IReadOnlyDictionary m_defaultTransformStates; /// /// ControlRig の生成オプション /// private bool m_useControlRig; + public IReadOnlyDictionary DefaultTransformStates + { + get + { + if (m_defaultTransformStates == null) + { + if (TryGetComponent(out var gltfInstance)) + { + // ランタイムインポートならここに到達してゼロコストになる + m_defaultTransformStates = gltfInstance.InitialTransformStates; + } + else + { + // エディタでプレハブ配置してる奴ならこっちに到達して収集する + m_defaultTransformStates = GetComponentsInChildren() + .ToDictionary(tf => tf, tf => new TransformState(tf)); + } + } + return m_defaultTransformStates; + } + } + /// /// VRM ファイルに記録された Humanoid ボーンに対応します。 /// これは、コントロールリグのボーンとは異なります。 @@ -88,9 +114,11 @@ namespace UniVRM10 } } - /// - /// ランタイム情報 - /// + public Vrm10Runtime MakeRuntime(bool useControlRig) + { + return new Vrm10Runtime(this, useControlRig, m_springBoneRuntime); + } + public Vrm10Runtime Runtime { get @@ -98,15 +126,39 @@ namespace UniVRM10 if (m_runtime == null) { if (this == null) throw new MissingReferenceException("instance was destroyed"); - m_runtime = new Vrm10Runtime(this, m_useControlRig); + m_runtime = MakeRuntime(m_useControlRig); } return m_runtime; } } - internal void InitializeAtRuntime(bool useControlRig) + internal void InitializeAtRuntime( + bool useControlRig, + IVrm10SpringBoneRuntime springBoneRuntime, + IReadOnlyDictionary defaultTransformStates = null + ) { m_useControlRig = useControlRig; + m_springBoneRuntime = springBoneRuntime; + + if (defaultTransformStates != null) + { + m_defaultTransformStates = defaultTransformStates; + } + else + { + if (TryGetComponent(out var gltfInstance)) + { + // ランタイムインポートならここに到達してゼロコストになる + defaultTransformStates = gltfInstance.InitialTransformStates; + } + else + { + // エディタでプレハブ配置してる奴ならこっちに到達して収集する + defaultTransformStates = GetComponentsInChildren() + .ToDictionary(tf => tf, tf => new TransformState(tf)); + } + } } void Start() diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs index bc33b17e0..3f873e8cf 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10Runtime.cs @@ -27,7 +27,7 @@ namespace UniVRM10 public IVrm10Constraint[] Constraints { get; } public Vrm10RuntimeExpression Expression { get; } public Vrm10RuntimeLookAt LookAt { get; } - public Vrm10RuntimeSpringBone SpringBone { get; } + public IVrm10SpringBoneRuntime SpringBone { get; } public IVrm10Animation VrmAnimation { get; set; } [Obsolete("use Vrm10Runtime.SpringBone.ExternalForce")] @@ -37,7 +37,7 @@ namespace UniVRM10 set { SpringBone.ExternalForce = value; } } - public Vrm10Runtime(Vrm10Instance instance, bool useControlRig) + public Vrm10Runtime(Vrm10Instance instance, bool useControlRig, IVrm10SpringBoneRuntime springBoneRuntime) { if (!Application.isPlaying) { @@ -58,7 +58,8 @@ namespace UniVRM10 Constraints = instance.GetComponentsInChildren(); LookAt = new Vrm10RuntimeLookAt(instance.Vrm.LookAt, instance.Humanoid, ControlRig); Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable); - SpringBone = new Vrm10RuntimeSpringBone(instance); + SpringBone = springBoneRuntime; + SpringBone.Initialize(instance); } public void Dispose() diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeSpringBone.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeSpringBone.cs index d14e0e9e7..ccb7384dd 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeSpringBone.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeSpringBone.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using UniGLTF; using UniGLTF.Utils; @@ -9,11 +8,10 @@ using UniGLTF.SpringBoneJobs.InputPorts; namespace UniVRM10 { - public class Vrm10RuntimeSpringBone : IDisposable + public class Vrm10RuntimeSpringBone : IVrm10SpringBoneRuntime { - private readonly Vrm10Instance m_instance; - private readonly IReadOnlyDictionary m_defaultTransformStates; - private readonly FastSpringBones.FastSpringBoneService m_fastSpringBoneService; + private Vrm10Instance m_instance; + private readonly FastSpringBones.FastSpringBoneService m_fastSpringBoneService = FastSpringBones.FastSpringBoneService.Instance; private FastSpringBoneSpring[] m_springs; private Quaternion[] m_initialLocalRotations; private FastSpringBoneBuffer m_fastSpringBoneBuffer; @@ -28,26 +26,14 @@ namespace UniVRM10 set => m_fastSpringBoneBuffer.IsSpringBoneEnabled = value; } - internal Vrm10RuntimeSpringBone(Vrm10Instance instance) + /// VRMの初期姿勢(T-Pose)状態。instanceがT-Poseから変化していても大丈夫 + public void Initialize(Vrm10Instance instance) { m_instance = instance; - if (instance.TryGetComponent(out var gltfInstance)) - { - // ランタイムインポートならここに到達してゼロコストになる - m_defaultTransformStates = gltfInstance.InitialTransformStates; - } - else - { - // エディタでプレハブ配置してる奴ならこっちに到達して収集する - m_defaultTransformStates = instance.GetComponentsInChildren() - .ToDictionary(tf => tf, tf => new TransformState(tf)); - } - // NOTE: FastSpringBoneService は UnitTest などでは動作しない if (Application.isPlaying) { - m_fastSpringBoneService = FastSpringBones.FastSpringBoneService.Instance; ReconstructSpringBone(); } } @@ -113,7 +99,7 @@ namespace UniVRM10 private TransformState GetOrAddDefaultTransformState(Transform tf) { - if (m_defaultTransformStates.TryGetValue(tf, out var defaultTransformState)) + if (m_instance.DefaultTransformStates.TryGetValue(tf, out var defaultTransformState)) { return defaultTransformState; } diff --git a/Assets/VRM10/Runtime/IO/IVrm10SpringBoneRuntime.cs b/Assets/VRM10/Runtime/IO/IVrm10SpringBoneRuntime.cs new file mode 100644 index 000000000..e1c1c2b49 --- /dev/null +++ b/Assets/VRM10/Runtime/IO/IVrm10SpringBoneRuntime.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using UniGLTF; +using UniGLTF.Utils; +using UnityEngine; + +namespace UniVRM10 +{ + public interface IVrm10SpringBoneRuntime : IDisposable + { + public void Initialize(Vrm10Instance instance); + + /// + /// 主に singleton のバッチング更新。 + /// + /// 再構築。initialTransform を使って再構築? + /// Joint の増減、T-Pose の変更などある? + /// + public void ReconstructSpringBone(); + + /// + /// initialTransform 状態に復帰。verlet の速度 も 0 に。 + /// + public void RestoreInitialTransform(); + + public Vector3 ExternalForce { get; set; } + + public bool IsSpringBoneEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Assets/VRM10/Runtime/IO/IVrm10SpringBoneRuntime.cs.meta b/Assets/VRM10/Runtime/IO/IVrm10SpringBoneRuntime.cs.meta new file mode 100644 index 000000000..dfa427709 --- /dev/null +++ b/Assets/VRM10/Runtime/IO/IVrm10SpringBoneRuntime.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 50a24e5a47bb02848abe4d257ffdc7f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index 31d49fc5d..6f7e4a973 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -24,13 +24,16 @@ namespace UniVRM10 private VRM10Object m_vrmObject; private List<(ExpressionPreset Preset, VRM10Expression Clip)> m_expressions = new List<(ExpressionPreset, VRM10Expression)>(); + private IVrm10SpringBoneRuntime m_springboneRuntime; + public Vrm10Importer( Vrm10Data vrm, IReadOnlyDictionary externalObjectMap = null, ITextureDeserializer textureDeserializer = null, IMaterialDescriptorGenerator materialGenerator = null, bool useControlRig = false, - ImporterContextSettings settings = null + ImporterContextSettings settings = null, + IVrm10SpringBoneRuntime springboneRuntime = null ) : base(vrm.Data, externalObjectMap, textureDeserializer, settings: settings) { @@ -49,6 +52,8 @@ namespace UniVRM10 { m_externalMap = new Dictionary(); } + + m_springboneRuntime = springboneRuntime ?? new Vrm10RuntimeSpringBone(); } static void AssignHumanoid(List nodes, UniGLTF.Extensions.VRMC_vrm.HumanBone humanBone, VrmLib.HumanoidBones key) @@ -258,7 +263,7 @@ namespace UniVRM10 // VrmController var controller = Root.AddComponent(); - controller.InitializeAtRuntime(m_useControlRig); + controller.InitializeAtRuntime(m_useControlRig, m_springboneRuntime); controller.enabled = false; // vrm diff --git a/Assets/VRM10/Tests/ExpressionTests.cs b/Assets/VRM10/Tests/ExpressionTests.cs index f097d503d..c849e17c0 100644 --- a/Assets/VRM10/Tests/ExpressionTests.cs +++ b/Assets/VRM10/Tests/ExpressionTests.cs @@ -32,7 +32,7 @@ namespace UniVRM10.Test controller.Vrm.Expression.Aa.MaterialColorBindings = src.ToArray(); // ok if no exception - var r = new Vrm10Runtime(controller, useControlRig: false); + var r = controller.MakeRuntime(useControlRig: false); } [Test] @@ -56,7 +56,7 @@ namespace UniVRM10.Test controller.Vrm.Expression.Aa.MaterialUVBindings = src.ToArray(); // ok if no exception - var r = new Vrm10Runtime(controller, useControlRig: false); + var r = controller.MakeRuntime(useControlRig: false); } } }