DirectGraphics�BアフィリエイトDirectGraphics�B前回、ポリゴンを使って画面上に四角形を描画しました。今回はそこに画像を貼り付けて、画面上に画像を表示してみましょう。いわゆるテクスチャーを張るというやつです。ハイレベルD3DCLKsへトップDirectXとは?環境構築DirectInput�@DirectGraphics�@DirectGraphics�ADirectGraphics�BDirectGraphics�Cテクスチャマッピング前回、今回と3Dエンジンを使って2Dのグラフィック表示を行っています。最低限DirectDrawの2D描画機能は実装したいところです。画像ファイルを読み込んでそれを表示するくらいの機能はないと話しになりません。今回はそれを実装します。GDI+などの描画機能で画像を表示するには、画像を持ったオブジェクト(Bitmapオブジェクトとか)から別の画像オブジェクトへ画像を転送します。Direct3Dには基本的にそのような機能はありません。そこで、それに近いテクスチャーマッピングを利用して画像の表示を行います。テクスチャマッピングとは、画像から必要な部分を切り出して、それをポリゴンに貼り付ける処理のことです。本来は、物体の模様なんかを画像として用意しておいて物体に貼り付けるもので、複雑な図形をすべて頂点計算して表示していると非常に時間がかかってしまうため、テクスチャマッピングを利用して処理を軽くしていることが多いようです。ポリゴンに画像を張るというのが、テクスチャマッピングの重要な概念になります。今回のサンプルプログラムGraphics�Aで作ったプログラムをさらに改良します。四角形に画像を貼り付けて画像を表示します。ゲーム的には、かなり実用的です。Direct3DSample3左の画面が今回のサンプルプログラムです。前回の四角に加えて、画像も表示してクルクルまわします。サンプルプログラム(dgsample3.lzh)プロジェクトは前回のものに改造を加えるので、前回のコードをベースに作っていきます。DirectGraphics�Aのサンプルプログラムをダウンロードして置いてください。テクスチャ座標コードの前に、テクスチャ座標の説明をします。テクスチャマッピングでは、画像の必要な部分をポリゴンに対して貼り付けます。その必要な部分を示すのがテクスチャ座標です。テクスチャ座標にはUV座標というものが使われています。左上の原点を(0,0)として横軸にU軸、縦軸にV軸を使用し、右下が(1,1)になるように座標を取っています。この座標を使って、テクスチャ画像内の任意の点を表します。このテクスチャ座標を各頂点に設定し、画像の任意の位置を切り出して表示するのです。CLKsTextureクラステクスチャの予備知識はこのくらいにして、テクスチャ画像を保管しておくCLKsTextureクラスを作ります。DirectXにTextureという画像を保存しておくクラスがあるのですが、画像以外にも情報を保管しておくと後々便利なことが多いので、今回はテクスチャ周りを一括管理できるクラスを作ることにします。今回のクラスには、�@Direct3D.Textureオブジェクトの保持と�Aファイル名を渡すと自動的に画像ファイルを読み込んでTextureオブジェクトを作る機能を実装します。tex;}}}これが、テクスチャーを管理するCLKsTextureクラスです。実際は、ただTextureオブジェクトを持っているだけなのですが、コンストラクタにファイル名を渡すと、自動的にTextureオブジェクトを作ってくれるのでちょっとだけ便利です。Textureインスタンスを作る際に、Direct3D.Deviceオブジェクトを渡さないといけないのですが、CLKsDGクラスにはDeviceを取得できる機能がないのでstatic変数としてDeviceを保持してあります。CLKsDGの初期化の部分でこの変数にインスタンスを設定すれば問題ないですね。今回、「tex」「dev」変数はprivateで宣言しておき、アクセスにはプロパティを使っています。プロパティはあたかも変数に設定、取得するようにメソッド呼び出しを行う機能で、C#特有のものです。設定、取得のどちらか一方しか出来ないようにも定義できます。今回はdevのアクセスはDirect3DDeviceプロパティで値の設定だけを、texはTextureプロパティで値の取得だけが出来るようになります。C#のコード的にはこのように直接変数をいじらず、publicメソッドやプロパティを使ってアクセスするのが綺麗なコードだそうです。プログラムの規模が大きくなると有り難味が分かるそうですが、小さいうちは面倒なだけですね。プロパティにの定義法については他のサイトで調べてみてください...LoadTextureメソッドさて、画像ファイルの読み込みとTextureインスタンスを生成するLoadTextureメソッドの説明をします。引数はファイル名とテクスチャのサイズを受け取って、Direct3D.Textureオブジェクトを返します。このテクスチャのサイズとは、実際にメモリ上に格納する画像のサイズで、読み込む先の画像のサイズではありませんので注意してください。いうのも、テクスチャとして使える画像のサイズは512×512とか、256×256とか特定のサイズしか扱えません。そこで、読み込みもとの画像と一番近そうなサイズを自分で選択して画像のサイズを変え、それをもとにテクスチャを生成しています。コードでは.NET標準の描画機能であるGDI+を使っているので、少し難しそうですね。tex;}説明しやすいようにもう一度切り出して書きました。.NETで画像を扱えるオブジェクトはいくつかありますが、今回はBitmapオブジェクトを使います。サイズ変更前の画像を格納しているのが「src」オブジェクトで、テクスチャ生成のもととなるのが「texbit」オブジェクトです。Bitmapクラスのコンストラクタの中にファイル名を渡すと、その画像を読み込んでオブジェクトを生成する機能があるのでそれを利用してsrcオブジェクトを生成しています。texbitはsizeで指定された大きさの空のオブジェクトを生成しています。次に、srcからtexbitへ画像を転送します。GDI+では、画像の転送先のBitmapからGraphicsオブジェクトを取得し、それを使って画像の転送を行います。BitmapからGraphicsを取得するにはGraphicsのstaticメソッドであるFromImageを使い、画像の転送にはDrawImageメソッドを使います。DrawImageには多くのオーバーロードメソッドがあるので、一度調べてみるといいと思います。texbitへ画像を転送したら、いよいよTextureオブジェクトの生成です。BitmapからDirect3D.Textureを生成するには、staticメソッドFromBitmapを使います。引数にはstaticで保持してあるDirect3D.Deviceを、第二引数にBitmapオブジェクトを、そのほかの引数には...このとおり渡してください。して生成したTextureオブジェクトを返せば機能的に完成です。一つ、GDI+周りで作ったオブジェクトは解放をしなくてはなりません。Textureオブジェクトを作り終わった時点で、src・texbit・gのオブジェクトはもう不要ですね。C#では基本的にいらなくなったオブジェクトは自動的に消してくれるのですが、ここら辺のオブジェクトは参照変数が消えても、インスタンスが消えない場合があります。そのため明示的にインスタンスを消す必要性があります。それを行っているのが各クラスの「Dispose」メソッドです。CLKsDGクラスを改良CLKsTextureクラスの定義が終わったところで、前回まで作っていたCLsDGクラスにテクスチャマッピングの機能を追加しましょう。先ほど作ったCLKsTextureクラスのstatic変数devにDirect3D.Deviceを渡しておかないといけません。device;}Direct3DDeviceプロパティに代入するだけで設定は完了です。Textureを描画-DrawTextureメソッド次に、Texture描画用に新しくメソッドを追加します。描画先の情報と、テクスチャ座標、あとはDirect3Dの恩恵を多少なり受けられるように頂点色の情報を受け取ってテクスチャを描画するDrawTextureメソッドを作ります。1f;}device.SetTexture(0,Tex.Texture);this.drawRectPrim(verts);}上がDrawTextureメソッドのコードです。前回作ったDrawBoxとほとんど変わっていませんね。各頂点のTu,Tvのところに受け取ったテクスチャ座標の値を計算して代入しています。注意しないといけないのは、テクスチャ座標に渡すのは基本的に0〜1のfloat型の値だということです。読み込んだ先の画像の座標ではありません。ちなみに、twの値に負の値を指定すると画像が反転して表示も出来ます。それ以外にも1以上の値を設定すると画像を繰り返して表示できたりとDirectDrawではなかなか実現が難しかったような機能も簡単に処理できます。アクションゲームなどを作っていると、同じ画像を反転させて表示したいことが多いので、結構実用的な機能です。テクスチャをマッピングする場合、当然転送もとのTextureオブジェクトを指定しなくてはいけません。今回、DrawTextureメソッドでは第一引数にCLKsTexture型のオブジェクトを受け取っているため、そこからDirect3D.Textureオブジェクトを取得してDirect3D.Deviceに設定します。それを行っているのが太字の「device.SetTexture(0,Tex.Texture);」の部分です。テクスチャの指定も描画前に事前に設定しておきます。テクスチャの設定には「SetTexture」メソッドを使用します。引数はテクスチャステージというもので、今のところは0を指定しておいてください。第二引数にCLKsTextureが保持しているTextureオブジェクトを渡します。してテクスチャを設定しておけば、ポリゴンを描画したときにテクスチャを張ってくれるようになります。Textureの取り消しこれで、テクスチャの描画はできるようになりました。このままプログラムを実行すると前回作ったDrawBoxメソッドを使ってもテクスチャが描画されてしまいます。いうと、Direct3D.Deviceにテクスチャを指定したままだからです。そこで、DrawBoxに少し修正を加え、指定したテクスチャを取り消す処理をします。Color.Yellow.ToArgb();//テクスチャーの消去device.SetTexture(0,null);this.drawRectPrim(verts);}drawRectPrimを呼び出す前に、「device.SetTexture(0,null);」と追加してください。SetTextureメソッドでは、第二引数にnullを渡すことで、設定したテクスチャを取り消して、マッピングを行わないように出来ます。画像を描画する新機能の実装が完了したので、早速使ってみましょう。今回もMainメソッド内ですべて処理しています。{//メインループ//講座で紹介したFPS安定タイマーを使用しています。wait;}Application.DoEvents();}}テクスチャを読み込みは、CLKsTextureクラスのコンストラクタにファイル名とサイズを渡すだけで出来ます。サイズは上で説明したとおり512,256,128,64など2の乗数しか使えないので、今回はもとの画像サイズに近い512×256を指定しています。当然ですが、CLKsTextureの生成はループ内で行わないでください。画像は最初に読み込めば十分ですので。ループ内でDrawTextureを呼び出しています。引数に先ほど生成したlogoオブジェクトを渡していますね。最後の引数colorには片方にWhite(白)を、もう片方には変化する色を渡してます。Whiteを渡すと、読み込んだ画像と同じ色で表示しますが、別の色を渡すと色が変化します。このように、テクスチャは頂点色と混ぜて使うことが出来るので、一つの画像で様々なバリエーションの画像転送が出来ます。ゲームを作っていると、これも便利な機能の一つでしょう。まとめこれで、画像を表示することが出来るようになりました。機能も実装できてしまいました。Direct3Dってホント便利ですね。これだけあれば、簡単なゲームくらいはもう作れてしまうでしょう。(文字が描画できないのが難点か...)次回は画像表示にひとつ欠けている機能、スプライト転送とついでにアルファブレンディング(半透明合成)を実装したいと思います。ここまで来れば、2D描画機能としては申し分ないですね。追加(2006/03/17)今回紹介したサンプルは、機種によっては正しくテクスチャーマッピングされない場合があります。ライティング(照明)の設定が正しくされていないことが原因です。「ライトのオフ」方法を次のアルファブレンディングの回で紹介していますので、そちらをご覧ください。追加�A(2006/04/18)今回紹介したサンプルは、機種によっては正しくテクスチャーマッピングされない場合があります。頂点の「Rhw」の値を必ず1に設定してください。