Direct3D Immediate Mode for Visual Basic

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

June 22, 2000

Download Document サンプルファイルダウンロード (SphereEnvmap.zip, zip 形式, 12KB)

Visual Basic を使って3Dエフェクトを実装します。Direct3D 直接モード ( Immediatte Mode ) を使うと頂点データを直接ハンドリングでき、エフェクトを実現するレンダリング ステートも設定できます。ここでは周囲の環境をオブジェクトが反射する環境マッピングに挑戦します。

ここで紹介するサンプルコードは SDK には含まれていないので、このページからダウンロードしてください。

SphereEnvMap

目次

  • 球状環境マッピング
  • IM コントロール IMCanvas
  • 標準モジュールとクラス モジュール
  • SphereEnvMap サンプル コード
  • Appendix

球状環境マッピング

環境マッピングは周囲の環境を反射するオブジェクトを描画する手法です。具体的にはオブジェクトの頂点データの向きを定義する法線に合わせて ( より正確にはビュー座標系での法線に合わせて )、その頂点のテクスチャ座標 ( UV座標 ) を描画するたびに再計算します。例えば法線がスクリーンに垂直な方向ならテクスチャの中心をセット ( U = V = 0.5 ) し、真っ直ぐ上ならテクスチャの中央上部 ( U = 0.5、V = 1.0 ) をセットします。つまりどこを向いているかによってテクスチャのどこを表示するかを定義しなおしているのです。

環境マップについての詳細は、「クールなエフェクトを実装しよう」 のページ を参照してください。DirectX 7 ではキューブ環境マップと球状環境マップがサポートされていますが、ここで紹介するのはほとんどの 3D カードで動作するであろう球状環境マップのサンプルです。

ここで重要なのは描画するたびに頂点データの再計算をし、頂点データを書き換え、描画している点です。こういった用途には Direct3D 直接モード (IM) が最適です。

IM コントロール IMCanvas

コンポーネント

Direct3D IM にも Direct3D RM と同様に Visual Basic で初期化を容易にするためのコントロール IMCanvas があります。このコントロールのコードはデフォルトでは mssdk\samples\multimedia\VBSamples\D3DIM\src\IMControl にあります。関数やプロパティの仕様は Appendix をご覧下さい。

標準モジュールとクラス モジュール

DXVBChat

このサンプルではIMCanvas に加えて、DirectX 7 SDK の Visla Basic 用サンプル Xfile で使われているモジュール xfilemath.bas と Xfile.cls を使用しています、Xfile.cls についてはこのサンプル用に関数とメソッドを1つづつ追加しました。

Xfilemath.bas 標準モジュールは数式処理を行うための関数群です、これをつかうことで行列やベクトルの演算が容易になります。例えば 行列の積や射影行列の計算、あるいはベクトルの正規化(絶対値を1にする)などの関数をサポートしています。

Xfile.cls は .X ファイルを読み込み、DrawIndexedPrimitive メソッドに渡す下記のデータ構造体をセットするためのクラス モジュールです。.X ファイルは DirectX で使用している 3D データフォーマットです、この仕様については SDK のヘルプを参照してください。

Private Type XGroup
    IndexList() As Integer
    VertexList() As D3DVERTEX
    mtVertexList() As D3DVERTEX
    mat As D3DMATERIAL7
    Texture As DirectDrawSurface7
    TextureFileName As String
End Type

SphereEnvMap サンプル コード

このサンプルは DirectX 7 SDK がデフォルト フォルダ ( C:\mssdk ) にインストールされていることを前提としています、カスタム インストールされている場合はサンプルコード内の teapot.x と spheremap.bmp のパスを変更してください。

全てのコードを説明することはできないので、ここではコアとなる次の3つについて説明します、詳細はサンプル コードをダウンロードしてご覧下さい。

  • 初期化
  • テクスチャ座標の計算
  • DrawIndexedPrimitive メソッド

初期化

PhereEnv フォームのInitDX は DirectX 関連の初期化を行っています、IMCanvas を使っているので DirectX 自身の初期化は非常に簡単です、このサンプルではウィンドウモードで動作させるので、デバイスの列挙などの面倒な初期化は IMCanvas1.StartWindowed メソッドに任せています。

Private Sub InitDX()
…
b = .StartWindowed()
If b = False Then End

If IMCanvas1.Direct3DDevice.GetDeviceGuid() = "IID_IDirect3DHALDevice" 
   Then
    Dim caps As D3DDEVICEDESC7
    IMCanvas1.Direct3DDevice.GetCaps caps
    If (caps.lDevCaps And D3DDEVCAPS_TEXTUREVIDEOMEMORY) = 0 Then
        b = IMCanvas1.InitWindowed("", "IID_IDirect3DRGBDevice")
        If b = False Then End
     End If
    UseRGB = True
 End If
…
End Sub

ここではそれ以外にディスプレイのビット深度が 16bits 以上であることの確認と、HAL デバイスのテクスチャ サポートを確認し、サポートされていなければ RGB デバイスを使用します。このサンプルでは TnL ( トランスフォーム & ライティング ) デバイスは考慮していません。

Private Sub ResetDevice()
Set d3ddev = IMCanvas1.Direct3DDevice
 ' 行列のセット
d3ddev.SetTransform D3DTRANSFORMSTATE_WORLD, matWorld1
d3ddev.SetTransform D3DTRANSFORMSTATE_VIEW, matView1
d3ddev.SetTransform D3DTRANSFORMSTATE_PROJECTION, matProj1
…
 ' レンダリング ステートのセット
     With d3ddev
      .SetTextureStageState 0, D3DTSS_COLORARG1, D3DTA_TEXTURE
      .SetTextureStageState 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE
      .SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_MODULATE
      .SetTextureStageState 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR
      .SetRenderState D3DRENDERSTATE_DITHERENABLE, True
      .SetRenderState D3DRENDERSTATE_SPECULARENABLE, False
      .SetRenderState D3DRENDERSTATE_ZENABLE, True
End With
End Sub

さらに ResetDevice でトランスフォーム(座標変換)、マテリアル、ライト、レンダリング ステートなど具体的なレンダリングに必要なDirect3D デバイスのパラメータを初期化しています。ここではテクスチャとディフューズ シェーディングをブレンドするようにテクスチャ ステージを設定しています。

テクスチャ座標の計算

SetupUV は XFileClass モジュールに追加したこのサンプルの中心となるメソッドです、オブジェクトを描画するたびにこのメソッドをコールして、そのときのオブジェクトの回転角度に応じたテクスチャ座標 ( U, V ) をオブジェクトのデータ構造体 Groups.VertexList にセットしています。このサンプルでは描画するたびにオブジェクトに X 軸と Y 軸を中心に0.02 ラジアンの回転を加えています。

' 環境マップ用にテクスチャ座標 UV をセットアップ
Public Sub SetUV(ViewMatrix As D3DMATRIX)

    Dim Index As Long
    Dim i As Long
    
    ' 回転行列の計算
    dx.RotateXMatrix TempMatrix, PitchSpin
    dx.MatrixMultiply RotMatrix, TempMatrix, RotMatrix
    dx.RotateYMatrix TempMatrix, YawSpin
    dx.MatrixMultiply RotMatrix, TempMatrix, RotMatrix
    dx.MatrixMultiply TempMatrix, RotMatrix, TranMatrix
    ' ビュー行列の追加
    dx.MatrixMultiply TempMatrix, ViewMatrix, TempMatrix
    
    ' UV を計算
    For Index = 0 To GroupCount - 1
        With Groups(Index)
            For i = 0 To UBound(.VertexList) - 1
                With .VertexList(i)
                    .tu = 0.5 * (1# + .nx * TempMatrix.rc11 
                                    + .ny * TempMatrix.rc21 
                                    + .nz * TempMatrix.rc31)
                    .tv = 0.5 * (1# - (.nx * TempMatrix.rc12 
                                     + .ny * TempMatrix.rc22 
                                     + .nz * TempMatrix.rc32))
                End With
            Next
        End With
    Next

End Sub

本来はワールド行列とビュー行列を使うだけなのですが、XFileClass では描画直前にワールド行列を計算し直しているので、同じ回転行列の計算をここでも行っています。

ここがこの環境マップのコアとなる部分です、UV を動的に変更しなければ普通のテクスチャ マップと何も変わる所はありません。動的に UV を変更することで環境マップという特殊効果を生み出しているのです。

DrawIndexedPrimitive メソッド



' グループ オブジェクトをバック サーフェイスにレンダリング

Private Sub RenderGroup(groupid As Long, d3ddev As Direct3DDevice7)
    On Local Error Resume Next
    Dim mat As D3DMATERIAL7
    Dim c As Long
    With Groups(groupid)
    
        If (Not .Texture Is Nothing) Then
            d3ddev.SetTexture 0, .Texture
        Else
            d3ddev.SetTexture 0, Nothing
        End If
        
        d3ddev.SetMaterial .mat
        
        d3ddev.DrawIndexedPrimitive D3DPT_TRIANGLELIST, D3DFVF_VERTEX, _
            .VertexList(0), UBound(.VertexList) + 1, .IndexList, _
                UBound(.IndexList), D3DDP_DEFAULT
    End With
                
End Sub

XFileClass の RenderGroup にある DrawIndexedPrimitive メソッドに三角形リストとして、先ほど計算した UV を含む頂点リストとインデックス リストを渡して描画をしています。

まとめ

このサンプルは複数のヘルパ モジュールやヘルパ コントロールを使っており、少し複雑です、Xfiles モジュール内部では保持モードを使っていたりもしています。しかしテクスチャ座標などを含む頂点座標の設定やレンダリング ステート、トランスフォーム行列の設定そして環境マップのための動的な UV の変更など、Direct3D 直接モードのコアの部分は分かっていただけたでしょうか。

Direct3D 直接モードを使えば、最新のグラフィックス ハードウェアが備えている様々なエフェクト性能をこのように Visual Basic からも使うことができます。

5 回の連載の最終回になりました、この連載で紹介したように DirectX for Visula Basic を使うことで様々な用途に DirectX のマルチメディア フィーチャーがより身近な Visual Basic の環境から実装できます。日本語マニュアルや SDK CD の申し込みはこちらのページをご覧下さい、またこの連載へのご意見・ご感想などのフィードバックはdirectxj@microsoft.com へメールをお送り下さい。ただし質問に対する個別の返信や回答はできませんので、あらかじめご了承ください。

Appendix

IMCanvas の関数

関数名 機能

StartWindowed

ウィンドウ モードで開始

InitWindowed

ウィンドウ モードで初期化

InitFullScreen

幅、高さ、bpp を与え、フルスクリーン モードで初期化

SetDefaultTransformsLighsAndMaterial 

トランスフォーム、ライト、マテリアルをデフォルトに設定

Update

バック サーフェイスの内容をフロントにブリット / フリップ 

ClearBackSurface

バック サーフェイスをクリア ( Z バッファも )

SetViewPosition

視点、注視点などからビュー トランスフォームをセット

SetViewFrastrum

視錐体をセット

CreateTextureSurface

テクスチャ ファイル名からサーフェイスをセット

IMCanvas のプロパティ

プロパティ名 属性 機能
Dx r DirectX オブジェクトを返す
Direct3D r Direct3D オブジェクトを返す
Direct3Ddevice r Direct3Ddevice オブジェクトを返す
DirectDraw r DirectDraw オブジェクトを返す
ScreenSurface r フロントサーフェイスの DirectDrawSurface オブジェクトを返す
BackSurface r バック サーフェイスの DirectDrawSurface オブジェクトを返す

※ r: 読み込み可能