#5では、シェーダーからテクスチャにアクセスし色を取得しました。しかし、テクスチャのある1点しか取得できなかったので、今回は面にテクスチャ全体を表示してみましょう。
頂点にUV座標を追加
ピクセルシェーダーでテクスチャから色を取得する時、「このピクセルは、テクスチャのこの位置だよー」という情報(データ)が必要になります。その情報は頂点に仕込んでおきます。いま頂点のデータと言えば「座標」だけですが、さらに「UV」座標の情報を追加します。
頂点と画像の位置関係を結びつけるのが、UV座標
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
~省略~ // このゲームの時間を進める(処理を実行する) void GameSystem::Execute() { // 画面を青色で塗りつぶす float color[4] = { 0.2f, 0.2f, 1.0f, 1.0f }; D3D.m_deviceContext->ClearRenderTargetView(D3D.m_backBufferView.Get(), color); // 三角形の描画 { /* // 1頂点の形式(今回は座標だけ) struct VertexType { DirectX::XMFLOAT3 Pos; // 座標 }; // 三角形を作るため、頂点を3つ作る VertexType v[4] = { {{-0.5f, -0.5f, 0}}, {{-0.5f, 0.5f, 0}}, {{ 0.5f, -0.5f, 0}}, {{ 0.5f, 0.5f, 0}}, }; ↓↓↓ 変更 ↓↓↓ */ // 1頂点の形式(今回は座標だけ) struct VertexType { DirectX::XMFLOAT3 Pos; // 座標 DirectX::XMFLOAT2 UV; // UV座標 }; // 三角形を作るため、頂点を3つ作る VertexType v[4] = { {{-0.5f, -0.5f, 0}, {0, 1}}, {{-0.5f, 0.5f, 0}, {0, 0}}, {{ 0.5f, -0.5f, 0}, {1, 1}}, {{ 0.5f, 0.5f, 0}, {1, 0}}, }; ~省略~ |
今回の設定では、上図のように四角形に合わせてテクスチャがピッタリ表示されるようにしました。もちろんこの値を変更すれば、テクスチャの一部分だけを表示したり、回転して表示したり、タイル状に並べて連続で表示したりするも可能です。
入力レイアウトの変更
UV座標を追加したことにより、頂点の形式が変更になりました。入力レイアウトの存在を覚えているでしょうか?これも新しい形式に合わせる必要があります。
入力レイアウトにUVの情報も追加する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
~省略~ // 1頂点の詳細な情報 std::vector<D3D11_INPUT_ELEMENT_DESC> layout = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXUV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; // 頂点インプットレイアウト作成 if (FAILED(m_device->CreateInputLayout(&layout[0], layout.size(), compiledVS->GetBufferPointer(), compiledVS->GetBufferSize(), &m_spriteInputLayout))) { return false; } return true; } |
注意点としては、Offset値の設定を間違えないようにすることです。今回の頂点では「UVの情報は12バイト目にありますよ」と正確に示さなければいけません。間違えるとデータがずれて認識されるため、正常に描画できなくなり変な色で表示されてしまいます。
UV座標は(x ,y)のデータなので、フォーマットには「DXGI_FORMAT_R32G32_FLOAT」を指定します(32ビット(4バイト)のfloatデータが2つ)。
セマンティクスは「TEXUV」にしていますが、これは自由なので好きな名前でいいです。一般的にはTEXCOORDとすることが多い感じですが、わかりやすくするためにTEXUVにしておきましょう。
シェーダーでUV座標を使用
入力レイアウトも変更できたので、最後は描画時に実行されるシェーダーの改良です。頂点のUV座標を活用しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// テクスチャ Texture2D g_texture : register(t0); // サンプラ SamplerState g_sampler : register(s0); // 頂点シェーダーから出力するデータ struct VSOutput { float4 Pos : SV_Position; // 頂点の座標(射影座標系) float2 UV : TEXCOORD0; // UV座標 }; //======================================== // 頂点シェーダー //======================================== VSOutput VS(float4 pos : POSITION, float2 uv : TEXUV) { VSOutput Out; // 頂点座標を、何も加工せずそのまま出力 Out.Pos = pos; // 頂点のUV座標を、何も加工せずそのまま出力 Out.UV = uv; return Out; } //======================================== // ピクセルシェーダー //======================================== float4 PS(VSOutput In) : SV_Target0 { // テクスチャから色を取得 float4 texColor = g_texture.Sample(g_sampler, In.UV); // 緑色にする return texColor; } |
UVは頂点に追加したデータなので、頂点シェーダーの引数として受け取ります。入力レイアウトで指定したセマンティクス「TEXUV」を間違えなく指定しましょう。受け取ったUVは、そのまま出力してください。これがピクセルシェーダーに渡った時には、ピクセル単位のUVになっています。
ピクセルシェーダーでは、g_terxture.Sample(・・・, In.UV) とすることで、上図のようにピクセルに対応するテクスチャの色を取得することができます。例えば、左上のピクセルなら(0,0)、真ん中なら(0.5, 0.5)といった感じです。
完成
これでテクスチャマッピングの完成です。