SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine(コードジン) DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

Direct3D Mobileによる3DCGプログラミング

Windows Mobile 5.0で動作する3Dアプリケーションの開発


描画

 描画処理全体のコードは、下記のようになります。

描画処理
HRESULT Render()
{
    HRESULT hr = S_OK;
    static int i = 0;    // Y軸に対するの回転量を保持する

    // バックバッファとZバッファのクリア
    g_pd3dmDevice->Clear(0, NULL, D3DMCLEAR_TARGET | D3DMCLEAR_ZBUFFER,
        D3DMCOLOR_XRGB(0,0,0), 1.0f, 0);

    // 描画開始
    if(SUCCEEDED(g_pd3dmDevice->BeginScene()))
    {
        // カリングの解除
        g_pd3dmDevice->
            SetRenderState( D3DMRS_CULLMODE, D3DMCULL_NONE );

        // ライティングはしない
        g_pd3dmDevice->SetRenderState( D3DMRS_LIGHTING, FALSE );

        // Y軸回転
        D3DMXMATRIX matWorld;
        D3DMXMatrixRotationY( &matWorld, D3DMXToRadian(i++) );
        g_pd3dmDevice->SetTransform( D3DMTS_WORLD,
            (D3DMMATRIX*)&matWorld, D3DMFMT_D3DMVALUE_FLOAT );

        // ビュー行列(3D空間のカメラ)
        D3DMXVECTOR3 vEyePt( 0.0f, 0.0f, -4.0f );
        D3DMXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
        D3DMXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
        D3DMXMATRIX matView;
        D3DMXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
        g_pd3dmDevice->SetTransform( D3DMTS_VIEW,
            (D3DMMATRIX*)&matView, D3DMFMT_D3DMVALUE_FLOAT );

        // プロジェクション(射影行列)
        // アスペクト比の調整はしない
        D3DMXMATRIX matProj;
        D3DMXMatrixPerspectiveFovLH( &matProj, D3DMX_PI/4.0f,
            1.0f, 0.1f, 100.0f );
        g_pd3dmDevice->SetTransform( D3DMTS_PROJECTION,
            (D3DMMATRIX*)&matProj, D3DMFMT_D3DMVALUE_FLOAT );

        // テクスチャのセット
        hr = g_pd3dmDevice->SetTexture( 0, g_pTexture );
        // 頂点バッファからレンダリング
        hr = g_pd3dmDevice->SetStreamSource(0, g_pVB, sizeof(VERTEX));
        hr = g_pd3dmDevice->DrawPrimitive(D3DMPT_TRIANGLESTRIP, 0, 2);

        hr = g_pd3dmDevice->SetTexture( 0, NULL);

        g_pd3dmDevice->EndScene();
    }
    // スクリーンへの転送
    hr = g_pd3dmDevice->Present(NULL, NULL, NULL, NULL);

    return hr;
}

 流れとしては以下の様になります。

  1. バックバッファとZバッファのクリア
  2. BeginScene()で描画開始
  3. 各種行列のセット
  4. テクスチャのセット
  5. 頂点バッファから描画命令を書く
  6. EndScene()で描画終了
  7. Present()でバックバッファを画面に出力
クリア
g_pd3dmDevice->Clear(0, NULL, D3DMCLEAR_TARGET | D3DMCLEAR_ZBUFFER,
    D3DMCOLOR_XRGB(0,0,0), 1.0f, 0);

 クリアは、上記の命令で行います。第3引数がクリア対象、第4引数が今回のサンプルでは背景の色になります。

各種行列のセット
// Y軸回転
D3DMXMATRIX matWorld;
D3DMXMatrixRotationY( &matWorld, D3DMXToRadian(i++) );
g_pd3dmDevice->SetTransform( D3DMTS_WORLD,
    (D3DMMATRIX*)&matWorld, D3DMFMT_D3DMVALUE_FLOAT );

// ビュー行列(3D空間のカメラ)
D3DMXVECTOR3 vEyePt( 0.0f, 0.0f, -4.0f );
D3DMXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DMXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DMXMATRIX matView;
D3DMXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dmDevice->SetTransform( D3DMTS_VIEW,
    (D3DMMATRIX*)&matView, D3DMFMT_D3DMVALUE_FLOAT );

// プロジェクション(射影行列)
// アスペクト比の調整はしない
D3DMXMATRIX matProj;
D3DMXMatrixPerspectiveFovLH( &matProj, D3DMX_PI/4.0f,
    1.0f, 0.1f, 100.0f );
g_pd3dmDevice->SetTransform( D3DMTS_PROJECTION,
    (D3DMMATRIX*)&matProj, D3DMFMT_D3DMVALUE_FLOAT );

 Direct3D Mobileでは、ポリゴンに対して、ワールド変換、ビュー変換、射影変換を行うことで3次元空間のものを2次元のスクリーンに投影します。このあたりはPC版のDirect3Dと同様の処理です。上記のコードでは、順番に各種変換に必要な行列のセットをしています。以下、細かい解説を書いていきます。

 Y軸回転と書かれたコメントの箇所ですが、ここではワールド変換用の処理です。今回は、毎フレームY軸に回転します。SetTransform関数の第1引数にD3DMTS_WORLDを指定するとレンダリングパイプラインはその行列をワールド変換行列と認識します。

 次に、ビュー行列のコメント以下の箇所です。ここでは、3つのベクトルを元にビュー行列を作成しています。このベクトルは、順番に、3次元空間での視点位置、注視点位置、上方向のベクトルになります。SetTransform関数の第1引数にD3DMTS_VIEWを指定するとレンダリングパイプラインはその行列をビュー変換行列と認識します。

 最後に、プロジェクション(射影行列)の箇所です。ここでは、視野角、アスペクト比、ニアクリップ面までの距離、ファークリップ面の距離から行列を作成します。SetTransform関数の第1引数にD3DMTS_PROJECTIONを指定するとレンダリングパイプラインはその行列を射影変換行列と認識します

 余談ですが、PC版のSetTransform関数には第3引数がありません。Direct3D Mobileは計算機リソースが少ない環境で動かすため固定小数を使うオプションがあります。

描画命令
// テクスチャのセット
hr = g_pd3dmDevice->SetTexture( 0, g_pTexture );
// 頂点バッファからレンダリング
hr = g_pd3dmDevice->SetStreamSource(0, g_pVB, sizeof(VERTEX));
hr = g_pd3dmDevice->DrawPrimitive(D3DMPT_TRIANGLESTRIP, 0, 2);

 テクスチャのセットは、SetTexture()を使います。第1引数は、マルチテクスチャ時のインデックスです。

 頂点バッファを使った描画では、まずSetStreamSource()で頂点バッファをセットします。続いてDrawPrimitive()で描画します。今回は、ストリップで描画します。PC版にあるDrawPrimitiveUp()とかは無いようです。

終了処理

CleanupD3DM()関数内
// Direct3D Mobileの解放
VOID CleanupD3DM()
{
    SAFE_RELEASE( g_pTexture );
    SAFE_RELEASE(g_pVB);
    SAFE_RELEASE(g_pd3dmDevice);
    SAFE_RELEASE(g_pd3d);
}

 Direct3D Mobileのインターフェイスは、アプリケーション終了時にメンバ関数のRelease()関数を呼び出す必要があります(今回は、NULLチェックもかねたマクロを作って代替処理にしています)。これらの処理を忘れることはメモリリークの原因になります。

実行とデバッグ

エミュレータ上での実行とデバッグ

 プログラムができたら実行してみます。ビルド後に実行してみると、自動的にエミュレータが起動してプログラムが転送され、実行されます。デバッグに関しては、ブレークポイントを使ったステップ実行なども可能です。

 ただし、エミュレータはソフトウェアでエミュレーションしてる関係上、ハードウェアと異なる挙動であったり、動作速度が実機より低速な点で注意が必要です。

実機上でのデバッグ

 実機上のデバッグは、まず実行したいPocketPCをPCに接続してActiveSyncが確立している必要があります(この際にパートナーシップはゲストでも大丈夫です)。接続ができていれば実行のターゲットをエミュレータから[Windows Mobile 5.0 PocetPC Device]に変えておきます。

 実機上でのデバッグは実行する環境が実際のPocketPCデバイス上になりますが、Visual Studio 2005上でのデバッガの機能を使うことはできますので、実機上でのさまざまな問題に対してPCからモニタすることができます。

 実機上でのデバッグは、エミュレータでは分からなかったバグの発見や実行速度の速さの面でエミュレータに比べて優位です。

CABインストーラの作成

 さて、実行ファイルができたらそれをインストールするインストーラの説明したいと思います。PocketPCでは、InstallShieldなどで作成したインストーラのほかに、CAB形式でアーカイブすることでインストーラにすることができます。Visual Studio 2005では、[セットアップと配置]から[スマートデバイス CAB プロジェクト]を新規プロジェクトで選択することでインストーラを作ることができます。このプロジェクトで作成したCABファイルは、実機上に転送して実行することで自動的にファイルがインストールされます。

スマートデバイス CAB プロジェクトを選択
スマートデバイス CAB プロジェクトを選択

 今回のサンプルの場合では、できあがった実行ファイル[d3dmobile.exe]をプロジェクトに加えて作成すればOKです。テクスチャをリソースファイルにしない場合などは一緒に追加します。

 あとは、でき上がったCABファイルをActiveSyncやメモリーカードなどを使って転送します。転送後はPocketPC上でCABファイルを展開すればインストールは完了です。アンインストールは[プログラムの削除]からできます。

 作業時の注意ですが、ビルド時に下記のようなエラーが出る場合があります。

Error: The INF file contains Unicode characters
 that could not be converted correctly to ANSI

 この場合には、下記の画像のように[プロジェクト]のプロパティの[Manufacturer]を全角文字ではなく半角文字で付けてください。

赤丸の部分を変更
赤丸の部分を変更

まとめ

 PCでDirect3Dでのプログラミングを経験したことがあれば、Direct3D Mobileの利用は、ほとんどPC版の固定機能パイプラインを利用したプログラムのやり方と同じであると気づきます。ドキュメントを見ると分かりますが、インターフェイスなどもほとんど同様です。ただ、PCとの違いとしては、プログラマブルシェーダが仕様に無いことと、Direct3DのヘルパーライブラリであるD3DXがPCほど充実していないことが挙げられます。D3DXに関しては、ベクトルや行列などの算術命令とテクスチャのみで、メッシュ系の機能がないのでPC版のように「.x」形式のモデルデータのファイルがサポートされていないようです。ただ、PC以上にリソースが限られた環境ですので、あまりリッチなデータフォーマットなどは利用できません。

 Direct3D MobileはPCに比べると高性能なGPUが無いので、プログラマブルシェーダなどは利用ができません。しかし、携帯ゲーム機のようなサイズでタッチパネルを備えたハードウェアであり、なおかつ3DCGプログラミングもできるとなると、PCとは異なった性質のアプリケーションを開発できる可能性があります。

 余談ですが今回は、C++での利用を解説しました。Direct3Dを使ったアプリケーションの開発者の中には、C#やVBなどの.NET Frameworkを利用した方もいらっしゃると思います。そういった開発者の方には英語ではあるのですが、MSDNにManaged Direct3D Mobileの情報がありますので参考になると思います。

参考資料

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
特集記事連載記事一覧

もっと読む

この記事の著者

高橋 誠史(タカハシ マサフミ)

僻地の大学院生です。GPUプログラミングとそのニュースを集めたサイトShader.jpを開いています。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/316 2006/03/08 16:14

おすすめ

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー