LoginSignup
1
0

More than 3 years have passed since last update.

4次元行列と透視行列

Last updated at Posted at 2020-05-18

主に3DCG関係で自分がよく使用する4次元行列関係の数式の自分用メモです。

表記

M = \begin{pmatrix}
M_{00} & M_{01} & M_{02} & M_{03}\\
M_{10} & M_{11} & M_{12} & M_{13}\\
M_{20} & M_{21} & M_{22} & M_{23}\\
M_{30} & M_{31} & M_{32} & M_{33}
\end{pmatrix}

行列式

4次元行列の行列式は少し複雑です。
疑似コードで表現します。

function determinat(M)
  d := 0
  for i=0 to 3
    j := (i == 0) ? 1 : 0
    k := (i <= 1) ? 2 : 1
    l := (i <= 2) ? 3 : 2
    a := M[1,j] * (M[2,k]*M[3,l] - M[3,k]*M[2,l])
    a += M[1,k] * (M[2,l]*M[3,j] - M[3,l]*M[2,j])
    a += M[1,l] * (M[2,j]*M[3,k] - M[3,j]*M[2,k])
    if (i mod 2) == 0
      d += M[0,i] * a
    else
      d -= M[0,i] * a
    endif
  next
  return d
end

逆行列

4次元行列の逆行列も少し複雑です。
疑似コードで表現します。

function inverse(M)
  R := ( 1, 0, 0, 0,
         0, 1, 0, 0,
         0, 0, 1, 0,
         0, 0, 0, 1 )
  d := 1.0 / determinat(M)
  for i=0 to 3
    j0 := (i == 0) ? 1 : 0
    j1 := (i <= 1) ? 2 : 1
    j2 := (i <= 2) ? 3 : 2
    for j=0 to 3
      i0 := (j == 0) ? 1 : 0
      i1 := (j <= 1) ? 2 : 1
      i2 := (j <= 2) ? 3 : 2
      a := M[i0,j0] * (M[i1,j1]*M[i2,j2] - M[i2,j1]*M[i1,j2])
      a += M[i0,j1] * (M[i1,j2]*M[i2,j0] - M[i2,j2]*M[i1,j0])
      a += M[i0,j2] * (M[i1,j0]*M[i2,j1] - M[i2,j0]*M[i1,j1])
      if ((i + j) mod 2) == 0
        R[i,j] := a * d
      else
        R[i,j] := -a * d
      endif
    next
  next
  return R
end

透視変換(z遠方制限なし)

ほとんど使用しないですが、zが無限遠までクリップされない視錐台
z = zs/2 ~ ∞
z座標の手前側の制限については注意が必要。手前側の制限についてはz制限付きの一般的な透視変換式から任意の値を導出可能

width : 画面幅
height : 画面高
x0 : 画面の中心x座標
y0 : 画面の中心y座標
zs : 投影面のz座標(透視座標と等倍になるz)

\begin{align}
ws &= 0.5 \cdot width\\
hs &= 0.5 \cdot height\\
xs &= zs / ws\\
ys &= -zs / hs\\
xo &= (x0 - ws) / ws\\
yo &= -(y0 - hs) / hs\\
Proj &= \begin{pmatrix}
xs & 0 & xo & 0 \\
0 & ys & yo & 0 \\
0 & 0 & 1 & -zs \\
0 & 0 & 1 & 0
\end{pmatrix}
\end{align}

※俺々エンジンの座標系から OpenGL への変換なので注意
 俺々エンジンはy座標は下に延びていて上下反転している。

透視変換

一般的な視錐台。
但し、俺々エンジンの座標系のためy座標が反転することに注意。

width : 画面幅
height : 画面高
x0 : 画面の中心x座標
y0 : 画面の中心y座標
zs : 投影面のz座標(透視座標と等倍になるz)
near : 視錐台の手前側z座標
far : 視錐台の奥側z座標

\begin{align}
ws &= 0.5 \cdot width\\
hs &= 0.5 \cdot height\\
xs &= zs / ws\\
ys &= -zs / hs\\
xo &= (x0 - ws) / ws\\
yo &= -(y0 - hs) / hs\\
zn &= near\\
zf &= 2 \cdot far\\
Proj &= \begin{pmatrix}
xs & 0 & xo & 0 \\
0 & ys & yo & 0 \\
0 & 0 & \frac{zf+zn}{zf-zn} & -\frac{2 \cdot zf \cdot zn}{zf - zn} \\
0 & 0 & 1 & 0
\end{pmatrix}
\end{align}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0