頂点と線と面
今回は、いよいよデバイスに図を描画してみたいと思いますGDI で、描画処理を行う時に BeginPaint() 〜 EndPaint() というような
描画の開始、及び終了を表す関数があったように
DirectX Graphics でも、開始と終了を表すメソッドが存在します
バッファへの描画を開始するには IDirect3DDevice8::BeginScene() を使い
描画を終了したなら IDirect3DDevice8::EndScene() を呼び出します
HRESULT BeginScene();
HRESULT EndScene();
それぞれ、成功すれば D3D_OK が、失敗すれば D3DERR_INVALIDCALL が返ります
これらのメソッドの間に、バッファに描画するメソッドを指定します
3次元グラフィックスにおいて、図は2次元と考え方が違います
まず最初の難関となるのが、座標の理解です
3次元グラフィックスは、奥行きを表す Z 座標が存在します
この一つの座標が増えたために、座標変換は極めて複雑になりました
3次元において、図はポリゴンで表現されます
つまり、図の基本構造は単純な線と面で構成されるのです
より分解すると、私たちが指定するのは座標を指定した点の集合です
そして、この点をどのように結びつけるのかをデバイスに指定することで図形とします
問題は、この点の座標をどのように指定するかということです
この点のことを、3次元グラフィックスでは頂点と呼びます
さらに、3次元グラフィックスには物体にあたる光の反射ライティングや
物体の性質マテリアルなども指定する必要があります
これらの高度なトピックスに� �いては、後ほど少しずつ解説していきます
座標を指定するには、まず頂点フォーマットを決定します
頂点フォーマットとは、描画に必要なデータをを集め、これを定義したものです
必ず必要なものに座標がありますが、この他にも色などのデータを含めます
頂点フォーマットを定義するには
IDirect3DDevice8::SetVertexShader() メソッドを使います
図を描画するには、まずこれを用いて頂点フォーマットを決定する必要があります
HRESULT SetVertexShader(DWORD Handle);
Handle には、頂点フォーマットのフラグを指定します
この引数には、以下の定数を組み合わせて指定することができます
ロバート·ヘイデンはどのように死ぬのですか?
定数 | 解説 |
---|---|
D3DFVF_DIFFUSE | 頂点フォーマットがディフューズ色成分を含む |
D3DFVF_NORMAL | 頂点フォーマットが頂点法線ベクトルを含む このフラグを、D3DFVF_XYZRHW と共に使用することはできない |
D3DFVF_PSIZE | 頂点フォーマットはポイント サイズで指定されている このサイズは、トランスフォーム済みでも ライティング済みでもない頂点に対するカメラ空間単位 およびトランスフォーム済みでライティング済みの 頂点に対するデバイス空間単位で表されている |
D3DFVF_SPECULAR | 頂点フォーマットがスペキュラ色成分を含む |
D3DFVF_XYZ | 頂点フォーマットが未トランスフォーム頂点の位置座標を含む このフラグを、D3DFVF_XYZRHW と共に使用することはできない |
D3DFVF_XYZRHW | 頂点フォーマットが、トランスフォームされた頂点の位置座標を含む このフラグを D3DFVF_XYZ または D3DFVF_NORMAL フラグと同時に使用することはできない |
D3DFVF_XYZB1 〜 D3DFVF_XYZB5 | 頂点フォーマットは、位置座標データ および複数の行列による 頂点ブレンディング処理用の加重 (ベータ) 値の対応数を含む 現在、MicrosoftR Direct3DR では最大 3 つの加重値 および 4 つのブレンディング行列でブレンディングが可能である |
D3DFVF_TEX0 〜 D3DFVF_TEX8 | この頂点に対応するテクスチャ座標セットの番号 これらのフラグに対応する数字は連続番号になっていない |
D3DFVF_TEXTUREFORMAT1 〜 D3DFVF_TEXTUREFORMAT4 | テクスチャ座標セットを定義する値の番号 D3DFVF_TEXTUREFORMAT1 は 1 次元座標を示し D3DFVF_TEXTUREFORMAT2 は 2 次元座標を示し、という順に以下続く このフラグが単独で使用されることはまれで D3DFVF_TEXCOORDSIZEn マクロと共に使用される |
D3DFVF_POSITION_MASK | 位置座標ビットを抽出するマスク |
D3DFVF_RESERVED0 D3DFVF_RESERVED2 | 柔軟な頂点フォーマットの予約ビットを抽出するためのマスク値 使用不可 |
D3DFVF_TEXCOUNT_MASK | テクスチャ フラグ ビットを抽出するためのマスク値 |
D3DFVF_LASTBETA_UBYTE4 | インデックス付き頂点ブレンディングと 固定機能 FVF 頂点シェーダを使用する場合は 頂点シェーダにこのフラグを指定しなければならない |
D3DFVF_TEXCOUNT_SHIFT | 頂点のテクスチャ座標数を 識別する整数値を何ビット分シフトするかを示す数 |
成功すれば D3D_OK が、失敗すれば D3DERR_INVALIDCALL が返ります
このメソッドで指定したフラグの組み合わせによって、頂点フォーマットが決定します
そして、頂点フォーマットによってこれを指定するための構造体のサイズが決まります
この関係は、基本的に次のようなものとなります
ツリーハウスの計画を見つけるためにどこに
意味とフラグ | 型 | |
---|---|---|
座標位置 D3DFVF_XYZ | x 座標 (float) y 座標(float) z 座標(float) | |
同次座標ベクトル D3DFVF_XYZRHW | rhw (float) | |
ブレンディングウェイト D3DFVF_XYZB1 〜 D3DFVF_XYZB5 | 1 〜 5 個のデータ (float) | |
頂点法線 D3DFVF_NORMAL | 法線 x (float) 法線 y (float) 法線 z (float) | |
ディフューズ色 D3DFVF_DIFFUSE | RGBA (DWORD) | |
スペキュラ色 D3DFVF_SPECULAR | RGBA (DWORD) | |
テクスチャ座標セット D3DFVF_TEX0 〜 D3DFVF_TEX8 | テクスチャ座標データ D3DFVF_TEXTUREFORMAT1 〜 D3DFVF_TEXTUREFORMAT4 | 1 〜 4 のデータ (float) |
どういうことかというと、頂点フォーマットによって型を決定し
独自のその型の構造体などを定義して、描画時の位置指定でこれを利用するのです
例えば、SetVertexShader() メソッドで D3DFVF_XYZRHW と D3DFVF_DIFFUSE を指定すると
構造体は、上の図を参考に計算すると次のようなサイズになります
struct { float x , y , z , rhw; DWORD color; };ポリゴンを描画する時に、頂点の位置や色を指定するために
メソッドの何らかの引数で、この構造体のポインタを渡すことになるでしょう
このように、頂点の情報は私たちが柔軟に組み合わせることができるのです
自分で細かく設定したい時は多くの情報を渡せばよいですし
最小限の情報で、あとは DirectX に計算させることも可能になっているということです
ところで、この頂点フォーマットには様々な見慣れない用語が含まれています
ブレンディングウェイトや頂点法線、同次座標ベクトルなどです
これらについて、今必要の無い情報は後ほど詳しく解説します
同次座標ベクトルとは、x、y、z 座標に対して、さらに w を加えた4次元ベクトルを指します
なぜ3次元画像を表すために、4次元のベクトルを使う必要があるのでしょうか
実は、この値は座標変換を行うために必要な値なのです
3次元の座標を変換するには、4 × 4 の行列を用いるのですが
3次元の座標形では、4 × 4 の行列を乗算することができないため w が加えられます
詳しくは、座標変換について解説する時に説明します
ディフューズ色は、頂点の色そのものを表します
スペキュラ色は、頂点の反射色を表します
これらの関係についても、ライティングについて解説する特に詳しく説明します
通常の図形を表示する場合は、基本的に上で記した構造体で十分です
つまり、座標を表す x、y、z と同次座標ベクトル rhw の float 型に
頂点の色を表すディフューズ色の DWORD 型を加えたものです
頂点フォーマットが準備できれば、次はいよいよ頂点を配置します
頂点は、頂点フォーマットで指定した型の構造体の配列を頂点の数だけ用意し
それぞれの頂点の座標や色など、定義した構造体に適切に指定します
後は IDirect3DDevice8::DrawPrimitiveUP() メソッドを使って
指定した頂点フォーマットの構造体の配列を渡し、デバイスに描画するだけです
HRESULT DrawPrimitiveUP( D3DPRIMITIVETYPE PrimitiveType , UINT PrimitiveCount , CONST void* pVertexStreamZeroData , UINT VertexStreamZeroStride );PrimitiveType には、D3DPRIMITIVETYPE 列挙型から、プリミティブ型を指定します
この列挙型や、プリミティブについては下記を参照してください
PrimitiveCount には、描画するプリミティブの数を指定します
pVertexStreamZeroData は、描画する頂点データ配列へのポインタを指定します
VertexStreamZeroStride は、頂点のデータサイズを指定します
成功すれば D3D_OK が、失敗すれば D3DERR_INVALIDCALL が返ります
lemonaideは何ですか?
さて、またまた新しい難関が登場しました
プリミティブ とは、頂点を結び付けてできた図形のことを意味します
プリミティブの種類はいくつかあって、単純に点として描画したり
線で結んだり、あるいは3つの頂点を1単位として三角形を描画することもできます
D3DPRIMITIVETYPE 列挙型はプリミティブの種類を提供しています
この列挙型は、次のように定義されています
typedef enum _D3DPRIMITIVETYPE { D3DPT_POINTLIST = 1, D3DPT_LINELIST = 2, D3DPT_LINESTRIP = 3, D3DPT_TRIANGLELIST = 4, D3DPT_TRIANGLESTRIP = 5, D3DPT_TRIANGLEFAN = 6, D3DPT_FORCE_DWORD = 0x7fffffff } D3DPRIMITIVETYPE;この列挙型のメンバは、以下のような意味を持っています
定数 | 解説 |
---|---|
D3DPT_POINTLIST | 頂点を別個の点の集合としてレンダリングする |
D3DPT_LINELIST | 別個の線分のリストとして頂点をレンダリングする このプリミティブ タイプを使用する呼び出しは カウントが 2 より小さいか、奇数の場合は失敗する |
D3DPT_LINESTRIP | 頂点を単一のポリラインとしてレンダリングする このプリミティブ タイプを使用する呼び出しは カウントが 2 より小さい場合は失敗する |
D3DPT_TRIANGLELIST | 別個の三角形の連続として指定の頂点をレンダリングする 各 3 頂点のグループは個別に三角形を定義する 背面のカリングは、現在のカリング モード レンダリング ステートの影響を受ける |
D3DPT_TRIANGLESTRIP | 頂点を三角形の展開図としてレンダリングする 背面カリング フラグは、偶数番号の三角形で自動的に反転する |
D3DPT_TRIANGLEFAN | 頂点を三角形の扇形としてレンダリングする |
D3DPT_FORCE_DWORD | この列挙型を強制的に 32 ビット サイズにコンパイルする この値は使用されていない |
実際に、頂点がどのように結ばれるかは、図で見たほうが早いでしょう
点や線の場合は、頂点の数がプリミティブ数となりますが
三角形の場合は、三角形の数がプリミティブ数となります
#includelpszClassName = TEXT("KITTY"); if (!RegisterClass(&winc)) return 0; hWnd = CreateWindow( TEXT("KITTY") , TITLE , WS_OVERLAPPEDWINDOW | WS_VISIBLE , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , NULL , NULL , hInstance , NULL ); if (!hWnd) return 0; pDirect3D->CreateDevice( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd , D3DCREATE_SOFTWARE_VERTEXPROCESSING , &d3dpp , &pD3Device ); while (GetMessage(&msg , NULL , 0 , 0 )) { TranslateMessage(&msg); DispatchMessage(&msg); } pDirect3D->Release(); pD3Device->Release(); return msg.wParam; }#include #define TITLE TEXT("Kitty on your lap") IDirect3D8 * pDirect3D; IDirect3DDevice8 * pD3Device; D3DPRESENT_PARAMETERS d3dpp; typedef struct { float x , y , z , rhw; DWORD diff; } D3DVERTEX; LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) { static D3DVERTEX pt[3] = { {200 , 10 , 1 , 1 , 0xFFFF0000} , {400 , 200 , 1 , 1 , 0xFFFF0000} , {10 , 200 , 1 , 1 , 0xFFFF0000} }; switch (msg) { case WM_DESTROY: PostQuitMessage(0); return 0; case WM_PAINT: if (!pD3Device) break; pD3Device->Clear(0 , NULL , D3DCLEAR_TARGET , D3DCOLOR_XRGB(0xFF , 0xFF , 0xFF) , 1.0 , 0); pD3Device->BeginScene(); pD3Device->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); pD3Device->DrawPrimitiveUP( D3DPT_TRIANGLELIST, 1 , pt , sizeof (D3DVERTEX) ); pD3Device->EndScene(); pD3Device->Present(NULL,NULL,NULL,NULL); ValidateRect(hWnd , NULL); return 0; case WM_SIZE: if (!pD3Device) return 0; d3dpp.BackBufferWidth = LOWORD(lp); d3dpp.BackBufferHeight = HIWORD(lp); pD3Device->Reset(&d3dpp); return 0; } return DefWindowProc(hWnd , msg , wp , lp); } int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance , PSTR lpCmdLine , int nCmdShow) { MSG msg; HWND hWnd; WNDCLASS winc; D3DDISPLAYMODE d3ddm; pDirect3D = Direct3DCreate8(D3D_SDK_VERSION); pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT , &d3ddm); ZeroMemory(&d3dpp , sizeof (D3DPRESENT_PARAMETERS)); d3dpp.BackBufferFormat = d3ddm.Format; d3dpp.BackBufferCount = 1; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.Windowed = TRUE; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = WndProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL , IDI_APPLICATION); winc.hCursor = LoadCursor(NULL , IDC_ARROW); winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpszMenuName = NULL; winc.
このプログラムは、3つの頂点を1つの三角形として描画しています
WM_PAINT メッセージにおける処理に注目してください
各頂点の情報は、独自に定義した D3DVERTEX 型の pt 配列変数で表現されています
単純な三角形を表示するだけでも、ものすごい複雑なことをやっています
この章では、頂点フォーマットとプリミティブの理解が最も重要です
しっかりと基本を押さえて、今後に望んでください
因みに、各頂点の色を別々にすれば、綺麗なグラデーションになります
IDirect3DDevice8::BeginScene()
HRESULT BeginScene(); シーンを開始しますレンタリングの実行前に、必ず呼び出す必要があります
戻り値 - 成功すれば D3D_OK 、失敗すれば D3DERR_INVALIDCALL
IDirect3DDevice8::EndScene()
HRESULT EndScene(); シーンを終了しますレンタリングを終了した時に、必ず呼び出す必要があります
戻り値 - 成功すれば D3D_OK 、失敗すれば D3DERR_INVALIDCALL
IDirect3DDevice8::SetVertexShader()
HRESULT SetVertexShader(DWORD Handle); 以前に作成した頂点シェーダ、または頂点フォーマットの固定機能シェーダに現在の頂点シェーダを設定します
Handle - 頂点シェーダのハンドル、または頂点フォーマットフラグを指定します
戻り値 - 成功すれば D3D_OK、失敗すれば D3DERR_INVALIDCALL
Handle には、以下の定数を組み合わせて指定することができます
定数 | 解説 |
---|---|
D3DFVF_DIFFUSE | 頂点フォーマットがディフューズ色成分を含む |
D3DFVF_NORMAL | 頂点フォーマットが頂点法線ベクトルを含む このフラグを、D3DFVF_XYZRHW と共に使用することはできない |
D3DFVF_PSIZE | 頂点フォーマットはポイント サイズで指定されている このサイズは、トランスフォーム済みでも ライティング済みでもない頂点に対するカメラ空間単位 およびトランスフォーム済みでライティング済みの 頂点に対するデバイス空間単位で表されている |
D3DFVF_SPECULAR | 頂点フォーマットがスペキュラ色成分を含む |
D3DFVF_XYZ | 頂点フォーマットが未トランスフォーム頂点の位置座標を含む このフラグを、D3DFVF_XYZRHW と共に使用することはできない |
D3DFVF_XYZRHW | 頂点フォーマットが、トランスフォームされた頂点の位置座標を含む このフラグを D3DFVF_XYZ または D3DFVF_NORMAL フラグと同時に使用することはできない |
D3DFVF_XYZB1 〜 D3DFVF_XYZB5 | 頂点フォーマットは、位置座標データ および複数の行列による 頂点ブレンディング処理用の加重 (ベータ) 値の対応数を含む 現在、MicrosoftR Direct3DR では最大 3 つの加重値 および 4 つのブレンディング行列でブレンディングが可能である |
D3DFVF_TEX0 〜 D3DFVF_TEX8 | この頂点に対応するテクスチャ座標セットの番号 これらのフラグに対応する数字は連続番号になっていない |
D3DFVF_TEXTUREFORMAT1 〜 D3DFVF_TEXTUREFORMAT4 | テクスチャ座標セットを定義する値の番号 D3DFVF_TEXTUREFORMAT1 は 1 次元座標を示し D3DFVF_TEXTUREFORMAT2 は 2 次元座標を示し、という順に以下続く このフラグが単独で使用されることはまれで D3DFVF_TEXCOORDSIZEn マクロと共に使用される |
D3DFVF_POSITION_MASK | 位置座標ビットを抽出するマスク |
D3DFVF_RESERVED0 D3DFVF_RESERVED2 | 柔軟な頂点フォーマットの予約ビットを抽出するためのマスク値 使用不可 |
D3DFVF_TEXCOUNT_MASK | テクスチャ フラグ ビットを抽出するためのマスク値 |
D3DFVF_LASTBETA_UBYTE4 | インデックス付き頂点ブレンディングと 固定機能 FVF 頂点シェーダを使用する場合は 頂点シェーダにこのフラグを指定しなければならない |
D3DFVF_TEXCOUNT_SHIFT | 頂点のテクスチャ座標数を 識別する整数値を何ビット分シフトするかを示す数 |
IDirect3DDevice8::DrawPrimitiveUP()
HRESULT DrawPrimitiveUP( D3DPRIMITIVETYPE PrimitiveType , UINT PrimitiveCount , CONST void* pVertexStreamZeroData , UINT VertexStreamZeroStride );ユーザーメモリポインタで指定された配列データを
指定されたジオメトリ・プリミティブのシーケンスとしてレンタリングします
PrimitiveType - D3DPRIMITIVETYPE 列挙型から、プリミティブ型を指定します
PrimitiveCount - 描画するプリミティブの数を指定します
pVertexStreamZeroData - 描画する頂点データ配列へのポインタを指定します
VertexStreamZeroStride - 頂点のデータサイズを指定します
戻り値 - 成功すれば D3D_OK、失敗すれば D3DERR_INVALIDCALL
0 件のコメント:
コメントを投稿