[Python] Numpy で3D座標変換 その3
Depth から World Position を復元
3D座標変換その2 で (320. , 33.06740882, 0.9986713, 1.0)という値から、World Position を復元する。
このベクトルの値は SV_POSITION の値として、頂点シェーダーから出力され、ピクセルシェーダーに入ってきた値を float4 の値を想定している。
ここに乗せている Python コードは「3D座標変換その2」に書いているコードの後ろに足せば、動くようにしている。
Depth から World Position を求めるのは以下の通り
- ピクセルシェーダーに来た座標を NDC 空間に戻す
- View と Proj の逆行列を求める
- NDC 空間の座標に、ViewProj の逆行列を掛ける
- ViewProj 行列の逆行列を求める
- もしくは View と Proj の逆行列をそれぞれ求めて、InvProj から順番にかけていく。
- 求めたベクトルの X,Y,Z を W で割る
NDC 空間に戻す
uv = np.array([v1[0,0]/screenWidth, v1[0,1]/screenHeight])
uv = (uv * 2.0) - 1.0
ndc = np.array([uv[0], uv[1], v1[0,2], 1.0])
ndc[1] = ndc[1] * -1.0
SV_Position の XY にはピクセルのスクリーン位置が返ってくる。その値を描画したスクリーンサイズで割ることで、[0,1] 範囲の UV を求めている。そして、NDC の XY 座標は [-1,1] の範囲を取るため、2倍して1引くことで NDC での座標に変換している。
ndc 変数に値をセットしているが、XY は先ほど UV の値から求めた座標を入れて、Z は SV_Position の値をそのまま代入している。(これは、DirectX の NDC の Z が [0,1] のためそのまま使用。[-1,1] の環境では、別途変換が必要)
View Proj の逆行列を掛ける
viewProjInv = np.linalg.inv(view*proj)
wp = np.matmul(ndc, viewProjInv)
#projInv = np.linalg.inv(proj)
#viewInv = np.linalg.inv(view)
#wp = np.matmul(ndc, projInv)
#wp = np.matmul(wp, viewInv)
wp = wp/wp[0,3]
ViewProj の逆行列をかけるか、もしくは、View, Proj の逆行列をそれぞれ求めて、projInv から順番にかけていく。最後に W で割れば、World Position が復元できた。
[[0. 2.5 2. 1. ]]