private void DrawModel(Model m) { // post process animation XSIAnimationData l_Animations = m.Tag as XSIAnimationData; // m.Tag(オブジェクト参照型)を、XSIAnimationDataクラス参照型に型変換し、l_Animationsに代入している。 // asはcastに似ているが、変換できないときはエラーにならずnullを返す。 // asの詳細については下記参照。 // http://www.atmarkit.co.jp/fdotnet/dotnettips/005castandas/castandas.html // // m.Tagには、このモデルを識別するオブジェクト(CrosswalkModel自身の参照値(ポインタ))が格納されている。 // 同一モデルを複数回読み込んだ場合、各インスタンスのCrosswalkModel.Tag(=m.Tag)には // 同じオブジェクトインスタンス(最初に読み込んだCrosswalkModelの参照値)が格納されている。 // よって、同一モデル複数回読込時は、メッシュ情報だけでなく、モーション関連情報も同一インスタンスのものを参照してしまう。 Matrix[] transforms = new Matrix[m.Bones.Count]; // ボーン数に応じたトランスフォーム情報(=モーション情報)格納用領域確保 m.CopyAbsoluteBoneTransformsTo(transforms); // モデル内の各ボーンのトランスフォーム (各ボーンのすべての親ボーンを基準とするトランスフォーム) を、transformsにコピーしている。 // 「親トランスフォームのコピー」「座標変換させるための元をコピー」 // デフォルト(モーション適用前?)のボーン位置情報をメモリに展開している。 bool isSkinned = false; Matrix[] bones = null; if (l_Animations != null) { l_Animations.ComputeBoneTransforms(transforms); // 実際に呼び出されるのはXSIAnimationDataクラスのComputeBoneTransforms()メソッド。 // その中で、BoneInvBindPoses(モデルファイルからロードされた情報。初期ポーズのトランスフォーム?)と // 引数transformsを掛け合わせている。これで初期ポーズ状態のボーン情報が完成?? bones = l_Animations.BoneTransforms; // 上記データをbonesに代入している。 if(bones.Length > 0) isSkinned = true; } foreach (ModelMesh mesh in m.Meshes) { SASData.Model = transforms[mesh.ParentBone.Index]; // 各メッシュの親元ボーンの位置情報をSASData.Modelに代入している。 // SASDataはSoftimageモデルデータ受け渡し用コンテナ。 // SASData.ModelはMatrix型で、XNAのワールド座標に該当する。 // 但し、Softimage付属fxファイルは、スキンモデルのワールド座標受け渡しに対応していないため、 // XNAからワールド座標を制御したい場合は、fxファイルの改修が必要。詳細は下記参照。 // http://tkina.blog60.fc2.com/blog-entry-156.html SASData.ComputeModel(); // ワールド/ビュー/プロジェクション情報等を計算し、パラメータをセット(シェーダーに渡す準備を)している。 foreach (Effect effect in mesh.Effects) { if (effect.GetType() == typeof(BasicEffect)) // エフェクトタイプをチェックしている。 // Softimageでエフェクトファイルを指定したモデルは、非BasicEffect扱いであろうと推測する。 { BasicEffect basiceffect = (BasicEffect)effect; basiceffect.EnableDefaultLighting(); basiceffect.PreferPerPixelLighting = true; basiceffect.Alpha = 0.5f; basiceffect.View = SASData.View; basiceffect.Projection = SASData.Projection; basiceffect.World = SASData.Model; // BasicEffectの場合は、fxファイルを改修しなくてもワールド座標が反映されるはず。 } else { // set the technique if (isSkinned && (effect.Techniques["Skinned"] != null)) { effect.CurrentTechnique = effect.Techniques["Skinned"]; } else { if (effect.Techniques["Static"] != null) { effect.CurrentTechnique = effect.Techniques["Static"]; } else { effect.CurrentTechnique = effect.Techniques[0]; } } // エフェクトテクニックを設定している。 // bind bones if (isSkinned) { if ((effect.Parameters["Bones"] != null) && isSkinned) effect.Parameters["Bones"].SetValue(bones); // ボーン情報をシェーダに渡している。 } // bind all other parameters foreach (EffectParameter Parameter in effect.Parameters) { SASData.SetEffectParameterValue(Parameter); // その他のエフェクトパラメータをシェーダに渡している。 } } } mesh.Draw(); } }