Ejemplo n.º 1
0
        public void ボーンを指定したフレームの姿勢に更新する(float 目標フレーム)
        {
            // 目標フレームの前後のキーフレームを探す

            _frameManager.現在のフレームの前後のキーフレームを探して返す(目標フレーム, out MMDFileParser.IFrameData 過去フレーム, out MMDFileParser.IFrameData 未来フレーム);

            var 過去のボーンフレーム = (ボーンフレーム)過去フレーム;
            var 未来のボーンフレーム = (ボーンフレーム)未来フレーム;


            // 目標フレームの前後キーフレーム間での進行度を求めてペジェ関数で変換する

            float 進行度合0to1 = (未来のボーンフレーム.フレーム番号 == 過去のボーンフレーム.フレーム番号) ? 0 :
                             (float)(目標フレーム - 過去のボーンフレーム.フレーム番号) / (float)(未来のボーンフレーム.フレーム番号 - 過去のボーンフレーム.フレーム番号);          // リニア

            var 移行度合 = new float[4];

            for (int i = 0; i < 4; i++)
            {
                移行度合[i] = 過去のボーンフレーム.ベジェ曲線[i].横位置Pxに対応する縦位置Pyを返す(進行度合0to1);         // リニア → ベジェ[4]
            }
            // ボーンを更新する

            _ボーン.移動 = CGHelper.ComplementTranslate(過去のボーンフレーム, 未来のボーンフレーム, new Vector3(移行度合[0], 移行度合[1], 移行度合[2]));

            _ボーン.回転 = CGHelper.ComplementRotateQuaternion(過去のボーンフレーム, 未来のボーンフレーム, 移行度合[3]);
        }
        /// <summary>
        /// ボーンを指定したフレーム番号の姿勢に更新する
        /// </summary>
        /// <param name="frameNumber">フレーム番号</param>
        public void ReviseBone(ulong frameNumber)
        {
            // 現在のフレームの前後のキーフレームを探す
            MMDFileParser.IFrameData pastFrame, futureFrame;
            frameManager.現在のフレームの前後のキーフレームを探して返す(frameNumber, out pastFrame, out futureFrame);
            var pastBoneFrame   = (BoneFrame)pastFrame;
            var futureBoneFrame = (BoneFrame)futureFrame;

            // 現在のフレームの前後キーフレーム間での進行度を求めてペジェ関数で変換する
            float s = (pastBoneFrame.frameNumber == futureBoneFrame.frameNumber) ? 0 :
                      (float)(frameNumber - pastBoneFrame.frameNumber) / (float)(futureBoneFrame.frameNumber - pastBoneFrame.frameNumber);                 // 進行度
            BezInterpolParams p = pastBoneFrame.interpolParameters;
            float             s_X, s_Y, s_Z, s_R;

            if (p != null)
            {
                s_X = BezEvaluate(p.X1, p.X2, s);
                s_Y = BezEvaluate(p.Y1, p.Y2, s);
                s_Z = BezEvaluate(p.Z1, p.Z2, s);
                s_R = BezEvaluate(p.R1, p.R2, s);                   // ペジェ変換後の進行度
            }
            else
            {            //ベジェ曲線のパラメータがないときは線形補完の量としてsを利用する
                s_X = s_Y = s_Z = s_R = s;
            }
            // ボーンを更新する
            bone.移動 = new SharpDX.Vector3(
                CGHelper.Lerp(pastBoneFrame.position.x, futureBoneFrame.position.x, s_X),
                CGHelper.Lerp(pastBoneFrame.position.y, futureBoneFrame.position.y, s_Y),
                CGHelper.Lerp(pastBoneFrame.position.z, futureBoneFrame.position.z, s_Z));
            bone.回転 = SharpDX.Quaternion.Slerp(pastBoneFrame.rotation.ToSharpDX(), futureBoneFrame.rotation.ToSharpDX(), s_R);
        }
Ejemplo n.º 3
0
        public float 指定したフレームにおけるモーフ値を取得する(float フレーム)
        {
            // 現在のフレームの前後のキーフレームを探す
            MMDFileParser.IFrameData 前フレーム, 後フレーム;

            _frameManager.現在のフレームの前後のキーフレームを探して返す(フレーム, out 前フレーム, out 後フレーム);

            var pastMorphFrame   = (モーフフレーム)前フレーム;
            var futureMorphFrame = (モーフフレーム)後フレーム;

            // 現在のフレームの前後キーフレーム間での進行度を求めてペジェ関数で変換する
            float s = (futureMorphFrame.フレーム番号 == pastMorphFrame.フレーム番号) ? 0 :
                      (float)(フレーム - pastMorphFrame.フレーム番号) / (float)(futureMorphFrame.フレーム番号 - pastMorphFrame.フレーム番号);                 // 進行度

            return(CGHelper.Lerp(pastMorphFrame.モーフ値, futureMorphFrame.モーフ値, s));
        }
Ejemplo n.º 4
0
        public float 指定したフレームにおけるモーフ値を取得する(ulong フレーム)
        {
            // 現在のフレームの前後のキーフレームを探す
            MMDFileParser.IFrameData 前フレーム, 後フレーム;

            _frameManager.現在のフレームの前後のキーフレームを探して返す(フレーム, out 前フレーム, out 後フレーム);

            var pastMorphFrame   = (MorphFrame)前フレーム;
            var futureMorphFrame = (MorphFrame)後フレーム;

            // 現在のフレームの前後キーフレーム間での進行度を求める
            float s = (futureMorphFrame.frameNumber == pastMorphFrame.frameNumber) ? 0 :
                      (float)(フレーム - pastMorphFrame.frameNumber) / (float)(futureMorphFrame.frameNumber - pastMorphFrame.frameNumber);                 // 進行度

            // 線形補完で値を求める
            return(CGHelper.Lerp(pastMorphFrame.value, futureMorphFrame.value, s));
        }
Ejemplo n.º 5
0
        private void _フレームを更新する(カメラフレーム cameraFrame1, カメラフレーム cameraFrame2, カメラ camera, 射影 projection, float 進行度合い0to1)
        {
            float ProgX = cameraFrame1.ベジェ曲線[0].横位置Pxに対応する縦位置Pyを返す(進行度合い0to1);
            float ProgY = cameraFrame1.ベジェ曲線[1].横位置Pxに対応する縦位置Pyを返す(進行度合い0to1);
            float ProgZ = cameraFrame1.ベジェ曲線[2].横位置Pxに対応する縦位置Pyを返す(進行度合い0to1);
            float ProgR = cameraFrame1.ベジェ曲線[3].横位置Pxに対応する縦位置Pyを返す(進行度合い0to1);
            float ProgL = cameraFrame1.ベジェ曲線[4].横位置Pxに対応する縦位置Pyを返す(進行度合い0to1);
            float ProgP = cameraFrame1.ベジェ曲線[5].横位置Pxに対応する縦位置Pyを返す(進行度合い0to1);

            // カメラ(ビュー)

            camera.移動する(
                注視点からの距離: CGHelper.Lerp(cameraFrame1.距離, cameraFrame2.距離, ProgL),
                注視点の位置: CGHelper.ComplementTranslate(cameraFrame1, cameraFrame2, new Vector3(ProgX, ProgY, ProgZ)),
                回転: CGHelper.ComplementRotateQuaternion(cameraFrame1, cameraFrame2, ProgR));

            // 射影

            float angle = CGHelper.Lerp(cameraFrame1.視野角, cameraFrame2.視野角, ProgP);

            projection.視野角rad = CGHelper.ToRadians(angle);
        }
Ejemplo n.º 6
0
        private bool _一回のIK演算を実行する(PMXボーン IKbone)
        {
            var エフェクタ = IKbone.IKターゲットボーン;
            var ターゲット = IKbone;

            // すべての IKリンク について……
            foreach (var ikLink in IKbone.IKリンクリスト)
            {
                var IKリンクのローカル座標へ変換する行列 = Matrix.Invert(ikLink.IKリンクボーン.モデルポーズ行列);

                var IKリンクローカル座標でのエフェクタ位置 = Vector3.TransformCoordinate(エフェクタ.ローカル位置, エフェクタ.モデルポーズ行列 * IKリンクのローカル座標へ変換する行列);
                var IKリンクローカル座標でのターゲット位置 = Vector3.TransformCoordinate(ターゲット.ローカル位置, ターゲット.モデルポーズ行列 * IKリンクのローカル座標へ変換する行列);

                var V1 = Vector3.Normalize(IKリンクローカル座標でのエフェクタ位置 - ikLink.IKリンクボーン.ローカル位置);
                var V2 = Vector3.Normalize(IKリンクローカル座標でのターゲット位置 - ikLink.IKリンクボーン.ローカル位置);


                // IKリンクを更新する

                ikLink.現在のループ回数++;


                // 回転軸 Vaxis = v1×v2 を計算する。

                var Vaxis = Vector3.Cross(V1, V2);


                // 回転軸周りの回転角 θa = Cos-1(V1・V2) を計算する。

                var 内積 = (double)Vector3.Dot(V1, V2);
                内積 = Math.Max(Math.Min(内積, 1.0), -1.0); // 誤差丸め

                double θa = Math.Acos(内積);              // 内積: -1 → 1  のとき、θa: π → 0
                θa = Math.Min(θa, IKbone.IK単位角);        // θa は単位角を超えないこと
                if (θa <= 0.00001)
                {
                    continue;                         // θa が小さすぎたら無視
                }
                // Vaxis と θa から、回転クォータニオンを計算する。

                var 回転クォータニオン = Quaternion.RotationAxis(Vaxis, (float)θa);
                回転クォータニオン.Normalize();


                // IKリンクに回転クォータニオンを適用する。

                ikLink.IKリンクボーン.回転 *= 回転クォータニオン;


                // 回転量制限があれば適用する。

                if (ikLink.回転制限がある)
                {
                    #region " 回転量制限 "
                    //----------------
                    float X軸回転角, Y軸回転角, Z軸回転角;

                    // 回転にはクォータニオンを使っているが、PMXのボーンの最小回転量・最大回転量は、クォータニオンではなくオイラー角(X,Y,Z)で指定される。
                    // そのため、回転数制限の手順は
                    //  (1) クォータニオンをいったんオイラー角(X,Y,Z)に変換
                    //  (2) X,Y,Z に対して回転量制限チェック
                    //  (3) オイラー角を再びクォータニオンに戻す
                    // となる。
                    //
                    // また、オイラー角で回転を表す場合、各軸の回転の順番が重要となる。
                    // ここでは、
                    //  (A) X → Y → Z の順
                    //  (B) Y → Z → X の順
                    //  (C) Z → X → Y の順
                    // の3通りを調べて、ジンバルロックが発生しない最初の分解値を採用する。

                    if (CGHelper.クォータニオンをXYZ回転に分解する(ikLink.IKリンクボーン.回転, out X軸回転角, out Y軸回転角, out Z軸回転角))       // ジンバルロックが発生しなければ true
                    {
                        // (A) XYZ 回転

                        var clamped = Vector3.Clamp(
                            new Vector3(X軸回転角, Y軸回転角, Z軸回転角).オイラー角の値域を正規化する(),
                            ikLink.最小回転量,
                            ikLink.最大回転量);

                        X軸回転角 = clamped.X;
                        Y軸回転角 = clamped.Y;
                        Z軸回転角 = clamped.Z;

                        ikLink.IKリンクボーン.回転 = Quaternion.RotationMatrix(Matrix.RotationX(X軸回転角) * Matrix.RotationY(Y軸回転角) * Matrix.RotationZ(Z軸回転角)); // X, Y, Z の順
                    }
                    else if (CGHelper.クォータニオンをYZX回転に分解する(ikLink.IKリンクボーン.回転, out Y軸回転角, out Z軸回転角, out X軸回転角))                                       // ジンバルロックが発生しなければ true
                    {
                        // (B) YZX 回転

                        var clamped = Vector3.Clamp(
                            new Vector3(X軸回転角, Y軸回転角, Z軸回転角).オイラー角の値域を正規化する(),
                            ikLink.最小回転量,
                            ikLink.最大回転量);

                        X軸回転角 = clamped.X;
                        Y軸回転角 = clamped.Y;
                        Z軸回転角 = clamped.Z;

                        ikLink.IKリンクボーン.回転 = Quaternion.RotationMatrix(Matrix.RotationY(Y軸回転角) * Matrix.RotationZ(Z軸回転角) * Matrix.RotationX(X軸回転角)); // Y, Z, X の順
                    }
                    else if (CGHelper.クォータニオンをZXY回転に分解する(ikLink.IKリンクボーン.回転, out Z軸回転角, out X軸回転角, out Y軸回転角))                                       // ジンバルロックが発生しなければ true
                    {
                        // (C) ZXY 回転

                        var clamped = Vector3.Clamp(
                            new Vector3(X軸回転角, Y軸回転角, Z軸回転角).オイラー角の値域を正規化する(),
                            ikLink.最小回転量,
                            ikLink.最大回転量);

                        X軸回転角 = clamped.X;
                        Y軸回転角 = clamped.Y;
                        Z軸回転角 = clamped.Z;

                        //ikLink.ikLinkBone.回転行列 = Quaternion.RotationYawPitchRoll( Y軸回転角, X軸回転角, Z軸回転角 );
                        ikLink.IKリンクボーン.回転 = Quaternion.RotationMatrix(Matrix.RotationZ(Z軸回転角) * Matrix.RotationX(X軸回転角) * Matrix.RotationY(Y軸回転角));            // Z, X, Y の順
                    }
                    else
                    {
                        // その他はエラー
                        continue;
                    }
                    //----------------
                    #endregion
                }

                // IKリンクの新しい回転行列を反映。
                ikLink.IKリンクボーン.モデルポーズを更新する();
            }

            return(true);
        }
 /// <summary>
 ///		現時点までに蓄積された三角形や四角形から、インデックスバッファを生成して返す。
 /// </summary>
 public Buffer インデックスバッファを作成する()
 {
     return(CGHelper.D3Dバッファを作成する(_IndexList, RenderContext.Instance.DeviceManager.D3DDevice, BindFlags.IndexBuffer));
 }