Unity Shader #0 数学基礎
このノートでは、レンダリング、CG、シェーダーで使用される可能性のある数学概念について説明します。基本的な数学概念を網羅するものではなく、主に概念の理解とレンダリングでの応用に焦点を当てています。
線形代数
ベクトル
ベクトルの基本概念は省略します。以下の概念がよく使われます:
- 内積:内積の計算は両者の大きさの積に夾角の余弦を掛けたものなので、両方のベクトルが単位ベクトルの場合、内積の結果は cosθ になります。したがって、単位ベクトルを扱う際、内積を夾角の代わりと見なすことができます。
- 外積:外積の重要な性質は、結果が乗算する両方のベクトルに垂直であることです。右手座標系では、四指をベクトル a からベクトル b に巻くと、親指の方向がベクトル a × b の方向になります。外積は法線を求めることや、三角面の向きを判定するのに使えます。
ベクトルと点は形式上どちらも数対です。3次元ベクトル/点を例にすると、数学的な表現だけでは (1,2,3) が点なのかベクトルなのか判断できません。後で斉次座標でこの問題を解決します。
行列
同様に、概念の説明は省略します。行列乗算の計算方法も省略します。以下の概念がよく使われます:
- 逆行列:行列式で行列が可逆かどうかを判断します。detM ≠ 0 であれば、行列 M は可逆です。シェーダーでは行列式を計算するサードパーティライブラリが豊富にあるため、行列式の計算はここでは省略します。逆行列は変換行列の逆変換に使います。
- 計算順序:変換 CBAv では、ベクトル v にまず A 変換、次に B 変換、最後に C 変換を適用します。ここで、v は列ベクトルでなければなりません。注意:ほとんどの場合、複合変換は交換法則を満たさないため、上記の順序は変更できません。
- ほとんどの場合、まずスケール、次に回転、最後に平行移動を行います。
斉次座標
斉次座標(homogeneous coordinate)とは、計算のため3次元座標の後に数値 w を加え、アフィン変換を線形変換に変えるものです。斉次座標の導入は、平行移動のような非線形変換を扱うためです。
- 線形変換:以下の2条件を満たす変換 f を線形変換と呼びます:- f(x) + f(y) = f(x+y)- kf(x) = f(kx)
- アフィン変換:f(x) = Ax + b を満たす変換はすべてアフィン変換と呼ばれます。
注意:点の場合、追加の成分 w = 1;ベクトルの場合、w = 0。これにより、点に平行移動を適用すると結果は点のまま、ベクトルに平行移動を適用すると結果はベクトルのままです(実際には効果はありません)。したがって、点とベクトルは斉次座標空間では形式的に区別されます。
座標空間変換
シェーダーでは、座標空間の変換が最も重要かもしれません。座標空間 A と B の間で相互変換するとします。
点 x_A を A 座標系から B 座標系に変換するには、変換行列 MATRIX_A2B を使用します:
x_B = MATRIX_A2B * x_A
点 y_B を B 座標系から A 座標系に変換するには、変換行列 MATRIX_B2A を使用します:
y_A = MATRIX_B2A * y_B
これを理解することが重要です。変換行列は変換であり、ベクトルの左側に左乗する必要があります。変換行列は元の座標系から目標座標系への変換行列です。したがって上記の結果になります。
通常、シェーダーで遭遇する様々な座標系の変換行列は既に組み込み済みです。シェーダーを書く際に遭遇する可能性のある座標系の種類を把握する必要があります。
頂点変換プロセス
Unity および他のコンピュータグラフィックスレンダリングでは、モデル上の頂点は最終的に複数回の変換を経て、画面上のピクセルにレンダリングされます。
この過程で、最初はモデルのモデル空間にあり、次にワールド空間に変換され、その後ビュー空間に変換され、クリップ空間を経て、最終的にスクリーン空間に変換されます。
モデル空間
モデル空間(Model Space)はローカル空間(Local Space)とも呼ばれます。美術がモデリングする際、ある点を原点とし、x、y、z 軸の正方向を設定します。Unity でオブジェクトをクリックすると表示される3つの軸と軸心が、モデル空間の3軸の正方向と原点を表しています。このオブジェクト上の各点は、この原点と3軸に対して独自の座標を持ちます。
ワールド空間とモデルからワールドへの変換
通常、ワールド空間は Unity の「最外層」の空間です。GameObject に親オブジェクトがない場合、その Transform の Position がワールド空間での座標です。
モデルからワールドへの変換 / モデル変換
モデル変換(Model Transform, M)とは、頂点をモデル空間からワールド空間に変換する変換です。Unity では、UnityShaderVariables.cginc ファイルに定義されている変数 _Object2World をモデル空間座標に左乗すると、座標をモデル空間からワールド空間に変換できます。この行列を M 行列と略称します。
ビュー空間とワールドからビューへの変換
ビュー空間(View Space)はカメラ空間とも呼ばれます。カメラを原点とし、+x 軸をカメラの右方向、+y 軸をカメラの上方向、+z 軸をカメラの後方に設定した座標系です。言い換えると、カメラの前方はビュー空間の -z 方向を指し、ビュー空間は前の2つの空間とは異なる旋向を使用します。前の2つは左手座標系で、ビュー空間は右手座標系です。
ワールドからビューへの変換 / ビュー変換
ビュー変換(View Transform, V)とは、頂点をワールド空間からビュー空間に変換する変換です。Unity では、UnityShaderVariables.cginc ファイルに定義されている変数 UNITY_MATRIX_V をワールド空間座標に左乗すると、座標をワールド空間からビュー空間に変換できます。この行列を V 行列と略称します。
クリップ空間とワールドからビューへの変換
クリップ空間(Clip Space, P)は斉次クリップ空間とも呼ばれます。クリップ空間の役割は、視錐台外のプリミティブをカリングし、視錐台の境界と交差するプリミティブをクリップすることです。
視錐台(View Frustum)とは、Unity のカメラの可視範囲で、6つの平面で囲まれたものです。カメラに最も近い平面を Near Clip 平面、最も遠い平面を Far Clip 平面と呼びます。
Unity には2つのレンダリングモードがあり、Orthographic(正射影)モードでは近遠平面のサイズが同じで、Perspective(透視投影)モードでは遠平面が近平面より大きくなります。
先ほど述べたように、頂点の場合、斉次座標の w 成分は 1 です。Unity では、UNITY_MATRIX_P をビュー空間座標に左乗すると、頂点をビュー空間からクリップ空間に変換できます。正射影と透視投影では対応する投影行列が異なり、その違いは以下の通りです:
-
正射影では、w 成分は投影行列によって -z に変換され、xyz に不同程度のスケールが適用されます。
-
透視投影では、w 成分は依然として 1 です。
透視行列は空間の旋向を変更し、右手座標系から左手座標系に変換するため、カメラから遠くなるほど z が大きくなります。
透視行列はカメラの近遠平面の位置、カメラのアスペクト比(Aspect Ratio)、および視野角(Field of View)に関係します。
クリップ空間からスクリーン空間へ
最後のステップは、頂点を2Dのスクリーン空間に変換することです。このステップは2段階に分かれます:
第一ステップ 斉次除算
x、y、z を x/w、y/w、z/w に変換します。このステップで得られる座標は正規化デバイス座標(NDC 座標)とも呼ばれます。視錐台はこの変換下で立方体になります。
第二ステップ スクリーンマッピング
Unity では、第一步の後、現在の x、y 座標は [-1,1] の範囲に収まっています。この (x,y) を x ∈ [0, width]、y ∈ [0, height] のスクリーン空間にマッピングするだけです。
この時、z 成分は深度バッファに使用される場合があります。
