Nanashi-softプログラマ専用DirectX11開発


◇DirectX11プログラミング -四角ポリゴンを立ててみる-

よくココで,立方体にするのですが
頂点数が増えたら話が難しくなるので,したくないです(*'-')

3Dに詳しい同僚の話を聞くと,三角形だけは特殊な描画命令があるそうです
なので,四角形でサンプルを作ると,五角形でも六角形でも,頂点を増やすだけで対応できるっぽいです(わかっていません(^^;)

四角形ポリゴンに戻す
	const int TYOUTEN = 4;	//ポリゴンの頂点数

Vertex3D hVectorData[TYOUTEN] = {
//500x811
{ { -0.27f, +0.75f, +0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f }, {0.0f, 0.0f} },
{ { +0.27f, +0.75f, +0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f }, {1.0f, 0.0f} },
{ { -0.27f, -0.75f, +0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f }, {0.0f, 1.0f} },
{ { +0.27f, -0.75f, +0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f }, {1.0f, 1.0f} }
};
この前,ベタっと画面に貼り付いていたポリゴンを,3D空間上に置いてみます

……で?('-'*)
なにをどうすればよいのかがさっぱりわかりません
ココで,前回書いた工程が役に立つのですよ

まずはじめに,XNAを使うのでヘッダーを追加します
#include <xnamath.h>
なんで XNAかって? だって,DirectX11サンプルに普通に使われていたから('-'*)
大丈夫,大丈夫。DirectX11と言う時点で既にマイナーだから,誰も驚かない ←

・ローカル座標
 ↓ワールド変換
・ワールド座標

「DirectX ワールド変換」でググると,ワールド座標は初期化するだけで良いみたいです(難しい説明は読み飛ばしたので,こういう解釈になった)
	//ワールド変換用行列を生成
XMMATRIX hWorld; //ワールド変換行列
//初期化
hWorld = XMMatrixIdentity();
他はわからんので,次いきます('-'*) ←
・ワールド座標
 ↓ビュー変換
・カメラから見た座標

「DirectX ビュー変換」でググると,XMMatrixLookAtLH関数を使うと言うことがわかります
MSDNのマニュアルを見ると,3つめのUpDirectionは[0.0f,1.0f,0.0f]がデフォルトだろうことがわかります
あとは,EyePositionがカメラの位置,FocusPositionが焦点の位置です

カメラを手前の方に置いて,中心に焦点を合わせてみます
	XMMATRIX hView;		//ビュー変換行列
XMVECTOR hEye = XMVectorSet(0.0f, 0.0f, -2.0f, 0.0f); //カメラの位置
XMVECTOR hAt = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f); //焦点の位置
XMVECTOR hUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
hView = XMMatrixLookAtLH(hEye, hAt, hUp);
・カメラから見た座標
 ↓透視変換(透視射影変換)
・遠近感のある座標

「DirectX 透視変換」でググると,XMMatrixPerspectiveFovLH関数を使うという事がわかります
結構ココはどのサンプルでも同じような値をセットされていました
第1引数の視野角度が違うぐらいです

DirectX11には以下のマクロがなぜか無いので,追加しておく
#define D3DX_PI ((FLOAT) 3.141592654f) 
#define D3DXToRadian( degree ) ((degree) * (D3DX_PI / 180.0f))
#define D3DXToDegree( radian ) ((radian) * (180.0f / D3DX_PI))

XMMATRIX hProjection; //透視射影変換行列
hProjection = XMMatrixPerspectiveFovLH(D3DXToRadian(45.0f), 16.0f/9.0f, 0.0f, 1000.0f);
・遠近感のある座標
 ↓ビューポート(切り取り)
・描画

これは既に記述しています
ビューポート設定のことです(たぶん)

これまで作成したのは,計算に必要な行列座標の生成でした
これを頂点シェーダーに計算させるようにしなければなりません

・頂点シェーダー(HLSL)
//入力用
struct vertexIn
{
float4 pos : POSITION0;
float4 col : COLOR0;
float2 tex : TEXCOORD0;
};

//出力用
struct vertexOut
{
float4 pos : SV_POSITION;
float4 col : COLOR;
float2 tex : TEXCOORD0;
};

//変換用行列
cbuffer ConstantBuffer : register( b0 )
{
matrix World; //ワールド変換行列
matrix View; //ビュー変換行列
matrix Projection; //透視射影変換行列
}

vertexOut vs_main(vertexIn IN)
{
vertexOut OUT;

OUT.pos = mul(IN.pos, World); //ワールド変換
OUT.pos = mul(OUT.pos, View); //ビュー変換
OUT.pos = mul(OUT.pos, Projection); //透視射影変換
OUT.col = IN.col;
OUT.tex = IN.tex;

return OUT;
}
mulが行列を計算する関数だそうですよ(他人事)
入ってきた頂点座標を,順番に変換していきます

ピクセルシェーダーに変更はありません
変化した頂点座標に合わせて,テクスチャーが貼られます(多分)


……で,問題は,どうやって変換用行列をメインプログラムからシェーダープログラムに渡すのか? です
試行錯誤の末,XNAを使用する方法でしかできませんでした(ぁ
なので,XNAを呼び出すサンプルになったのですよ(*'-')

ここから,C++プログラムの続きです
	//それらをシェーダーに送る
struct ConstantBuffer
{
XMMATRIX mWorld; //ワールド変換行列
XMMATRIX mView; //ビュー変換行列
XMMATRIX mProjection; //透視射影変換行列
};

//constantバッファ生成
ID3D11Buffer* hpConstantBuffer = NULL;
hBufferDesc.ByteWidth = sizeof(ConstantBuffer);
hBufferDesc.Usage = D3D11_USAGE_DEFAULT;
hBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
hBufferDesc.CPUAccessFlags = 0;
hBufferDesc.MiscFlags = 0;
hBufferDesc.StructureByteStride = sizeof(float);
if(FAILED(hpDevice->CreateBuffer(&hBufferDesc, NULL, &hpConstantBuffer))){
MessageBoxW(hWnd, L"Create ConstantBuffer", L"Err", MB_ICONSTOP);
goto End;
}

ConstantBuffer hConstantBuffer;
hConstantBuffer.mWorld = XMMatrixTranspose(hWorld);
hConstantBuffer.mView = XMMatrixTranspose(hView);
hConstantBuffer.mProjection = XMMatrixTranspose(hProjection);
hpDeviceContext->UpdateSubresource(hpConstantBuffer, 0, NULL, &hConstantBuffer, 0, 0);

//コンテキストに設定
hpDeviceContext->VSSetConstantBuffers(0, 1, &hpConstantBuffer);
これを実行すると,3D空間に描画されます

どのへんが3Dなの?('-'*)?
既に自在に空間を操れるようになっています
様々な計算を行うヘルパー関数郡が用意されており,公式とか全く知らなくても色々できるようになっています

ポリゴンをワールドに置く際に,少し傾けて見ます
シェーダーに送る前に,ワールド座標を45度傾けておきます
	XMMATRIX hRotate;
hRotate = XMMatrixRotationZ(D3DXToRadian(-45.0f));
hWorld = XMMatrixMultiply(hWorld, hRotate);
そうすると,傾いた状態で描画されます

まだ,立体的じゃない。と思う想像力が貧困な人の為に,縦にも回転させてみます
	hRotate = XMMatrixRotationY(D3DXToRadian(-45.0f));
hWorld = XMMatrixMultiply(hWorld, hRotate);
遠近感でたでしょ?(そうか?)

カメラを後ろに下げたりもできます
	hEye = XMVectorSet(0.0f, 0.0f, -5.0f, 0.0f);
hView = XMMatrixLookAtLH(hEye, hAt, hUp);
hProjection = XMMatrixPerspectiveFovLH(D3DXToRadian(45.0f), 16.0f/9.0f, 0.0f, 1000.0f);
ずずっと,後ろに下げると小さくなります



TOPプログラマ専用DirectX11開発

Melonbooks DL