public void 初期化する(PMXモデル model, モーフ管理 morph, スキニング skinning, バッファ管理 bufferManager)
        {
            _スキニング = skinning;

            _Stopwatch = new Stopwatch();
            _Stopwatch.Start();

            _モーフ管理 = morph;

            モーションリスト = new List <KeyValuePair <string, モーション> >();
        }
        public PMXボーン(List <MMDFileParser.PMXModelParser.ボーン> bones, int index, int layer, スキニング skinning)
        {
            var me = bones[index];   //このボーン

            _スキニング = skinning;
            _スキニング.ボーン配列[index] = this;
            ボーンインデックス           = index;
            ローカル位置   = me.位置;
            ボーン名     = me.ボーン名;
            ローカル軸あり  = me.ローカル軸あり;
            形階層      = layer;
            形階層の物理前後 = me.物理後変形である ?  形階層の物理前後指定種別.物理演算後 :  形階層の物理前後指定種別.物理演算前;

            if (ローカル軸あり)
            {
                DefaultLocalX = me.ローカル軸のX軸の方向ベクトル;
                DefaultLocalY = Vector3.Cross(me.ローカル軸のZ軸の方向ベクトル, DefaultLocalX);
                DefaultLocalZ = Vector3.Cross(DefaultLocalX, DefaultLocalY);
            }

            if (me.IKボーンである)
            {
                skinning.IKボーンリスト.Add(this);

                // IK関連の情報をボーン(me)から取得

                IKボーンである          = true;
                IK単位角             = me.IK単位角rad;
                _IKターゲットボーンインデックス = me.IKターゲットボーンインデックス;
                IK演算のLoop回数       = me.IKループ回数;
                foreach (MMDFileParser.PMXModelParser.ボーン.IKリンク ikLink in me.IKリンクリスト)
                {
                    this.IKリンクリスト.Add(new IKリンク(new WeakReference <スキニング>(skinning), ikLink));
                }
            }

            回転付与される = me.回転付与される;
            移動付与される = me.移動付与される;

            if (me.付与親ボーンインデックス == -1)
            {
                回転付与される = false;
                移動付与される = false;
            }

            if (移動付与される || 回転付与される)
            {
                付与親ボーンインデックス = me.付与親ボーンインデックス;
                付与率          = me.付与率;
            }
            else
            {
                付与親ボーンインデックス = -1;
            }

            for (int i = 0; i < bones.Count; i++)
            {
                MMDFileParser.PMXModelParser.ボーン bone = bones[i];

                if (bone.親ボーンのインデックス == index)
                {
                    var child = new PMXボーン(bones, i, layer + 1, skinning);

                    子ボーンを追加する(child);
                }
            }
        }
Beispiel #3
0
        public void D3Dスキニングバッファを更新する(スキニング skelton, エフェクト effect)
        {
            if (!(D3Dスキニングバッファをリセットする))
            {
                return;
            }

            var skinning   = (skelton as PMXスケルトン) ?? throw new System.NotSupportedException("PMXバッファ管理クラスでは、スキニングとして PMXスケルトン クラスを指定してください。");
            var d3dContext = RenderContext.Instance.DeviceManager.D3DDeviceContext;


            // エフェクト変数にボーンの情報を設定する。

            this._D3DBoneTransデータストリーム.WriteRange(skinning.ボーンのモデルポーズ配列);
            this._D3DBoneTransデータストリーム.Position = 0;
            d3dContext.UpdateSubresource(new DataBox(_D3DBoneTransデータストリーム.DataPointer, 0, 0), _D3DBoneTrans定数バッファ, 0);
            effect.D3DEffect.GetConstantBufferByName("BoneTransBuffer").SetConstantBuffer(this._D3DBoneTrans定数バッファ);

            this._D3DBoneLocalPositionデータストリーム.WriteRange(skinning.ボーンのローカル位置);
            this._D3DBoneLocalPositionデータストリーム.Position = 0;
            d3dContext.UpdateSubresource(new DataBox(_D3DBoneLocalPositionデータストリーム.DataPointer, 0, 0), _D3DBoneLocalPosition定数バッファ, 0);
            effect.D3DEffect.GetConstantBufferByName("BoneLocalPositionBuffer").SetConstantBuffer(this._D3DBoneLocalPosition定数バッファ);

            this._D3DBoneQuaternionデータストリーム.WriteRange(skinning.ボーンの回転);
            this._D3DBoneQuaternionデータストリーム.Position = 0;
            d3dContext.UpdateSubresource(new DataBox(_D3DBoneQuaternionデータストリーム.DataPointer, 0, 0), _D3DBoneQuaternion定数バッファ, 0);
            effect.D3DEffect.GetConstantBufferByName("BoneQuaternionBuffer").SetConstantBuffer(this._D3DBoneQuaternion定数バッファ);


            // 現在の入力頂点リストをスキニングバッファに転送する。

            this._頂点データストリーム.WriteRange(入力頂点リスト);
            this._頂点データストリーム.Position = 0;
            d3dContext.UpdateSubresource(new DataBox(_頂点データストリーム.DataPointer, 0, 0), D3Dスキニングバッファ, 0);


            // 使用するtechniqueを検索する。

            テクニック technique =
                (from teq in effect.テクニックリスト
                 where
                 teq.テクニックを適用する描画対象 == MMDPass種別.スキニング
                 select teq).FirstOrDefault();

            if (null != technique)
            {
                // パスを通じてコンピュートシェーダーステートを設定する。

                technique.パスリスト.ElementAt(0).Value.D3DPass.Apply(d3dContext);


                // コンピュートシェーダーでスキニングを実行し、結果を頂点バッファに格納する。

                d3dContext.ComputeShader.SetShaderResource(0, this.D3DスキニングバッファSRView);
                d3dContext.ComputeShader.SetUnorderedAccessView(0, this.D3D頂点バッファビューUAView);
                d3dContext.Dispatch((入力頂点リスト.Length / 64) + 1, 1, 1);
            }

            // UAVを外す(このあと頂点シェーダーが使えるように)

            d3dContext.ComputeShader.SetUnorderedAccessView(0, null);


            #region " (CPUで行ったときのソース)"
            //----------------

            /*
             * var boneTrans = skinning.ボーンのモデルポーズ配列;
             * var スキニング後の入力頂点リスト = new VS_INPUT[ 入力頂点リスト.Length ];
             *
             * for( int i = 0; i < 入力頂点リスト.Length; i++ )
             * {
             *  switch( 入力頂点リスト[ i ].変形方式 )
             *  {
             *      case (uint) 変形方式.BDEF1:
             #region " *** "
             *          //----------------
             *          {
             *              var 頂点 = 入力頂点リスト[ i ];
             *
             *              Matrix bt =
             *                  boneTrans[ 頂点.BoneIndex1 ];
             *
             *              if( Matrix.Zero == bt )
             *                  bt = Matrix.Identity;
             *
             *              スキニング後の入力頂点リスト[ i ].Position = Vector4.Transform( 頂点.Position, bt );
             *              スキニング後の入力頂点リスト[ i ].Normal = Vector3.TransformNormal( 頂点.Normal, bt );
             *              スキニング後の入力頂点リスト[ i ].Normal.Normalize();
             *          }
             *          //----------------
             #endregion
             *          break;
             *
             *      case (uint) 変形方式.BDEF2:
             #region " *** "
             *          //----------------
             *          {
             *              var 頂点 = 入力頂点リスト[ i ];
             *
             *              Matrix bt =
             *                  boneTrans[ 頂点.BoneIndex1 ] * 頂点.BoneWeight1 +
             *                  boneTrans[ 頂点.BoneIndex2 ] * 頂点.BoneWeight2;
             *
             *              if( Matrix.Zero == bt )
             *                  bt = Matrix.Identity;
             *
             *              スキニング後の入力頂点リスト[ i ].Position = Vector4.Transform( 頂点.Position, bt );
             *              スキニング後の入力頂点リスト[ i ].Normal = Vector3.TransformNormal( 頂点.Normal, bt );
             *              スキニング後の入力頂点リスト[ i ].Normal.Normalize();
             *          }
             *          //----------------
             #endregion
             *          break;
             *
             *      case (uint) 変形方式.BDEF4:
             #region " *** "
             *          //----------------
             *          {
             *              var 頂点 = 入力頂点リスト[ i ];
             *
             *              Matrix bt =
             *                  boneTrans[ 頂点.BoneIndex1 ] * 頂点.BoneWeight1 +
             *                  boneTrans[ 頂点.BoneIndex2 ] * 頂点.BoneWeight2 +
             *                  boneTrans[ 頂点.BoneIndex3 ] * 頂点.BoneWeight3 +
             *                  boneTrans[ 頂点.BoneIndex4 ] * 頂点.BoneWeight4;
             *
             *              if( Matrix.Zero == bt )
             *                  bt = Matrix.Identity;
             *
             *              スキニング後の入力頂点リスト[ i ].Position = Vector4.Transform( 頂点.Position, bt );
             *              スキニング後の入力頂点リスト[ i ].Normal = Vector3.TransformNormal( 頂点.Normal, bt );
             *              スキニング後の入力頂点リスト[ i ].Normal.Normalize();
             *          }
             *          //----------------
             #endregion
             *          break;
             *
             *      case (uint) 変形方式.SDEF:
             #region " *** "
             *          //----------------
             *          {
             *              // 参考:
             *              // 自分用メモ「PMXのスフィリカルデフォームのコードっぽいもの」(sma42氏)
             *              // https://www.pixiv.net/member_illust.php?mode=medium&illust_id=60755964
             *
             *              var 頂点 = 入力頂点リスト[ i ];
             *
             #region " 影響度0,1 の算出 "
             *              //----------------
             *              float 影響度0 = 0f;  // 固定値であるSDEFパラメータにのみ依存するので、これらの値も固定値。
             *              float 影響度1 = 0f;  //
             *              {
             *                  float L0 = ( 頂点.SdefR0 - (Vector3) skinning.ボーン配列[ 頂点.BoneIndex2 ].ローカル位置 ).Length();   // 子ボーンからR0までの距離
             *                  float L1 = ( 頂点.SdefR1 - (Vector3) skinning.ボーン配列[ 頂点.BoneIndex2 ].ローカル位置 ).Length();   // 子ボーンからR1までの距離
             *
             *                  影響度0 = ( System.Math.Abs( L0 - L1 ) < 0.0001f ) ? 0.5f : SharpDX.MathUtil.Clamp( L0 / ( L0 + L1 ), 0.0f, 1.0f );
             *                  影響度1 = 1.0f - 影響度0;
             *              }
             *              //----------------
             #endregion
             *
             *              Matrix モデルポーズ行列L = boneTrans[ 頂点.BoneIndex1 ] * 頂点.BoneWeight1;
             *              Matrix モデルポーズ行列R = boneTrans[ 頂点.BoneIndex2 ] * 頂点.BoneWeight2;
             *              Matrix モデルポーズ行列C = モデルポーズ行列L + モデルポーズ行列R;
             *
             *              Vector4 点C = Vector4.Transform( 頂点.Sdef_C, モデルポーズ行列C );    // BDEF2で計算された点Cの位置
             *              Vector4 点P = Vector4.Transform( 頂点.Position, モデルポーズ行列C );  // BDEF2で計算された頂点の位置
             *
             *              Matrix 重み付き回転行列 = Matrix.RotationQuaternion(
             *                  Quaternion.Slerp(   // 球体線形補間
             *                      skinning.ボーン配列[ 頂点.BoneIndex1 ].回転 * 頂点.BoneWeight1,
             *                      skinning.ボーン配列[ 頂点.BoneIndex2 ].回転 * 頂点.BoneWeight2,
             *                      頂点.BoneWeight1 ) );
             *
             *              Vector4 点R0 = Vector4.Transform( new Vector4( 頂点.SdefR0, 1f ), ( モデルポーズ行列L + ( モデルポーズ行列C * -頂点.BoneWeight1 ) ) );
             *              Vector4 点R1 = Vector4.Transform( new Vector4( 頂点.SdefR1, 1f ), ( モデルポーズ行列R + ( モデルポーズ行列C * -頂点.BoneWeight2 ) ) );
             *              点C += ( 点R0 * 影響度0 ) + ( 点R1 * 影響度1 );   // 膨らみすぎ防止
             *
             *              点P -= 点C;     // 頂点を点Cが中心になるよう移動して
             *              点P = Vector4.Transform( 点P, 重み付き回転行列 );   // 回転して
             *              点P += 点C;     // 元の位置へ
             *
             *              スキニング後の入力頂点リスト[ i ].Position = 点P;
             *              スキニング後の入力頂点リスト[ i ].Normal = Vector3.TransformNormal( 頂点.Normal, 重み付き回転行列 );
             *              スキニング後の入力頂点リスト[ i ].Normal.Normalize();
             *          }
             *          //----------------
             #endregion
             *          break;
             *
             *      case (uint) 変形方式.QDEF:
             #region " *** "
             *          //----------------
             *          {
             *              // ※ QDEFを使ったモデルが見つからないのでテストしてません。あれば教えてください!
             *
             *              var 頂点 = 入力頂点リスト[ i ];
             *
             *              var dualQuaternion = new DualQuaternion[ 4 ];   // 最大4ボーンまで対応
             *
             *              var boneIndexes = new[] { 頂点.BoneIndex1, 頂点.BoneIndex2, 頂点.BoneIndex3, 頂点.BoneIndex4 };
             *              var boneWeights = new[] { 頂点.BoneWeight1, 頂点.BoneWeight2, 頂点.BoneWeight3, 頂点.BoneWeight4 };
             *
             *              for( int b = 0; b < 4; b++ )
             *              {
             *                  if( boneWeights[ b ] == 0f )
             *                  {
             *                      dualQuaternion[ b ] = DualQuaternion.Zero;  // 未使用
             *                  }
             *                  else
             *                  {
             *                      dualQuaternion[ b ] = new DualQuaternion( boneTrans[ boneIndexes[ b ] ] );
             *                  }
             *              }
             *
             *              Matrix bt = (
             *                  dualQuaternion[ 0 ] * boneWeights[ 0 ] +
             *                  dualQuaternion[ 1 ] * boneWeights[ 1 ] +
             *                  dualQuaternion[ 2 ] * boneWeights[ 2 ] +
             *                  dualQuaternion[ 3 ] * boneWeights[ 3 ] ).ToMatrix();
             *
             *              if( Matrix.Zero == bt )
             *                  bt = Matrix.Identity;
             *
             *              スキニング後の入力頂点リスト[ i ].Position = Vector4.Transform( 頂点.Position, bt );
             *              スキニング後の入力頂点リスト[ i ].Normal = 頂点.Normal;
             *          }
             *          //----------------
             #endregion
             *          break;
             *  }
             *
             *  スキニング後の入力頂点リスト[ i ].UV = 入力頂点リスト[ i ].UV;
             *  スキニング後の入力頂点リスト[ i ].AddUV1 = 入力頂点リスト[ i ].AddUV1;
             *  スキニング後の入力頂点リスト[ i ].AddUV2 = 入力頂点リスト[ i ].AddUV2;
             *  スキニング後の入力頂点リスト[ i ].AddUV3 = 入力頂点リスト[ i ].AddUV3;
             *  スキニング後の入力頂点リスト[ i ].AddUV4 = 入力頂点リスト[ i ].AddUV4;
             *  スキニング後の入力頂点リスト[ i ].EdgeWeight = 入力頂点リスト[ i ].EdgeWeight;
             *  スキニング後の入力頂点リスト[ i ].Index = 入力頂点リスト[ i ].Index;
             * }
             *
             * // データストリームに、スキニング後の入力頂点リストを書き込む。
             * _頂点データストリーム.WriteRange( スキニング後の入力頂点リスト );
             * _頂点データストリーム.Position = 0;
             *
             * // D3D頂点バッファに、スキニング後の入力頂点リストを(データストリーム経由で)書き込む。
             * RenderContext.Instance.DeviceManager.D3DDeviceContext.UpdateSubresource( new DataBox( _頂点データストリーム.DataPointer, 0, 0 ), D3D頂点バッファ, 0 );
             */
            //----------------
            #endregion

            D3Dスキニングバッファをリセットする = false;
        }