2012年5月22日火曜日

Tutorial 07: Texture Mapping and Constant Buffers の和訳


要約

Summary 

In the previous tutorial, we introduced lighting to our project.
Now we will build on that by adding textures to our cube. 
Also, we will introduce the concept of constant buffers, and explain how you can use buffers to speed up processing by minimizing bandwidth usage.

The purpose of this tutorial is to modify the center cube to have a texture mapped onto it.

前のチュートリアルでは、プロジェクトへのライティングについて説明しました。ここではそれを元にして、立方体にテクスチャーを追加します。また、定数バッファーの概念およびそれを使用して帯域幅使用率を最小限に抑えることで処理を高速化する方法について説明します。

このチュートリアルの目的は、中央の立方体の上にテクスチャーがマッピングされるように変更する事です。


テクスチャマッピング

Texture Mapping

Texture mapping refers to the projection of a 2D image onto 3D geometry.

テクスチャマッピングは3D幾何上の2Dイメージの投影のことを指します。

We can think of it as wrapping a present, by placing decorative paper over an otherwise bland box.

それは、平凡な箱の上に包装紙を配置する、プレゼントのラッピングと考えられます。

To do this, we have to specify how the points on the surface of the geometry correspond with the 2D image.

これをやるには、幾何表面上の頂点が2Dイメージとどの様に対応するかを指定する必要があります。

The trick is to properly align the coordinates of the model with the texture.

その方法は、モデルの座標とテクスチャーを正しく合わせるというものです。

For complex models, it is difficult to determine the coordinates for the textures by hand.

複雑なモデルでは、手動でテクスチャの座標を決めるのが難しいです。

Thus, 3D modeling packages generally will export models with corresponding texture coordinates.

そこで3Dモデリングのソフトは一般的にモデルを対応するテクスチャ座標と共にエクスポートします。

Since our example is a cube, it is easy to determine the coordinates needed to match the texture.

我々の例は立方体だからテクスチャに合わせる座標を決めるのは簡単です。

Texture coordinates are defined at the vertices, and are then interpolated for individual pixels on a surface.

テクスチャ座標は頂点として定義され、そして そこから面上に個々のピクセルが挿入されます。


テクスチャーとサンプルステートからのシェーダーリソースの作成

Creating a Shader Resource from the Texture and Sampler State


The texture is a 2D image that is retrieved from file and used to create a shader-resource view, so that it can be read from a shader.

テクスチャはファイルから回収される2D画像です。そしてそれをシェーダーから読める様にするため、シェーダーリーソースビューを作ります。

hr = D3DX11CreateShaderResourceViewFromFile
( g_pd3dDevice, L"seafloor.dds", NULL, NULL, &g_pTextureRV, NULL );

We also need to create a sampler state that controls how the shader handles filtering, MIPs, and addressing.

サンプラーステートも作る必要があります。これはシェーダーがどの様にフィルタリング、ミップマップ,そしてアドレッシングを操るかコントロールします。

For this tutorial we will enable simple sampler state that enables linear filtering and wrap addressing.

このチュートリアルでは単純なサンプラステートを有効にします。これは線形フィルタリングとラップアドレッシングを有効にします。

To create the sampler state, we will use ID3D11Device::CreateSamplerState().

サンプラステートを作るにはID3D11Device::CreateSamplerState()が使えます。

// Create the sample state
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory( &sampDesc, sizeof(sampDesc) );
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
hr = g_pd3dDevice->CreateSamplerState( &sampDesc, &g_pSamplerLinear );


座標の定義

Defining the Coordinates


Before we can map the image onto our cube, we must first define the texture coordinates on each of the vertices of the cube.

立方体に画像をマッピング出来るようにするため、最初に立方体のそれぞれの頂点にテクスチャ座標を定義する必要があります。

Since images can be of any size, the coordinate system used has been normalized to [0, 1].

画像サイズが色んなサイズがあり得るので、使用される座標系を [0, 1] に正規化する必要があります。

The top left corner of the texture corresponds to (0,0) and the bottom right corner maps to (1,1).

テクスチャーの左上の隅が(0,0)に対応し、右下の隅が(1,1)にマッピングされます。

In this example, we're having the whole texture spread across each side of the cube.

この例では、テクスチャ全体を立方体のそれぞれの面に対して広げています。

This simplifies the definition of the coordinates, without confusion.

これは座標の定義を混乱なしに簡素化します。

However, it is entirely possible to specify the texture to stretch across all six faces, although it's more difficult to define the points, and it will appear stretched and distorted.

しかしながら、テクスチャーを 6 面すべてにわたって引き伸ばすように指定することは可能です。しかしこの場合、点の定義がもっと難しくなるし、伸ばされて曲げられたように見えるでしょう。

First, we updated the structure used to define our vertices to include the texture coordinates.

最初に、テクスチャ座標を含んだ頂点を定義するために構造体を作り変えました。

struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT2 Tex;
};

Next, we updated the input layout to the shaders to also include these coordinates.

次に、シェーダーに対するインプットレイアウトもこれらの座標を含む様に更新しました。

// インプットレイアウトの定義
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

Since the input layout changed, the corresponding vertex shader input must also be modified to match the addition.

インプットレイアウトが変わったから、この追加にマッチするように対応する頂点シェーダの入力も変えなければなりません。

struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD;
};

Finally, we are ready to include texture coordinates in our vertices we defined back in Tutorial 4.

ついに、チュートリアル 4 で定義した頂点にテクスチャー座標を含める準備ができました。

Note the second parameter input is a D3DXVECTOR2 containing the texture coordinates.

入力のうちの2番目の値はテクスチャ座標を含んだD3DXVECTOR2である事に注目して下さい。
(訳注: 実際にはDirect3D11のサンプルではD3DXVECTRO2ではなくXMFLOAT2を使っています。)

Each vertex on the cube will correspond to a corner of the texture.

立方体のそれぞれの頂点はテクスチャの角と一致する事になります。

This creates a simple mapping where each vertex gets (0,0) (0,1) (1,0) or (1,1) as the coordinate.

これにより、各頂点の座標が (0,0) (0,1) (1,0) または (1,1) となる単純なマッピングが作成されます。

// Create vertex buffer
SimpleVertex vertices[] =
{
{ XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

{ XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },
};

When we sample the texture, we will need to modulate it with a material color for the geometry underneath.

テクスチャーをサンプリングするときは、下にあるジオメトリのマテリアル カラーでそれを調整する必要があります。

 テクスチャをシェーダリソースとして登録する

Bind Texture as Shader Resource


A texture and sampler state are objects like the constant buffers that we have seen in previous tutorials.

前回のチュートリアルで定数バッファを見ましたが、テクスチャとサンプラステートはそれと似たオブジェクトです。

Before they can be used by the shader, they need to be set with the ID3D11DeviceContext::PSSetSamplers() and ID3D11DeviceContext::PSSetShaderResources() APIs.

それらがシェーダーで使われる前にID3D11DeviceContext::PSSetSamplers()ID3D11DeviceContext::PSSetShaderResources()APIsを使ってセットする必要があります。


g_pImmediateContext->PSSetShaderResources( 0, 1, &g_pTextureRV );
g_pImmediateContext->PSSetSamplers( 0, 1, &g_pSamplerLinear );

There we go, now we're ready to use the texture within the shader.

ここまでで、シェーダー内のテクスチャーを使用する準備ができました。

 テクスチャの適用

Applying the Texture


To map the texture on top of the geometry, we will be calling a texture lookup function within the pixel shader.

幾何上にテクスチャをマップするには、ピクセルシェーダー内のでテクスチャ・ルックアップ関数を呼びます。

The function Sample will perform a texture lookup of a 2D texture, and then return the sampled color.

関数Sample()は2Dテクスチャの探索(ルックアップ)を行い、そしてサンプルされた色を返します。

The pixel shader shown below calls this function and multiplies it by the underlying mesh color (or material color), and then outputs the final color.

以下で示したピクセルシェーダはこの関数を呼び、元のメッシュの色(または材質の色)を掛け、最終的な色を出力します。

●txDiffuse is the object storing our texture that we passed in from the code above, when we bound the resource view g_pTextureRV to it.

txDiffuse は、リソース ビュー g_pTextureRV をそれにバインドしたときに、上のコードから渡したテクスチャーを格納するオブジェクトです。

●samLinear will be described below; it is the sampler specifications for the texture lookup.

samLinear は、テクスチャー ルックアップのためのサンプラ仕様であり、以下で説明されています。

●input.Tex is the coordinates of the texture that we have specified in the source.

input.Tex は、ソース内で指定したテクスチャーの座標です。

// Pixel Shader(ピクセルシェーダ)
float4 PS( PS_INPUT input) : SV_Target
{
return txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor;
}

Another thing we must remember to do is to pass the texture coordinates through the vertex shader.

あと忘れてはいけないのが頂点シェーダーを通じてテクスチャー座標を渡すことです。

If we don't, the data is lost when it gets to the pixel shader.

これを行わないと、それがピクセル シェーダーに到達するときにはデータは失われます。

Here, we just copy the input's coordinates to the output, and let the hardware handle the rest.

ここでは、単純に入力の座標を出力にコピーして、ハードウェアに残りを処理させます。

// Vertex Shader(頂点シェーダ)
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Tex = input.Tex;

return output;
}



定数バッファ

Constant Buffers


In Direct3D 11, an application can use a constant buffer to set shader constants (shader variables).

Direct3D 11ではアプリケーションで定数バッファーを使用してシェーダー定数 (シェーダー変数) を設定できます。

Constant buffers are declared using a syntax similar to C-style structs.

定数バッファはCスタイルの構造体に似た文法を使って宣言されます。

Constant buffers reduce the bandwidth required to update shader constants by allowing shader constants to be grouped together and committed at the same time, rather than making individual calls to commit each constant separately.

定数バッファはシェーダーの定数の更新に必要なバンド幅を減らすのに一役買います。定数バッファを使えば、それぞれのシェーダー定数を別々に渡すのではなく、更新タイミングを元にグループ化されたデータを渡す事が出来るからです。

In the previous tutorials, we used a single constant buffer to hold all of the shader constants we need.

前回のチュートリアルでは必要な全てのシェーダー定数を保持するために、一つの定数バッファを使いました。

But the best way to efficiently use constant buffers is to organize shader variables into constant buffers based on their frequency of update.

しかし定数バッファを使うベストな方法は、更新頻度に基づいて定数バッファへ入れるシェーダー変数を構成する事です。

This allows an application to minimize the bandwidth required for updating shader constants.

 これがシェーダー定数を更新する時に必要なバンド幅を最小化する事を可能にします。 


As an example, this tutorial groups constants into three structures: one for variables that change every frame, one for variables that change only when a window size is changed, and one for variables that are set once and then do not change.

例えば、このチュートリアルでは定数を3つの構造体にグループ化しました。:一つは全てのフレーム(コマ)で変わる変数用、もう一つはウインドウサイズが変わった時のみ変わる変数用、そして一旦セットされたら変わらない変数用です。

The following constant buffers are defined in this tutorial's .fx file.

以下の定数バッファはこのチュートリアルのfxファイルに定義されています。

cbuffer cbNeverChanges
{
matrix View;
};

cbuffer cbChangeOnResize
{
matrix Projection;
};

cbuffer cbChangesEveryFrame
{
matrix World;
float4 vMeshColor;
};

To work with these constant buffers, you need to create a ID3D11Buffer object for each one.

これらの定数バッファを機能させるには、それぞれに対してID3D11Bufferオブジェクトを作る必要があります。

Then you can call ID3D11DeviceContext::UpdateSubresource() to update each constant buffer when needed without affecting the other constant buffers.

そのためにID3D11DeviceContext::UpdateSubresource()を呼びます。これによって 必要な時に、他の定数バッファに影響を与える事なしに それぞれの定数バッファを更新出来ます。

//
// Update variables that change once per frame
// フレーム毎に更新する変数
CBChangesEveryFrame cb;
cb.mWorld = XMMatrixTranspose( g_World );
cb.vMeshColor = g_vMeshColor;
g_pImmediateContext->UpdateSubresource( g_pCBChangesEveryFrame, 0, NULL, &cb, 0, 0 );

0 件のコメント: