[Python] Numpy で3D座標変換 その1

[Python] Numpy で3D座標変換 その1

World 行列

Scale

Transform

trans = np.mat(
    [
        [1.0,0.0,0.0,0.0],
        [0.0,1.0,0.0,0.0],
        [0.0,0.0,1.0,0.0],
        [1.0,2.0,3.0,1.0],
    ]
)

v1 = np.array([-1.0,1.0,-1.0,1.0])
v1 = np.matmul(v1,trans)
v1

Rotation

View 行列

eye = np.array([0.0, 0.0,-5.0])
at = np.array([0.0,0.0,0.0])
up = np.array([0.0,1.0,0.0])

# zaxis
a = at - eye
b = np.linalg.norm(at-eye)
zaxis = a / b

# xaxis
d = np.cross(up, zaxis)
e = np.linalg.norm(d)
xaxis = d / e

# yaxis
yaxis = np.cross(zaxis, xaxis)

view = np.mat(
        [
            [xaxis[0], yaxis[0], zaxis[0], 0.0],
            [xaxis[1], yaxis[1], zaxis[1], 0.0],
            [xaxis[2], yaxis[2], zaxis[2], 0.0],
            [-np.dot(xaxis, eye), -np.dot(yaxis, eye), -np.dot(zaxis,eye),1.0]
        ]
    )

view

Projection 行列

povy = 0.785398163
yscale = 1.0 / np.tan(povy/2.0)

aspect = 1.333333333
xscale = yscale / aspect

zn = 0.01
zf = 100.0

proj = np.mat(
    [
        [xscale, 0, 0, 0],
        [0, yscale, 0, 0],
        [0, 0,  zf / (zf-zn), 1 ],
        [0, 0, -zn * zf / (zf-zn), 0]
    ]
)

proj

頂点を計算

座標 (-1.0, 1.0, -1.0) の頂点を View, Proj 変換を行う。

v1 = np.array([-1.0,1.0,-1.0,1.0])
v1 = np.matmul(v1,view)
v1 = np.matmul(v1,proj)

v1 頂点を変換して、頂点シェーダーからの出力として、SV_POSITION に渡される値は下記になる。

[-1.81066017,  2.41421356,  3.99039904,  4.        ]

なお、この時点での座標は w が 4.0 の同次座標と呼ばれるものになっている。w 4.0 を使って xyz を割る(正規化する)ことにより、座標は NDC(Normalized Device Coordinate)と呼ばれる空間に移る。

この空間は xy が [-1, 1] で、z が [0, 1] の範囲の座標になる。(OpenGL の場合は z は [-1, 1] まで)w で割った後の座標は下記になる。

[-0.45266504,  0.60355339,  0.99759976]

xy が [-1,1] で、z が [0,1] の範囲に収まっている。この値を、次に説明する Viewport のスケール行列を掛けることにより、スクリーン上の座標へとスケールする。

ラスタライザで Pixel 位置を計算

頂点は v1 / v1[0,3] で、w で割っている。その後に Viewport のスケール行列を掛ける。

w = 640.0/2
h = 480.0/2
viewport = np.mat(
    [
        [w, 0, 0, 0],
        [0, -h, 0, 0],
        [0, 0, 1, 0],
        [w, h, 0, 1]
    ]
)

v1 = v1 / v1[0,3]
v1 = np.matmul(v1, viewport)
v1

v1 の結果として、下記になる。

[175.14718614,  95.14718618,   0.99759976,   1.        ]

この結果により座標変換を行った頂点は Viewport 640×480 の 175, 96 位置にラスタライザされる。 Depth Buffer に書かれるのは、この時の3つ目の要素 0.9976 あたりがこの時の深度値。

参考

https://shikihuiku.github.io/post/projection_matrix/

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA