using System; using UnityEngine; namespace UniVRM10 { /// /// VRM モデルインスタンスを、状態をもって、元の状態から操作・変更するためのクラス。 /// また、仕様に従ってその操作を行う。 /// /// 操作対象としては以下が挙げられる。 /// - ControlRig /// - Constraint /// - LookAt /// - Expression /// public class Vrm10Runtime : IDisposable { private readonly Vrm10Instance m_instance; private readonly Transform m_head; /// /// Control Rig may be null. /// Control Rig is generated at loading runtime only. /// public Vrm10RuntimeControlRig ControlRig { get; } public IVrm10Constraint[] Constraints { get; } public Vrm10RuntimeExpression Expression { get; } public Vrm10RuntimeLookAt LookAt { get; } public Vrm10RuntimeSpringBone SpringBone { get; } public IVrm10Animation VrmAnimation { get; set; } [Obsolete("use Vrm10Runtime.SpringBone.ExternalForce")] public Vector3 ExternalForce { get { return SpringBone.ExternalForce; } set { SpringBone.ExternalForce = value; } } public Vrm10Runtime(Vrm10Instance instance, bool useControlRig) { if (!Application.isPlaying) { Debug.LogWarning($"{nameof(Vrm10Runtime)} expects runtime behaviour."); } m_instance = instance; if (!instance.TryGetBoneTransform(HumanBodyBones.Head, out m_head)) { throw new Exception(); } if (useControlRig) { ControlRig = new Vrm10RuntimeControlRig(instance.Humanoid, m_instance.transform); } Constraints = instance.GetComponentsInChildren(); LookAt = new Vrm10RuntimeLookAt(instance.Vrm.LookAt, instance.Humanoid, ControlRig); Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable); SpringBone = new Vrm10RuntimeSpringBone(instance); } public void Dispose() { ControlRig?.Dispose(); SpringBone.Dispose(); } [Obsolete("use Vrm10Runtime.SpringBone.ReconstructSpringBone")] public void ReconstructSpringBone() { SpringBone.ReconstructSpringBone(); } /// /// 毎フレーム関連コンポーネントを解決する /// /// * Update from VrmAnimation /// * Constraint /// * Spring /// * LookAt /// * Expression /// /// public void Process() { // 1. Update From VrmAnimation if (VrmAnimation != null) { // copy pose { Vrm10Retarget.Retarget(VrmAnimation.ControlRig, (ControlRig, ControlRig)); } // update expressions foreach (var (k, v) in VrmAnimation.ExpressionMap) { Expression.SetWeight(k, v()); } // look at if (VrmAnimation.LookAt.HasValue) { LookAt.LookAtInput = VrmAnimation.LookAt.Value; } } // 2. Control Rig ControlRig?.Process(); // 3. Constraints foreach (var constraint in Constraints) { constraint.Process(); } if (m_instance.LookAtTargetType == VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform && m_instance.LookAtTarget != null) { // Transform 追跡で視線を生成する。 // 値を上書きします。 LookAt.LookAtInput = new LookAtInput { WorldPosition = m_instance.LookAtTarget.position }; } // 4. Gaze control var eyeDirection = LookAt.Process(); // 5. Apply Expression // LookAt の角度制限などはこちらで処理されます。 Expression.Process(eyeDirection); } } }