コード例 #1
0
        private void Update()
        {
            var headPose = TobiiAPI.GetHeadPose();

            if (headPose.IsRecent())
            {
                var rot = headPose.Rotation;
                if (isMirrored)
                {
                    rot.y *= -1;
                    rot.z *= -1;
                }
                _head.localRotation = Quaternion.Lerp(
                    _head.localRotation,
                    rot,
                    Time.deltaTime * responsiveness
                    );

                var pos = headPose.Position;
                // Debug.Log($"Head Pos = {pos.x:0.00},{pos.y:0.00},{pos.z:0.00}");
                _root.localPosition = new Vector3(
                    pos.x * (-0.001f),
                    pos.y * 0.001f,
                    0
                    );
            }

            var gazePoint = TobiiAPI.GetGazePoint();

            if (gazePoint.IsRecent())
            {
                var fov          = _cam.fieldOfView;
                var mirrorFactor = isMirrored ? -1f : 1f;
                var eyeRotation  = Quaternion.Euler(
                    (gazePoint.Viewport.y - 0.5f) * fov * eyeRotationApplyRate * (-1),
                    (gazePoint.Viewport.x - 0.5f) * fov * _cam.aspect * eyeRotationApplyRate * mirrorFactor,
                    0
                    );

                _leftEye.localRotation  = eyeRotation;
                _rightEye.localRotation = eyeRotation;
            }

            _eyeClosed =
                TobiiAPI.GetUserPresence().IsUserPresent() && (Time.unscaledTime - gazePoint.Timestamp) > eyeCloseJudgeLimitTime ||
                !gazePoint.IsRecent();

            if (_eyeClosed)
            {
                _blinkValue = 1.0f;
            }
            else
            {
                _blinkValue = Mathf.Max(_blinkValue - eyeOpenRate * Time.deltaTime, 0f);
            }

            blendShape.AccumulateValue(lBlinkKey, _blinkValue);
            blendShape.AccumulateValue(rBlinkKey, _blinkValue);
            blendShape.Apply();
        }
コード例 #2
0
        private void Update()
        {
            //眼球運動もモード別で切り替えていく
            bool canUseExternalEyeJitter =
                _config.ControlMode == FaceControlModes.ExternalTracker && externalTrackEyeJitter.IsTracked;

            randomEyeJitter.IsActive        = !canUseExternalEyeJitter;
            externalTrackEyeJitter.IsActive = canUseExternalEyeJitter;

            if (!_hasModel)
            {
                return;
            }

            if (_config.ShouldSkipNonMouthBlendShape)
            {
                //TODO: これ系の「非ゼロにしたいBlendShapeを明示的に切る」処理をどこに入れるか、というのは悩みどころ
                //ResetBlink();
                return;
            }

            DefaultBlendShape.Apply(_proxy);

            var blinkSource =
                _config.ControlMode == FaceControlModes.ExternalTracker ? externalTrackerBlink.BlinkSource :
                (_config.ControlMode == FaceControlModes.WebCam && !PreferAutoBlinkOnWebCamTracking) ? imageBasedBlinkController.BlinkSource :
                autoBlink.BlinkSource;

            _proxy.AccumulateValue(BlinkLKey, blinkSource.Left);
            _proxy.AccumulateValue(BlinkRKey, blinkSource.Right);
        }
コード例 #3
0
        public void Apply(VRMBlendShapeProxy proxy)
        {
            float left  = _currentLeftBlink > closeThreshold ? 1.0f : _currentLeftBlink;
            float right = _currentRightBlink > closeThreshold ? 1.0f : _currentRightBlink;

            proxy.AccumulateValue(BlinkLKey, left);
            proxy.AccumulateValue(BlinkRKey, right);
        }
コード例 #4
0
 /// <summary>
 /// 確認用の表情設定
 /// </summary>
 void Set(float joy, float angry, float sorrow, float fun)
 {
     Proxy.AccumulateValue(BlendShapePreset.Joy, joy);
     Proxy.AccumulateValue(BlendShapePreset.Angry, angry);
     Proxy.AccumulateValue(BlendShapePreset.Sorrow, sorrow);
     Proxy.AccumulateValue(BlendShapePreset.Fun, fun);
     Proxy.Apply();
 }
コード例 #5
0
 private void Update()
 {
     if (_reserveBlendShapeReset)
     {
         for (int i = 0; i < _allBlendShapeKeys.Length; i++)
         {
             _proxy.AccumulateValue(_allBlendShapeKeys[i], 0f);
         }
         _proxy?.Apply();
         _reserveBlendShapeReset = false;
     }
 }
コード例 #6
0
        /// <summary>
        /// すべてのクリップにゼロを当て込みます。
        /// </summary>
        public void InitializeBlendShapes()
        {
            if (!_hasModel)
            {
                return;
            }

            for (int i = 0; i < _keys.Length; i++)
            {
                _proxy.AccumulateValue(_keys[i], 0);
            }
        }
コード例 #7
0
 void Update()
 {
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.A), Lip_A);
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.I), Lip_I);
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.U), Lip_U);
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.E), Lip_E);
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.O), Lip_O);
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Blink), Blink);
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Joy), Expression_Joy);
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Angry), Expression_Angry);
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Sorrow), Expression_Sorrow);
     m_proxy.AccumulateValue(BlendShapeKey.CreateFromPreset(BlendShapePreset.Fun), Expression_Fun);
 }
コード例 #8
0
        public void Accumulate(VRMBlendShapeProxy proxy)
        {
            //NOTE: マイクが無効な場合はanimMorphEasedTargetの出力がゼロになる、というのを想定した書き方でもあります
            var src = PreferExternalTrackerLipSync
                ? externalTrackerLipSync.LipSyncSource
                : animMorphEasedTarget.LipSyncSource;

            proxy.AccumulateValue(_a, src.A);
            proxy.AccumulateValue(_i, src.I);
            proxy.AccumulateValue(_u, src.U);
            proxy.AccumulateValue(_e, src.E);
            proxy.AccumulateValue(_o, src.O);
        }
コード例 #9
0
    void Update()
    {
        available = false;

        //全ノブを調べる
        if (blendShapeProxy != null)
        {
            for (int i = 0; i < MidiCCWrapper.KNOBS; i++)
            {
                //キーが登録されている場合
                if (KnobToBlendShape[i] != null && KnobToBlendShape[i] != "")
                {
                    //表情を反映する
                    blendShapeProxy.AccumulateValue(KnobToBlendShape[i], midiCCWrapper.CCValue[i]);
                    available = true;
                }
            }

            //値が一つでも存在すれば反映、でなければ特に触らない
            if (available)
            {
                blendShapeProxy.Apply();
            }
        }
    }
コード例 #10
0
 public void ApplyNeutralClip(VRMBlendShapeProxy proxy)
 {
     if (HasValidNeutralClipKey)
     {
         proxy.AccumulateValue(NeutralClipKey, 1f);
     }
 }
コード例 #11
0
        public void InitializeBlendShapes(bool keepLipSync)
        {
            if (!_hasModel)
            {
                return;
            }

            for (int i = 0; i < _keys.Length; i++)
            {
                if (keepLipSync && _lipSyncKeys.Contains(_keys[i]))
                {
                    continue;
                }
                _proxy.AccumulateValue(_keys[i], 0);
            }
        }
コード例 #12
0
 public void ApplyOffsetClip(VRMBlendShapeProxy proxy)
 {
     if (HasValidOffsetClipKey)
     {
         proxy.AccumulateValue(OffsetClipKey, 1f);
     }
 }
コード例 #13
0
        public void Accumulate(VRMBlendShapeProxy proxy)
        {
            if (!HasBlendShapeToApply)
            {
                //オーバーライド不要なので何もしない
                return;
            }

            //NOTE: LateUpdateの実装(初期実装)と違い、必要なとこだけ狙ってAccumulateする
            for (int i = 0; i < _allBlendShapeKeys.Length; i++)
            {
                var key = _allBlendShapeKeys[i];
                //リップシンク保持オプションがオン = AIUEOはAccumulateしない(元の値をリスペクトする)
                if (KeepLipSync && _lipSyncKeys.Any(k => k.Preset == key.Preset && k.Name == key.Name))
                {
                    continue;
                }
                //NOTE: パーフェクトシンクのクリップはリップシンク保持であっても通す。
                //これはフィルタすると重すぎるので「パーフェクトシンク使う人はそのくらい理解してくれ」という意味です
                if (_blendShape.TryGetValue(key, out float value) && value > 0f)
                {
                    proxy.AccumulateValue(key, value);
                }
            }
            _eyeBoneResetter.ReserveReset = true;
        }
コード例 #14
0
        private void Update()
        {
            if (!_hasModel || _config.ShouldSkipMouthBlendShape)
            {
                return;
            }

            //NOTE: マイクが無効な場合はanimMorphEasedTargetの出力がゼロになる、というのを想定した書き方でもあります
            var src = PreferExternalTrackerLipSync
                ? externalTrackerLipSync.LipSyncSource
                : animMorphEasedTarget.LipSyncSource;

            _blendShape.AccumulateValue(_a, src.A);
            _blendShape.AccumulateValue(_i, src.I);
            _blendShape.AccumulateValue(_u, src.U);
            _blendShape.AccumulateValue(_e, src.E);
            _blendShape.AccumulateValue(_o, src.O);
        }
コード例 #15
0
 private void AccumulateBlendShapes()
 {
     if (proxy == null)
     {
         return;
     }
     foreach (var shapeKey in CurrentShapeKeys)
     {
         proxy.AccumulateValue(shapeKey.Key, shapeKey.Value);
     }
     foreach (var presets in AccumulateShapeKeys)
     {
         foreach (var preset in presets.Value)
         {
             proxy.AccumulateValue(preset.Key, preset.Value);
         }
     }
     proxy.Apply();
 }
コード例 #16
0
        public void Accumulate(VRMBlendShapeProxy proxy)
        {
            if (!_hasModel)
            {
                return;
            }

            //NOTE: ここのデフォルトfunだが
            //「パーフェクトシンク使用中」「FaceSwitch適用中」「Word to Motion適用中」
            //の3ケースでは適用されると困る。
            //で、ここに書いておくと上記3ケースではそもそもAccumulateが呼ばれないため、うまく動く。
            DefaultBlendShape.Apply(proxy);

            var blinkSource =
                _config.ControlMode == FaceControlModes.ExternalTracker ? externalTrackerBlink.BlinkSource :
                (_config.ControlMode == FaceControlModes.WebCam && !PreferAutoBlinkOnWebCamTracking) ? imageBasedBlinkController.BlinkSource :
                autoBlink.BlinkSource;

            proxy.AccumulateValue(BlinkLKey, blinkSource.Left);
            proxy.AccumulateValue(BlinkRKey, blinkSource.Right);
        }
コード例 #17
0
    void OnDataReceived(uOSC.Message message)
    {
        if (message.address == "/VMC/Ext/Root/Pos")
        {
            Vector3    pos = new Vector3((float)message.values[1], (float)message.values[2], (float)message.values[3]);
            Quaternion rot = new Quaternion((float)message.values[4], (float)message.values[5], (float)message.values[6], (float)message.values[7]);

            Model.transform.localPosition = pos;
            Model.transform.localRotation = rot;
        }

        else if (message.address == "/VMC/Ext/Bone/Pos")
        {
            //モデルが更新されたときのみ読み込み
            if (Model != null && OldModel != Model)
            {
                animator        = Model.GetComponent <Animator>();
                blendShapeProxy = Model.GetComponent <VRMBlendShapeProxy>();
                OldModel        = Model;
            }

            HumanBodyBones bone;
            if (Enum.TryParse <HumanBodyBones>((string)message.values[0], out bone))
            {
                if ((animator != null) && (bone != HumanBodyBones.LastBone))
                {
                    Vector3    pos = new Vector3((float)message.values[1], (float)message.values[2], (float)message.values[3]);
                    Quaternion rot = new Quaternion((float)message.values[4], (float)message.values[5], (float)message.values[6], (float)message.values[7]);

                    var t = animator.GetBoneTransform(bone);
                    if (t != null)
                    {
                        t.localPosition = pos;
                        t.localRotation = rot;
                    }
                }
            }
        }
        else if (message.address == "/VMC/Ext/Blend/Val")
        {
            string BlendName  = (string)message.values[0];
            float  BlendValue = (float)message.values[1];

            blendShapeProxy.AccumulateValue(BlendName, BlendValue);
        }
        else if (message.address == "/VMC/Ext/Blend/Apply")
        {
            blendShapeProxy.Apply();
        }
    }
コード例 #18
0
        public void Accumulate(VRMBlendShapeProxy proxy)
        {
            if (!_hasModel ||
                string.IsNullOrEmpty(_externalTracker.FaceSwitchClipName) ||
                _config.WordToMotionExpressionActive
                )
            {
                return;
            }

            if (_latestClipName != _externalTracker.FaceSwitchClipName)
            {
                _latestKey      = CreateKey(_externalTracker.FaceSwitchClipName);
                _latestClipName = _externalTracker.FaceSwitchClipName;
            }

            //ターゲットのキーだけいじり、他のクリップ状態については呼び出し元に責任を持ってもらう
            proxy.AccumulateValue(_latestKey, 1.0f);
            //表情を適用した = 目ボーンは正面向きになってほしい
            _eyeBoneResetter.ReserveReset = true;
        }
コード例 #19
0
        static void OnDefaultBlend(OVRLipSync.Frame frame, VRMBlendShapeProxy vrmBlendShapeProxy)
        {
            var visemes = new float[visemeToBlendTargets.Length];

            Array.Copy(frame.Visemes, (int)OVRLipSync.Viseme.aa, visemes, 1, visemes.Length - 1);
            visemes[0] = frame.Visemes[(int)OVRLipSync.Viseme.sil];
            var sum = visemes.Sum();

            if (sum <= float.Epsilon)
            {
                visemes[0] = 1;
            }
            else
            {
                for (int i = 0; i < visemes.Length; ++i)
                {
                    visemes[i] /= sum;
                }
            }
            for (int i = 0; i < visemes.Length; ++i)
            {
                vrmBlendShapeProxy.AccumulateValue(BlendShapeKey.CreateFromPreset(visemeToBlendTargets[i]), visemes[i]);
            }
        }
コード例 #20
0
        private void LateUpdate()
        {
            if (!_hasModel ||
                string.IsNullOrEmpty(_externalTracker.FaceSwitchClipName) ||
                _config.WordToMotionExpressionActive
                )
            {
                return;
            }

            _proxy.Apply();
            _initializer.InitializeBlendShapes(_externalTracker.KeepLipSyncForFaceSwitch);

            if (_latestClipName != _externalTracker.FaceSwitchClipName)
            {
                _latestKey      = CreateKey(_externalTracker.FaceSwitchClipName);
                _latestClipName = _externalTracker.FaceSwitchClipName;
            }

            //NOTE: 最終的な適用はWordToMotionBlendShapeがやる。ので、ここではその前処理だけやってればよい
            _proxy.AccumulateValue(_latestKey, 1.0f);
            //表情を適用した = 目ボーンは正面向きになってほしい
            _eyeBoneResetter.ReserveReset = true;
        }
コード例 #21
0
 public void Reset(VRMBlendShapeProxy proxy)
 {
     proxy.AccumulateValue(FunKey, 0);
 }
コード例 #22
0
 public void Apply(VRMBlendShapeProxy proxy)
 {
     proxy.AccumulateValue(FunKey, FaceDefaultFunValue);
 }
コード例 #23
0
        //メッセージ処理本体
        private void ProcessMessage(ref uOSC.Message message)
        {
            //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない
            if (message.address == null || message.values == null)
            {
                StatusMessage = "Bad message.";
                return;
            }

            //ルート位置がない場合
            if (RootPositionTransform == null && Model != null)
            {
                //モデル姿勢をルート姿勢にする
                RootPositionTransform = Model.transform;
            }

            //ルート回転がない場合
            if (RootRotationTransform == null && Model != null)
            {
                //モデル姿勢をルート姿勢にする
                RootRotationTransform = Model.transform;
            }

            //モーションデータ送信可否
            if (message.address == "/VMC/Ext/OK" &&
                (message.values[0] is int))
            {
                Available = (int)message.values[0];
                if (Available == 0)
                {
                    StatusMessage = "Waiting for [Load VRM]";
                }

                //V2.5 キャリブレーション状態(長さ3以上)
                if (message.values.Length >= 3)
                {
                    if ((message.values[1] is int) && (message.values[2] is int))
                    {
                        int calibrationState = (int)message.values[1];
                        int calibrationMode  = (int)message.values[2];

                        //キャリブレーション出来ていないときは隠す
                        if (HideInUncalibrated && Model != null)
                        {
                            Model.SetActive(calibrationState == 3);
                        }
                        //スケール同期をキャリブレーションと連動させる
                        if (SyncCalibrationModeWithScaleOffsetSynchronize)
                        {
                            RootScaleOffsetSynchronize = !(calibrationMode == 0); //通常モードならオフ、MR系ならオン
                        }
                    }
                }
                return;
            }
            //データ送信時刻
            else if (message.address == "/VMC/Ext/T" &&
                     (message.values[0] is float))
            {
                time = (float)message.values[0];
                PacketCounterInFrame++; //フレーム中のパケットフレーム数を測定
                return;
            }
            //VRM自動読み込み
            else if (message.address == "/VMC/Ext/VRM" &&
                     (message.values[0] is string) &&
                     (message.values[1] is string)
                     )
            {
                string path  = (string)message.values[0];
                string title = (string)message.values[1];

                //前回読み込んだパスと違う場合かつ、読み込みが許可されている場合
                if (path != loadedVRMPath && enableAutoLoadVRM == true)
                {
                    loadedVRMPath = path;
                    loadedVRMName = title;
                    LoadVRM(path);
                }
                return;
            }
            //オプション文字列
            else if (message.address == "/VMC/Ext/Opt" &&
                     (message.values[0] is string))
            {
                OptionString = (string)message.values[0];
                return;
            }


            //モデルがないか、モデル姿勢、ルート姿勢が取得できないなら以降何もしない
            if (Model == null || Model.transform == null || RootPositionTransform == null || RootRotationTransform == null)
            {
                return;
            }

            //Root姿勢
            if (message.address == "/VMC/Ext/Root/Pos" &&
                (message.values[0] is string) &&
                (message.values[1] is float) &&
                (message.values[2] is float) &&
                (message.values[3] is float) &&
                (message.values[4] is float) &&
                (message.values[5] is float) &&
                (message.values[6] is float) &&
                (message.values[7] is float)
                )
            {
                StatusMessage = "OK";

                pos.x = (float)message.values[1];
                pos.y = (float)message.values[2];
                pos.z = (float)message.values[3];
                rot.x = (float)message.values[4];
                rot.y = (float)message.values[5];
                rot.z = (float)message.values[6];
                rot.w = (float)message.values[7];

                //位置同期
                if (RootPositionSynchronize)
                {
                    RootPositionTransform.localPosition = pos;
                }
                //回転同期
                if (RootRotationSynchronize)
                {
                    RootRotationTransform.localRotation = rot;
                }
                //スケール同期とオフセット補正(v2.1拡張プロトコルの場合のみ)
                if (RootScaleOffsetSynchronize && message.values.Length > RootPacketLengthOfScaleAndOffset &&
                    (message.values[8] is float) &&
                    (message.values[9] is float) &&
                    (message.values[10] is float) &&
                    (message.values[11] is float) &&
                    (message.values[12] is float) &&
                    (message.values[13] is float)
                    )
                {
                    scale.x  = 1.0f / (float)message.values[8];
                    scale.y  = 1.0f / (float)message.values[9];
                    scale.z  = 1.0f / (float)message.values[10];
                    offset.x = (float)message.values[11];
                    offset.y = (float)message.values[12];
                    offset.z = (float)message.values[13];

                    Model.transform.localScale          = scale;
                    RootPositionTransform.localPosition = Vector3.Scale(RootPositionTransform.localPosition, scale);

                    //位置同期が有効な場合のみオフセットを反映する
                    if (RootPositionSynchronize)
                    {
                        offset = Vector3.Scale(offset, scale);
                        RootPositionTransform.localPosition -= offset;
                    }
                }
                else
                {
                    Model.transform.localScale = Vector3.one;
                }
            }
            //ボーン姿勢
            else if (message.address == "/VMC/Ext/Bone/Pos" &&
                     (message.values[0] is string) &&
                     (message.values[1] is float) &&
                     (message.values[2] is float) &&
                     (message.values[3] is float) &&
                     (message.values[4] is float) &&
                     (message.values[5] is float) &&
                     (message.values[6] is float) &&
                     (message.values[7] is float)
                     )
            {
                string boneName = (string)message.values[0];
                pos.x = (float)message.values[1];
                pos.y = (float)message.values[2];
                pos.z = (float)message.values[3];
                rot.x = (float)message.values[4];
                rot.y = (float)message.values[5];
                rot.z = (float)message.values[6];
                rot.w = (float)message.values[7];

                //Humanoidボーンに該当するボーンがあるか調べる
                HumanBodyBones bone;
                if (HumanBodyBonesTryParse(ref boneName, out bone))
                {
                    //あれば位置と回転をキャッシュする
                    if (HumanBodyBonesPositionTable.ContainsKey(bone))
                    {
                        HumanBodyBonesPositionTable[bone] = pos;
                    }
                    else
                    {
                        HumanBodyBonesPositionTable.Add(bone, pos);
                    }

                    if (HumanBodyBonesRotationTable.ContainsKey(bone))
                    {
                        HumanBodyBonesRotationTable[bone] = rot;
                    }
                    else
                    {
                        HumanBodyBonesRotationTable.Add(bone, rot);
                    }
                }
                //受信と更新のタイミングは切り離した
            }
            //ブレンドシェープ同期
            else if (message.address == "/VMC/Ext/Blend/Val" &&
                     (message.values[0] is string) &&
                     (message.values[1] is float)
                     )
            {
                if (BlendShapeSynchronize && blendShapeProxy != null)
                {
                    //v0.55ブレンドシェープ仕様変更対応
                    //ワークアラウンドが有効か
                    if (VRMVersion.MAJOR >= 0 && VRMVersion.MINOR > 53 && BlendShapeCaseWorkAround)
                    {
                        //まず、小文字変換テーブルを作成する
                        string RawKey             = (string)message.values[0];
                        string CaseSensitiveKey   = "";
                        string NoCaseSensitiveKey = "";

                        //小文字変換テーブルに存在しなければ
                        if (!blendShapeProxyCaseBuffer.TryGetValue(RawKey, out NoCaseSensitiveKey))
                        {
                            //小文字変換テーブルに登録する
                            blendShapeProxyCaseBuffer[RawKey] = RawKey.ToLower();
                            NoCaseSensitiveKey = RawKey.ToLower();

                            //Debug.Log("Register to CaseBuffer:" + RawKey + " -> " + NoCaseSensitiveKey);
                        }

                        //小文字変換された結果で、まずプリセットに存在するか確認する
                        string           presetName = "";
                        BlendShapePreset preset     = BlendShapePreset.Unknown;
                        //プリセット変換テーブルで見つかるか
                        if (BlendShapePresetCaseConverter.TryGetValue(NoCaseSensitiveKey, out presetName))
                        {
                            //ENUMテーブルで見つかるか
                            if (BlendShapePresetTryParse(ref presetName, out preset))
                            {
                                //見つかった
                                blendShapeProxy.AccumulateValue(preset, (float)message.values[1]);
                                //Debug.Log("Key Found: " + NoCaseSensitiveKey + "->" + preset.ToString());
                            }
                            else
                            {
                                //見つからない
                                preset = BlendShapePreset.Unknown;
                            }
                        }
                        else
                        {
                            //見つからない
                            preset = BlendShapePreset.Unknown;
                        }

                        //プリセットに該当するものがなかった場合
                        if (preset == BlendShapePreset.Unknown)
                        {
                            //小文字変換された結果を使って、ケースセンシティブな文字列に変換する
                            if (blendShapeProxyCaseConverter.TryGetValue(NoCaseSensitiveKey, out CaseSensitiveKey))
                            {
                                //独自キーとしてUniVRMにわたす
                                blendShapeProxy.AccumulateValue(CaseSensitiveKey, (float)message.values[1]);
                                //Debug.Log("Key Convert: " + NoCaseSensitiveKey + "->" + CaseSensitiveKey);
                            }
                            else
                            {
                                //Debug.Log("Key not found");
                            }
                        }
                    }
                    else
                    {
                        //通常通り適用する
                        blendShapeProxy.AccumulateValue((string)message.values[0], (float)message.values[1]);
                    }
                }
            }
            //ブレンドシェープ適用
            else if (message.address == "/VMC/Ext/Blend/Apply")
            {
                if (BlendShapeSynchronize && blendShapeProxy != null)
                {
                    blendShapeProxy.Apply();
                }
            }
        }
コード例 #24
0
    // Update is called once per frame
    void Update()
    {
        if (EnableLipSync)
        {
            if (Context != 0)
            {
                if (proxy == null)
                {
                    if (VRMmodel != null)
                    {
                        proxy = VRMmodel.GetComponent <VRMBlendShapeProxy>();
                    }
                }
                else
                {
                    // get the current viseme frame
                    OVRLipSync.Frame frame = GetCurrentPhonemeFrame();
                    if (frame != null)
                    {
                        //あ OVRLipSync.Viseme.aa; BlendShapePreset.A;
                        //い OVRLipSync.Viseme.ih; BlendShapePreset.I;
                        //う OVRLipSync.Viseme.ou; BlendShapePreset.U;
                        //え OVRLipSync.Viseme.E;  BlendShapePreset.E;
                        //お OVRLipSync.Viseme.oh; BlendShapePreset.O;
                        var presets = new BlendShapePreset[] {
                            BlendShapePreset.A,
                            BlendShapePreset.I,
                            BlendShapePreset.U,
                            BlendShapePreset.E,
                            BlendShapePreset.O,
                        };
                        var visemes = new float[] {
                            frame.Visemes[(int)OVRLipSync.Viseme.aa],
                            frame.Visemes[(int)OVRLipSync.Viseme.ih],
                            frame.Visemes[(int)OVRLipSync.Viseme.ou],
                            frame.Visemes[(int)OVRLipSync.Viseme.E],
                            frame.Visemes[(int)OVRLipSync.Viseme.oh],
                        };

                        int   maxindex   = 0;
                        float maxvisemes = 0;
                        for (int i = 0; i < presets.Length; i++)
                        {
                            if (visemes[i] < WeightThreashold)
                            {
                                visemes[i] = 0;
                            }
                            if (maxvisemes < visemes[i])
                            {
                                maxindex   = i;
                                maxvisemes = visemes[i];
                            }
                        }

                        if (MaxWeightEmphasis)
                        {
                            visemes[maxindex] = Mathf.Clamp(visemes[maxindex] * 3, 0.0f, 1.0f);
                        }

                        if (MaxWeightEnable)
                        {
                            for (int i = 0; i < presets.Length; i++)
                            {
                                if (i != maxindex)
                                {
                                    visemes[i] = 0.0f;
                                }
                            }
                        }

                        for (int i = 0; i < presets.Length; i++)
                        {
                            visemes[i] *= MaxLevel;
                            proxy.AccumulateValue(presets[i], visemes[i]);
                        }

                        proxy.Apply();

                        //Debug.Log("Visemes:" + string.Join(",", frame.Visemes.Select(d => d.ToString())));
                    }
                }
            }

            if (string.IsNullOrEmpty(selectedDevice) == false)
            {
                audioSource.volume = (sourceVolume / 100);
                if (!Microphone.IsRecording(selectedDevice))
                {
                    StartMicrophone();
                }

                if (EnableLowLatency)
                {
                    var position = Microphone.GetPosition(selectedDevice);
                    if (position < 0 || head == position)
                    {
                        return;
                    }

                    audioSource.clip.GetData(microphoneBuffer, 0);
                    while (GetDataLength(microphoneBuffer.Length, head, position) > processBuffer.Length)
                    {
                        var remain = microphoneBuffer.Length - head;
                        if (remain < processBuffer.Length)
                        {
                            Array.Copy(microphoneBuffer, head, processBuffer, 0, remain);
                            Array.Copy(microphoneBuffer, 0, processBuffer, remain, processBuffer.Length - remain);
                        }
                        else
                        {
                            Array.Copy(microphoneBuffer, head, processBuffer, 0, processBuffer.Length);
                        }

                        OVRLipSync.ProcessFrame(Context, processBuffer, Frame, OVRLipSync.AudioDataType.F32_Mono);

                        head += processBuffer.Length;
                        if (head > microphoneBuffer.Length)
                        {
                            head -= microphoneBuffer.Length;
                        }
                    }
                }
            }
        }
    }
コード例 #25
0
    void OnDataReceived(uOSC.Message message)
    {
        //有効なとき以外処理しない
        if (this.isActiveAndEnabled)
        {
            //仮想コントローラー V2.3
            if (message.address == "/VMC/Ext/Con/Pos" &&
                (message.values[0] is string) &&
                (message.values[1] is float) &&
                (message.values[2] is float) &&
                (message.values[3] is float) &&
                (message.values[4] is float) &&
                (message.values[5] is float) &&
                (message.values[6] is float) &&
                (message.values[7] is float)
                )
            {
                string serial         = (string)message.values[0];
                var    rigidTransform = SetTransform(ref pos, ref rot, ref message);

                lock (LockObject)
                {
                    if (virtualController.ContainsKey(serial))
                    {
                        virtualController[serial] = rigidTransform;
                    }
                    else
                    {
                        virtualController.Add(serial, rigidTransform);
                        virtualControllerFiltered.Add(serial, rigidTransform);
                    }
                }
            }
            //仮想トラッカー V2.3
            else if ((message.address == "/VMC/Ext/Hmd/Pos" ||
                      message.address == "/VMC/Ext/Tra/Pos") &&
                     (message.values[0] is string) &&
                     (message.values[1] is float) &&
                     (message.values[2] is float) &&
                     (message.values[3] is float) &&
                     (message.values[4] is float) &&
                     (message.values[5] is float) &&
                     (message.values[6] is float) &&
                     (message.values[7] is float)
                     )
            {
                string serial         = (string)message.values[0];
                var    rigidTransform = SetTransform(ref pos, ref rot, ref message);

                lock (LockObject)
                {
                    if (virtualTracker.ContainsKey(serial))
                    {
                        virtualTracker[serial] = rigidTransform;
                    }
                    else
                    {
                        virtualTracker.Add(serial, rigidTransform);
                        virtualTrackerFiltered.Add(serial, rigidTransform);
                    }
                }
            }
            //フレーム設定 V2.3
            else if (message.address == "/VMC/Ext/Set/Period" &&
                     (message.values[0] is int) &&
                     (message.values[1] is int) &&
                     (message.values[2] is int) &&
                     (message.values[3] is int) &&
                     (message.values[4] is int) &&
                     (message.values[5] is int)
                     )
            {
                externalSender.periodStatus     = (int)message.values[0];
                externalSender.periodRoot       = (int)message.values[1];
                externalSender.periodBone       = (int)message.values[2];
                externalSender.periodBlendShape = (int)message.values[3];
                externalSender.periodCamera     = (int)message.values[4];
                externalSender.periodDevices    = (int)message.values[5];
            }
            //Virtual MIDI CC V2.3
            else if (message.address == "/VMC/Ext/Midi/CC/Val" &&
                     (message.values[0] is int) &&
                     (message.values[1] is float)
                     )
            {
                MIDICCWrapper.KnobUpdated(0, (int)message.values[0], (float)message.values[1]);
            }
            //Camera Control V2.3
            else if (message.address == "/VMC/Ext/Cam" &&
                     (message.values[0] is string) &&
                     (message.values[1] is float) &&
                     (message.values[2] is float) &&
                     (message.values[3] is float) &&
                     (message.values[4] is float) &&
                     (message.values[5] is float) &&
                     (message.values[6] is float) &&
                     (message.values[7] is float) &&
                     (message.values[8] is float)
                     )
            {
                pos.x = (float)message.values[1];
                pos.y = (float)message.values[2];
                pos.z = (float)message.values[3];
                rot.x = (float)message.values[4];
                rot.y = (float)message.values[5];
                rot.z = (float)message.values[6];
                rot.w = (float)message.values[7];
                float fov = (float)message.values[8];

                //FreeCameraじゃなかったらFreeCameraにする
                if (ControlWPFWindow.CurrentSettings.CameraType != UnityMemoryMappedFile.CameraTypes.Free)
                {
                    window.ChangeCamera(UnityMemoryMappedFile.CameraTypes.Free);
                }

                //カメラ制御を切る
                window.FreeCamera.GetComponent <CameraMouseControl>().enabled = false;

                //座標とFOVを適用
                window.FreeCamera.transform.position = pos;
                window.FreeCamera.transform.rotation = rot;
                window.FreeCamera.fieldOfView        = fov;
            } //ブレンドシェープ同期
            else if (message.address == "/VMC/Ext/Blend/Val" &&
                     (message.values[0] is string) &&
                     (message.values[1] is float)
                     )
            {
                if (blendShapeProxy != null)
                {
                    blendShapeProxy.AccumulateValue((string)message.values[0], (float)message.values[1]);
                }
            }
            //ブレンドシェープ適用
            else if (message.address == "/VMC/Ext/Blend/Apply")
            {
                if (blendShapeProxy != null)
                {
                    blendShapeProxy.Apply();
                }
            }//外部アイトラ V2.3
            else if (message.address == "/VMC/Ext/Set/Eye" &&
                     (message.values[0] is int) &&
                     (message.values[1] is float) &&
                     (message.values[2] is float) &&
                     (message.values[3] is float)
                     )
            {
                bool enable = ((int)message.values[0]) != 0;
                pos.x = (float)message.values[1];
                pos.y = (float)message.values[2];
                pos.z = (float)message.values[3];

                if (enable)
                {
                    //ターゲットが存在しなければ作る
                    if (lookTargetOSC == null)
                    {
                        lookTargetOSC = new GameObject();
                        lookTargetOSC.transform.parent = null;
                        lookTargetOSC.name             = "lookTargetOSC";
                    }
                    //位置を書き込む
                    if (lookTargetOSC.transform != null)
                    {
                        lookTargetOSC.transform.position = pos;
                    }

                    //視線に書き込む
                    if (vrmLookAtHead != null)
                    {
                        vrmLookAtHead.Target = lookTargetOSC.transform;
                    }
                }
                else
                {
                    //視線を止める
                    if (vrmLookAtHead != null)
                    {
                        vrmLookAtHead.Target = null;
                    }
                }
            }
            //情報要求 V2.4
            else if (message.address == "/VMC/Ext/Set/Req")
            {
                externalSender.SendPerLowRate(); //即時送信
            }
            //情報表示 V2.4
            else if (message.address == "/VMC/Ext/Set/Res" && (message.values[0] is string))
            {
                statusString = (string)message.values[0];
            }
            //キャリブレーション準備 V2.5
            else if (message.address == "/VMC/Ext/Set/Calib/Ready")
            {
                if (File.Exists(ControlWPFWindow.CurrentSettings.VRMPath))
                {
                    window.ImportVRM(ControlWPFWindow.CurrentSettings.VRMPath, true, true, true);
                }
            }
            //キャリブレーション実行 V2.5
            else if (message.address == "/VMC/Ext/Set/Calib/Exec" && (message.values[0] is int))
            {
                PipeCommands.CalibrateType calibrateType = PipeCommands.CalibrateType.Default;

                switch ((int)message.values[0])
                {
                case 0:
                    calibrateType = PipeCommands.CalibrateType.Default;
                    break;

                case 1:
                    calibrateType = PipeCommands.CalibrateType.FixedHand;
                    break;

                case 2:
                    calibrateType = PipeCommands.CalibrateType.FixedHandWithGround;
                    break;

                default: return;     //無視
                }
                StartCoroutine(window.Calibrate(calibrateType));
                Invoke("EndCalibrate", 2f);
            }
            //設定読み込み V2.5
            else if (message.address == "/VMC/Ext/Set/Config" && (message.values[0] is string))
            {
                string path = (string)message.values[0];
                if (File.Exists(path))
                {
                    //なぜか時間がかかる
                    window.LoadSettings(path);
                }
            }
        }
    }
コード例 #26
0
        //メッセージ処理本体
        private void ProcessMessage(ref uOSC.Message message)
        {
            //メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない
            if (message.address == null || message.values == null)
            {
                StatusMessage = "Bad message.";
                return;
            }

            //ルート位置がない場合
            if (RootPositionTransform == null && Model != null)
            {
                //モデル姿勢をルート姿勢にする
                RootPositionTransform = Model.transform;
            }

            //ルート回転がない場合
            if (RootRotationTransform == null && Model != null)
            {
                //モデル姿勢をルート姿勢にする
                RootRotationTransform = Model.transform;
            }

            //モーションデータ送信可否
            if (message.address == "/VMC/Ext/OK" &&
                (message.values[0] is int))
            {
                Available = (int)message.values[0];
                if (Available == 0)
                {
                    StatusMessage = "Waiting for [Load VRM]";
                }

                //V2.5 キャリブレーション状態(長さ3以上)
                if (message.values.Length >= 3)
                {
                    if ((message.values[1] is int) && (message.values[2] is int))
                    {
                        int calibrationState = (int)message.values[1];
                        int calibrationMode  = (int)message.values[2];

                        //キャリブレーション出来ていないときは隠す
                        if (HideInUncalibrated && Model != null)
                        {
                            Model.SetActive(calibrationState == 3);
                        }
                        //スケール同期をキャリブレーションと連動させる
                        if (SyncCalibrationModeWithScaleOffsetSynchronize)
                        {
                            RootScaleOffsetSynchronize = !(calibrationMode == 0); //通常モードならオフ、MR系ならオン
                        }
                    }
                }
                return;
            }
            //データ送信時刻
            else if (message.address == "/VMC/Ext/T" &&
                     (message.values[0] is float))
            {
                time = (float)message.values[0];
                PacketCounterInFrame++; //フレーム中のパケットフレーム数を測定
                return;
            }
            //VRM自動読み込み
            else if (message.address == "/VMC/Ext/VRM" &&
                     (message.values[0] is string) &&
                     (message.values[1] is string)
                     )
            {
                string path  = (string)message.values[0];
                string title = (string)message.values[1];

                //前回読み込んだパスと違う場合かつ、読み込みが許可されている場合
                if (path != loadedVRMPath && enableAutoLoadVRM == true)
                {
                    loadedVRMPath = path;
                    loadedVRMName = title;
                    LoadVRM(path);
                }
                return;
            }
            //オプション文字列
            else if (message.address == "/VMC/Ext/Opt" &&
                     (message.values[0] is string))
            {
                OptionString = (string)message.values[0];
                return;
            }


            //モデルがないか、モデル姿勢、ルート姿勢が取得できないなら以降何もしない
            if (Model == null || Model.transform == null || RootPositionTransform == null || RootRotationTransform == null)
            {
                return;
            }

            //Root姿勢
            if (message.address == "/VMC/Ext/Root/Pos" &&
                (message.values[0] is string) &&
                (message.values[1] is float) &&
                (message.values[2] is float) &&
                (message.values[3] is float) &&
                (message.values[4] is float) &&
                (message.values[5] is float) &&
                (message.values[6] is float) &&
                (message.values[7] is float)
                )
            {
                StatusMessage = "OK";

                pos.x = (float)message.values[1];
                pos.y = (float)message.values[2];
                pos.z = (float)message.values[3];
                rot.x = (float)message.values[4];
                rot.y = (float)message.values[5];
                rot.z = (float)message.values[6];
                rot.w = (float)message.values[7];

                //位置同期
                if (RootPositionSynchronize)
                {
                    RootPositionTransform.localPosition = pos;
                }
                //回転同期
                if (RootRotationSynchronize)
                {
                    RootRotationTransform.localRotation = rot;
                }
                //スケール同期とオフセット補正(v2.1拡張プロトコルの場合のみ)
                if (RootScaleOffsetSynchronize && message.values.Length > RootPacketLengthOfScaleAndOffset &&
                    (message.values[8] is float) &&
                    (message.values[9] is float) &&
                    (message.values[10] is float) &&
                    (message.values[11] is float) &&
                    (message.values[12] is float) &&
                    (message.values[13] is float)
                    )
                {
                    scale.x  = 1.0f / (float)message.values[8];
                    scale.y  = 1.0f / (float)message.values[9];
                    scale.z  = 1.0f / (float)message.values[10];
                    offset.x = (float)message.values[11];
                    offset.y = (float)message.values[12];
                    offset.z = (float)message.values[13];

                    Model.transform.localScale          = scale;
                    RootPositionTransform.localPosition = Vector3.Scale(RootPositionTransform.localPosition, scale);

                    //位置同期が有効な場合のみオフセットを反映する
                    if (RootPositionSynchronize)
                    {
                        offset = Vector3.Scale(offset, scale);
                        RootPositionTransform.localPosition -= offset;
                    }
                }
                else
                {
                    Model.transform.localScale = Vector3.one;
                    scale  = Vector3.one;
                    offset = Vector3.zero;
                }
            }
            //ボーン姿勢
            else if (message.address == "/VMC/Ext/Bone/Pos" &&
                     (message.values[0] is string) &&
                     (message.values[1] is float) &&
                     (message.values[2] is float) &&
                     (message.values[3] is float) &&
                     (message.values[4] is float) &&
                     (message.values[5] is float) &&
                     (message.values[6] is float) &&
                     (message.values[7] is float)
                     )
            {
                string boneName = (string)message.values[0];
                pos.x = (float)message.values[1];
                pos.y = (float)message.values[2];
                pos.z = (float)message.values[3];
                rot.x = (float)message.values[4];
                rot.y = (float)message.values[5];
                rot.z = (float)message.values[6];
                rot.w = (float)message.values[7];

                //Humanoidボーンに該当するボーンがあるか調べる
                HumanBodyBones bone;
                if (HumanBodyBonesTryParse(ref boneName, out bone))
                {
                    //あれば位置と回転をキャッシュする
                    if (HumanBodyBonesPositionTable.ContainsKey(bone))
                    {
                        HumanBodyBonesPositionTable[bone] = pos;
                    }
                    else
                    {
                        HumanBodyBonesPositionTable.Add(bone, pos);
                    }

                    if (HumanBodyBonesRotationTable.ContainsKey(bone))
                    {
                        HumanBodyBonesRotationTable[bone] = rot;
                    }
                    else
                    {
                        HumanBodyBonesRotationTable.Add(bone, rot);
                    }
                }
                //受信と更新のタイミングは切り離した
            }
            //ブレンドシェープ同期
            else if (message.address == "/VMC/Ext/Blend/Val" &&
                     (message.values[0] is string) &&
                     (message.values[1] is float)
                     )
            {
                if (BlendShapeSynchronize && blendShapeProxy != null)
                {
                    blendShapeProxy.AccumulateValue((string)message.values[0], (float)message.values[1]);
                }
            }
            //ブレンドシェープ適用
            else if (message.address == "/VMC/Ext/Blend/Apply")
            {
                if (BlendShapeSynchronize && blendShapeProxy != null)
                {
                    blendShapeProxy.Apply();
                }
            }
        }
コード例 #27
0
    void OnDataReceived(uOSC.Message message)
    {
        //有効なとき以外処理しない
        if (this.isActiveAndEnabled)
        {
            //仮想コントローラー V2.3
            if (message.address == "/VMC/Ext/Con/Pos" &&
                (message.values[0] is string) &&
                (message.values[1] is float) &&
                (message.values[2] is float) &&
                (message.values[3] is float) &&
                (message.values[4] is float) &&
                (message.values[5] is float) &&
                (message.values[6] is float) &&
                (message.values[7] is float)
                )
            {
                string serial         = (string)message.values[0];
                var    rigidTransform = SetTransform(ref pos, ref rot, ref message);

                if (virtualController.ContainsKey(serial))
                {
                    virtualController[serial] = rigidTransform;
                }
                else
                {
                    virtualController.Add(serial, rigidTransform);
                }
            }
            //仮想トラッカー V2.3
            else if ((message.address == "/VMC/Ext/Hmd/Pos" ||
                      message.address == "/VMC/Ext/Tra/Pos") &&
                     (message.values[0] is string) &&
                     (message.values[1] is float) &&
                     (message.values[2] is float) &&
                     (message.values[3] is float) &&
                     (message.values[4] is float) &&
                     (message.values[5] is float) &&
                     (message.values[6] is float) &&
                     (message.values[7] is float)
                     )
            {
                string serial         = (string)message.values[0];
                var    rigidTransform = SetTransform(ref pos, ref rot, ref message);

                if (virtualTracker.ContainsKey(serial))
                {
                    virtualTracker[serial] = rigidTransform;
                }
                else
                {
                    virtualTracker.Add(serial, rigidTransform);
                }
            }
            //フレーム設定 V2.3
            else if (message.address == "/VMC/Ext/Set/Period" &&
                     (message.values[0] is int) &&
                     (message.values[1] is int) &&
                     (message.values[2] is int) &&
                     (message.values[3] is int) &&
                     (message.values[4] is int) &&
                     (message.values[5] is int)
                     )
            {
                externalSender.periodStatus     = (int)message.values[0];
                externalSender.periodRoot       = (int)message.values[1];
                externalSender.periodBone       = (int)message.values[2];
                externalSender.periodBlendShape = (int)message.values[3];
                externalSender.periodCamera     = (int)message.values[4];
                externalSender.periodDevices    = (int)message.values[5];
            }
            //Virtual MIDI CC V2.3
            else if (message.address == "/VMC/Ext/Midi/CC/Val" &&
                     (message.values[0] is int) &&
                     (message.values[1] is float)
                     )
            {
                MIDICCWrapper.KnobUpdated(0, (int)message.values[0], (float)message.values[1]);
            }
            //Camera Control V2.3
            else if (message.address == "/VMC/Ext/Cam" &&
                     (message.values[0] is string) &&
                     (message.values[1] is float) &&
                     (message.values[2] is float) &&
                     (message.values[3] is float) &&
                     (message.values[4] is float) &&
                     (message.values[5] is float) &&
                     (message.values[6] is float) &&
                     (message.values[7] is float) &&
                     (message.values[8] is float)
                     )
            {
                pos.x = (float)message.values[1];
                pos.y = (float)message.values[2];
                pos.z = (float)message.values[3];
                rot.x = (float)message.values[4];
                rot.y = (float)message.values[5];
                rot.z = (float)message.values[6];
                rot.w = (float)message.values[7];
                float fov = (float)message.values[8];

                //FreeCameraじゃなかったらFreeCameraにする
                if (ControlWPFWindow.CurrentSettings.CameraType != UnityMemoryMappedFile.CameraTypes.Free)
                {
                    window.ChangeCamera(UnityMemoryMappedFile.CameraTypes.Free);
                }

                //カメラ制御を切る
                window.FreeCamera.GetComponent <CameraMouseControl>().enabled = false;

                //座標とFOVを適用
                window.FreeCamera.transform.position = pos;
                window.FreeCamera.transform.rotation = rot;
                window.FreeCamera.fieldOfView        = fov;
            } //ブレンドシェープ同期
            else if (message.address == "/VMC/Ext/Blend/Val" &&
                     (message.values[0] is string) &&
                     (message.values[1] is float)
                     )
            {
                if (blendShapeProxy != null)
                {
                    blendShapeProxy.AccumulateValue((string)message.values[0], (float)message.values[1]);
                }
            }
            //ブレンドシェープ適用
            else if (message.address == "/VMC/Ext/Blend/Apply")
            {
                if (blendShapeProxy != null)
                {
                    blendShapeProxy.Apply();
                }
            }//外部アイトラ V2.3
            else if (message.address == "/VMC/Ext/Set/Eye" &&
                     (message.values[0] is int) &&
                     (message.values[1] is float) &&
                     (message.values[2] is float) &&
                     (message.values[3] is float)
                     )
            {
                bool enable = ((int)message.values[0]) != 0;
                pos.x = (float)message.values[1];
                pos.y = (float)message.values[2];
                pos.z = (float)message.values[3];

                if (enable)
                {
                    //ターゲットが存在しなければ作る
                    if (lookTargetOSC == null)
                    {
                        lookTargetOSC = new GameObject();
                        lookTargetOSC.transform.parent = null;
                        lookTargetOSC.name             = "lookTargetOSC";
                    }
                    //位置を書き込む
                    if (lookTargetOSC.transform != null)
                    {
                        lookTargetOSC.transform.position = pos;
                    }

                    //視線に書き込む
                    if (vrmLookAtHead != null)
                    {
                        vrmLookAtHead.Target = lookTargetOSC.transform;
                    }
                }
                else
                {
                    //視線を止める
                    if (vrmLookAtHead != null)
                    {
                        vrmLookAtHead.Target = null;
                    }
                }
            }
        }
    }
コード例 #28
0
 /// <summary>
 /// 指定されたブレンドシェイプに、現在計算したまばたきブレンドシェイプの値を適用する
 /// </summary>
 /// <param name="proxy"></param>
 public void Apply(VRMBlendShapeProxy proxy)
 {
     proxy.AccumulateValue(BlinkLKey, _currentBlinkValue);
     proxy.AccumulateValue(BlinkRKey, _currentBlinkValue);
 }
コード例 #29
0
 public void Reset(VRMBlendShapeProxy proxy)
 {
     proxy.AccumulateValue(BlinkLKey, 0);
     proxy.AccumulateValue(BlinkRKey, 0);
 }