Windows フォームへの 3D 描画 2

~ Cutting Edge DX 9 - 第 22 回目 ~

Hiroyuki Kawanishi (川西 裕幸)
マイクロソフト株式会社
テクニカル エバンジェリスト

2005 年 3 月 23 日

Dd188549.winForm2(ja-jp,MSDN.10).jpg

今回は、Windows フォーム上のピクチャ ボックスに 3D メッシュを描画する方法を紹介します。ピクチャ ボックスに描画すれば、ボタンのような他の .NET Framework コンポーネントと一緒に表示させることができるので便利です。また、System.Windows.Forms.ColorDialog 使って3D メッシュの色を指定できるようにします。この文章では、前回の Windows フォームへの描画サンプルとの違いに焦点を当てて説明します。

Dd188549.download(ja-jp,MSDN.10).gif この記事のソースコードをダウンロードする (meshInPB.zip, 4 KB)

目次

サンプルの使い方
Direct3D デバイスの作成
メッシュオブジェクトの作成
色の設定
メッシュの描画
最後に

サンプルの使い方

  1. Visual Studio .NET 2003 から [ファイル] → [新規作成] で、ダイアログの [Windows アプリケーション] を選択し、プロジェクト名と場所を設定して、[OK] ボタンをクリックします。
  2. 作成されたプロジェクト フォルダに、ダウンロードした meshInPB.cs をコピーします。
  3. [ソリューション エクスプローラ] で、Form1.cs, App.ico, AssemblyInfo.cs を右クリックし [プロジェクトから削除] を選択します。
  4. [ソリューション エクスプローラ] でプロジェクト名を右クリックし、[追加] → [既存項目の追加] を選び、既存項目の追加ダイアログで meshInPB.cs を選択します。
  5. [ソリューション エクスプローラ] で [参照設定] を右クリックし、[参照の追加] を選択し、ダイアログから Microsoft.DirectX, Microsoft.DirectX.Direct3D, Microsoft.DirectX.Direct3DX を [選択] し [OK] をクリックします。複数のバージョンがあるときは、すべて最新のものにしたほうがよいでしょう。
  6. F5 キーでコンパイル・実行できます。

注意 : このサンプルをビルド・実行するには、DirectX 9.0 SDK Update (Summer 2004) 以降が必要です。

Direct3D デバイスの作成

Direct3D デバイスを作成するとき、前回は第 3 引数に (Form に描画するので) Form オブジェクトを渡しました。今回はそこに PictureBox オブジェクトを引数として渡します。実は、描画先をフォームからピクチャ ボックスに変更するのに必要な修正はその部分だけです。フォームではなくピクチャ ボックスに描画することによって、ボタンなどの他のコントロールが使えるようになります。ボタンなどの作成とコールバックはコードの終わりのほうにあります。


private System.Windows.Forms.PictureBox renderTarget;
...
// Direct3D デバイスの作成に使う構造体を設定する。
presentParams = new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.EnableAutoDepthStencil = true;
presentParams.AutoDepthStencilFormat = DepthFormat.D16;
// Direct3D デバイスの作成
device = new Device(0, DeviceType.Hardware, this.renderTarget, // ピクチャ ボックス
                CreateFlags.SoftwareVertexProcessing, presentParams);
device.DeviceReset += new System.EventHandler(this.OnResetDevice);
this.OnResetDevice(device, null);
pause = false;

あるいは、フォームを引数として Direct3D デバイスを作成して、描画時にピクチャ ボックスを指定することも可能です。この手法なら、1 つのデバイスで複数のピクチャ ボックスに別々に描画することもできます。その手法については次回紹介します。

メッシュ オブジェクトの作成

Direct3D.Mesh クラスにはティーポット以外に、円柱 (Cylinder)、球 (Sphere) などの作成メソッドがあることは紹介しました。今回はボタンの操作からそれらを生成し直して、描画しています。円柱や球のコンストラクタには Direct3D デバイス以外の引数があり、メッシュの大きさや細かさを指定できます、詳細はドキュメントを参照してください。


// ボタン操作のコールバック ティーポット
private void button1_Click(object sender, System.EventArgs e)
{
    meshObject.Dispose();
    meshObject = null;
    meshObject = Mesh.Teapot(device);
}
// ボタン操作のコールバック 円柱
private void button2_Click(object sender, System.EventArgs e)
{
    meshObject.Dispose();
    meshObject = null;
    meshObject = Mesh.Cylinder(device, 0.5f, 0.5f, 2.0f, 10, 10);
}
// ボタン操作のコールバック 球
private void button3_Click(object sender, System.EventArgs e)
{
    meshObject.Dispose();
    meshObject = null;
    meshObject = Mesh.Sphere(device, 1.0f, 10, 10);
}

色の設定

メッシュ オブジェクトの色はライトの色とマテリアルの色から決まります。前回はどちらも白でしたので、灰色の陰影を持つ白いティーポットが描画されました。今回はカラー ダイアログ System.Windows.Forms.ColorDialog クラスを使って、マテリアルの色を変更できるようにしました。カラー ダイアログの使い方は通常のアプリケーションと同じです。コールバックの中でカラー ダイアログから取得した色をディフューズ マテリアルに代入します。


Material mtrl;
...
// マテリアルの設定
mtrl = new Material();
mtrl.Diffuse = Color.White;
...
// ボタン操作のコールバック カラーダイアログ
private void button4_Click(object sender, System.EventArgs e)
{
    // カラー ダイアログの表示
    ColorDialog cd = new ColorDialog();
    cd.FullOpen = true;
    cd.Color = Color.FromArgb(mtrl.Diffuse.ToArgb());
    cd.ShowDialog();
    // マテリアル デュフューズ色の設定
    mtrl.Diffuse = cd.Color;
}

メッシュの描画

前回はマテリアルの変更がなかったので、描画前に 1 回だけ設定していましたが、このサンプル コードでは描画するたびに (DrawSubset を呼び出す前に) マテリアルを設定しています。コールバックの中でデバイスに設定してもかまいませんが、複数のメッシュを別のマテリアルで描画することが多いので、一般に DrawSubset の前にマテリアル (あるいはテクスチャ) を設定する手順がよく使われます。


private void Render()
{
    if (device == null || pause) return;
    // バックバッファを青色にクリア、Z バッファもクリア
    device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, System.Drawing.Color.DarkBlue, 1.0f, 0);
    // シーンの開始
    device.BeginScene();
    // ワールド・ビュー・投影行列を設定
    SetupMatrices();
    // マテリアルの設定
    device.Material = mtrl;
    // メッシュ サブセットを描画
    meshObject.DrawSubset(0);
    // シーンの終了
    device.EndScene();
    // シーンの更新
    try { device.Present(); }
    // デバイス消失のチェックとリセット
    catch (DeviceLostException) { OnDeviceLostException(); }
}

最後に

今回は、回転するメッシュ オブジェクトを Windows フォーム上のピクチャ ボックスに描画する単純なサンプルを紹介しました。次回はピクチャ ボックスに表示した複数のジオメトリ オブジェクトをマウスでクリックすると、クリックされたオブジェクトを別のピクチャ ボックスに表示するサンプルを紹介します。

この文章へのご意見やフィードバックは GDNJ Managed DirectX 掲示板に投稿してください。