[DirectX12] World, View, Projection マトリックス
World 行列
View 行列
XMVECTOR Eye = XMVectorSet( 0.0f, 0.0f, -5.0f, 0.0f );
XMVECTOR At = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
XMVECTOR Up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
g_View = XMMatrixLookAtLH( Eye, At, Up );
カメラ位置(座標)と、カメラの見ている場所(注視点)、そしてカメラの上方向のベクトルをXMMatrixLookAtLH に指定することで View 行列が作られる。この行列によって、World 座標から定義した View 座標への変換が行える。
上記の Eye, At, Up から作られる View 行列はこちら。
{1.00, 0.00, 0.00, 0.00}
{0.00, 1.00, 0.00, 0.00}
{0.00, 0.00, 1.00, 0.00}
{0.00, 0.00, 5.00, 1.00}
計算式は以下。
zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)
xaxis.x yaxis.x zaxis.x 0
xaxis.y yaxis.y zaxis.y 0
xaxis.z yaxis.z zaxis.z 0
-dot(xaxis, eye) -dot(yaxis, eye) -dot(zaxis, eye) 1
計算式を見れば分かるが up ベクトルが必要なのは、カメラからの視線のベクトルと up 方向のベクトルの外積を取って、横方向(xaxis)のベクトルを計算するために使用している。つまり、カメラの3次元での軸を決定するために、上方向がどちらかという情報が必要になる。
Projection 行列
g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV4, width / (FLOAT)height, 0.01f, 100.0f );
- XM_PIDIV4 は 0.785398163f(3.14/4)
- 2つ目はビュースペースのアスペクト比。(640/480=1.333333)
- 3つ目と、4つ目は NearPlane と FarPlane。(0.01~100.0)
これによって、下記の Projection 行列が得られる。
{1.81066, 0.00, 0.00, 0.00}
{0.00, 2.41421, 0.00, 0.00}
{0.00, 0.00, 1.0001, 1.00}
{0.00, 0.00, -0.01, 0.00}
計算式としては下記。
xScale 0 0 0
0 yScale 0 0
0 0 zf/(zf-zn) 1
0 0 -zn*zf/(zf-zn) 0
where:
yScale = cot(fovY/2)
xScale = yScale / aspect ratio
https://learn.microsoft.com/ja-jp/windows/win32/direct3d9/d3dxmatrixperspectivefovlh
Viewport 行列
640×480 のレンダーターゲットに描画する場合は、Viewport も Width 640, Height 480 に設定する。他は通常はデフォルト値の X, Y 0で、Min 0.0, Max 1.0 になるのが普通。
dwWidth/2, 0, 0, 0,
0, -dwHeight/2, 0, 0,
0, 0, dwMaxZ-dwMinZ, 0,
dwX+DwWidth/2, dwHeight/2+dwY, dwMinZ, 1,
https://learn.microsoft.com/ja-jp/windows/win32/direct3d9/viewports-and-clipping
実際は width, height ぐらいしかパラメータは設定しないので、
w = width / 2
h = height / 2
w 0 0 0
0 -h 0 0
0 0 1 0
w h 0 1
ぐらいの単純な行列になる。
SV_Position の値
頂点シェーダーを使用して、上記のような View, Projection 行列で、ローカル座標 [ -1.0f, 1.0f, -1.0f] を変換した場合はこのような結果になる。
[-1.81066, 2.41421, 3.9904, 4.00]
頂点シェーダーから SV_Position へ渡している値はこれ。
ラスタライザを通り、ピクセルシェーダーの入力として渡ってくる SV_Position は下記のようになる。
[175.50, 95.50, 0.9976, 4.00]
X, Y はピクセルのスクリーン座標。
Z は Depth Buffer に書かれる値と一致する。頂点シェーダーからの出力 3.9904 / 4.0 = 0.9976 になる。
W は頂点シェーダーでの World, View, Projection の計算結果がそのまま来る。