ワールド座標からレンダリングイメージ上の位置とZ(Depth)値を計算 (スクリプト)
スクリプトでワールド座標位置の1点をレンダリングイメージ上の2次元空間の位置XYとZ値(Depth値)を計算するには、
ベクトルと行列計算を使用します。
スクリプトでは、ベクトルと行列計算でnumpyを使用するのが便利です。
「3DCGでの座標変換の流れ」の手順で、ワールド座標位置を順番にレンダリングイメージ上の位置まで変換します。
ワールド座標 → ビュー座標 → パースペクティブ座標 → デバイス座標、
と座標変換を行い、最終的なレンダリングイメージ上の位置を計算します。
Shade3Dのスクリプトでは、sceneクラスから以下の座標変換の行列を取得できます。
# ワールド座標系からビュー座標系に変換する行列を取得.
wvMat = xshade.scene().world_to_view_matrix
# ワールド座標系からパースペクティブ座標系に変換する行列を取得.
wpMat = xshade.scene().world_to_perspective_matrix
# ワールド座標系からデバイス座標系に変換する行列を取得.
wdMat = xshade.scene().world_to_device_matrix
# ワールド座標系からユーザー座標系に変換する行列を取得.
wuMat = xshade.scene().world_to_user_matrix
戻り値は、4×4=16の実数が配列で返ります。
ビュー座標系からデバイス座標系に変換する行列のメソッドはないですが、
上記の行列と逆行列の乗算で計算できます。
ワールド座標からレンダリングイメージ上の位置を計算
ワールド座標上の1点をカメラから見たレンダリングイメージ上の位置に変換するには、以下のスクリプトを実行します。
import numpy
import math
scene = xshade.scene()
# ワールド座標からデバイス座標への変換行列.
wdMat = numpy.matrix(scene.world_to_device_matrix)
# ワールド座標位置 (xyzwの4要素を格納する。w=1.0).
wPos = [10.0, 15.0, 150.0, 1.0]
# ワールド座標からデバイス座標に変換.
dPos = numpy.dot(wPos, wdMat)
dPos = [dPos[0,0], dPos[0,1], dPos[0,2], dPos[0,3]]
# デバイス座標をレンダリングイメージ上の座標に変換.
sx = dPos[0] / dPos[3] # x/w
sy = dPos[1] / dPos[3] # y/w
depth = dPos[2] / dPos[3] # z/w
ここで計算された(sx, sy)が、wPos(10.0, 15.0, 150.0)をレンダリングイメージの座標に変換した位置になります。
depthが0.0-1.0の実数値で表されるZ値です。
ただし、ここのDepth値はマルチパスの「Z値 (ZDepth)」とは異なります。
ワールド座標からマルチパスの「Z値 (ZDepth)」を計算
マルチパスの「Z値 (ZDepth)」は、ビュー座標でのカメラから対象位置までの距離が格納されています。
これは以下の式で計算できます。
import numpy
import math
scene = xshade.scene()
# ワールド座標位置 (xyzwの4要素を格納する。w=1.0).
wPos = [10.0, 15.0, 150.0, 1.0]
# ワールド座標系からビュー座標系に変換する行列を取得.
wvMat = numpy.matrix(scene.world_to_view_matrix)
# ワールド座標からビュー座標に変換.
vPos = numpy.dot(wPos, wvMat)
vPos = [vPos[0,0], vPos[0,1], vPos[0,2], vPos[0,3]]
# vPosの長さを計算.
zDist = numpy.linalg.norm(numpy.array([vPos[0], vPos[1], vPos[2]]))
print "zDist = " + str(zDist)
ここで計算されたzDist値が、マルチパスの「Z値 (ZDepth)」に格納される値になります。
レンダリングイメージ上の位置(sx, sy)からワールド座標に変換するには、
「レンダリングイメージ上の1点より、ワールド座標位置を計算」をご参照くださいませ。