はじめに
前回の記事で頂点シェーダでの座標変換の話が出てきました。
多くの場合、頂点シェーダでは入力の頂点座標にMVP行列を掛ける作業を行います。
今回の記事では、このMVP行列についてざっくり解説を行います。
まず最初に行列の導入と行列による座標変換を紹介します。
その後、Model行列、View行列、Projection行列の順で説明していきます。
行列の導入
行列とは数字を縦横に並べたものです。
縦にm個、横にn個ならべたものをm×n行列と呼びます。
(acbd),⎝⎜⎛adgbehcfi⎠⎟⎞,(adbecf),⎝⎜⎜⎜⎛acegbdfh⎠⎟⎟⎟⎞,⎝⎜⎜⎜⎜⎛a11a21⋮am1a12a22⋮am2……⋱…a1na2n⋮amn⎠⎟⎟⎟⎟⎞
左から順に、2×2行列、3×3行列、2×3行列、4×2行列、m×n行列です。
それぞれの行を1行目2行目...と数え、
それぞれの列を1列目2列目...と数えます。
行列の掛け算
l×m行列とm×n行列の積は次のように定義されます。
⎝⎜⎜⎜⎜⎛a11a21⋮al1a12a22⋮al2……⋱…a1ma2m⋮alm⎠⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎛b11b21⋮bm1b12b22⋮bm2……⋱…b1nb2n⋮bmn⎠⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎛j=1∑ma1jbj1j=1∑ma2jbj1⋮j=1∑maljbj1j=1∑ma1jbj2j=1∑ma2jbj2⋮j=1∑maljbj2……⋱…j=1∑ma1jbjnj=1∑ma2jbjn⋮j=1∑maljbjn⎠⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎞
行列同士の掛け算の例をいくつか出してみます。
(4−22)⎝⎜⎛531⎠⎟⎞=4⋅5+(−2)⋅3+2⋅1=16
⎝⎜⎛214−132⎠⎟⎞(45)=⎝⎜⎛2⋅4+(−1)⋅51⋅4+3⋅54⋅4+2⋅5⎠⎟⎞=⎝⎜⎛31926⎠⎟⎞
(1028)(3645)=(1⋅3+2⋅60⋅3+8⋅61⋅4+2⋅50⋅4+8⋅5)=(15481440)
(3645)(1028)=(3⋅1+4⋅06⋅1+5⋅03⋅2+4⋅86⋅2+5⋅8)=(363852)
1つ目の行列の列数と2つ目の行列の行数が等しくないと掛け算はできません。
行列の掛け算は前後の順番を入れ替えられません。
行列の積には結合法則が成り立ちます。
行列A,B,Cの積ABCについて、
前から先に計算しても後ろから先に計算しても等しくなります。
(AB)C=A(BC)
他にも足し算やスカラー倍、転置をとったり逆行列をとったりと、
行列にはさまざまな計算がありますが、今回は使わないので説明は省略します。
行列と連立方程式
行列の導入と掛け算について説明をしました。
行列は数字が複数組み合わさったものなので掛け算の計算も複雑です。
なぜあのように面倒な計算なのでしょうか。
分数の足し算は「通分をしてから分子だけを足す」というルールが有りましたが、
このルールにはきちんとした意味があるものでした。
たとえば21と31を足す場合、
ケーキのホールの半分と31を考えてみると
6等分を単位として考える意味がわかります。
行列のよくわからない計算のルールにも、このような意味があるのでしょうか。
行列の計算の意味といってもいろいろとありますが、
ここでは「連立方程式の便利表記」という意味を説明していきます。
次のような連立方程式の問題を解く場合を考えてみましょう。
プリンを3個とヨーグルトを2個買ったら690円でした。
プリンを4個とヨーグルトを5個買ったら1200円でした。
プリンとヨーグルトはそれぞれ何円でしょう。
まずは行列を使わずに普通に解いてみましょう。
プリンの値段をx円、ヨーグルトの値段をy円とします。
すると次のような式がたてられます。
{690=3x+2y1200=4x+5y
あとはこの連立方程式を解けばよいだけですね。
この連立方程式は行列で表記できます。
(6901200)=(3425)(xy)
この例だけでは行列表記したところであまりありがたみが感じられませんね。
もうひとつ例題を出してみます。
プリンを1個とヨーグルトを2個のセットAがあります。
プリンを2個とヨーグルトを3個のセットBがあります。
セットAを2個とセットBを1個買ったら960円でした。
セットAを2個とセットBを2個買ったら1400円でした。
プリンとヨーグルトはそれぞれ何円でしょう。
セットの値段に割引はないものとします。
今回は連立方程式を二段階に立てる必要があります。
プリンの値段をx円、ヨーグルトの値段をy円とします。
セットAの値段をx′円、セットBの値段をy′円とします。
すると次のような式がたてられます。
{x′=1x+2yy′=2x+3y
{960=2x′+1y′1400=2x′+2y′
これを行列を使って表記してみましょう。
(x′y′)=(1223)(xy)
(9601400)=(2212)(x′y′)
1つ目の式の(x′y′)を2つ目の式に代入してみましょう。
(9601400)=(2212)((1223)(xy))
結合法則が成り立つので前の行列の積の部分から掛け算ができますね。
(9601400)=(2212)(1223)(xy)=(2⋅1+1⋅22⋅2+1⋅22⋅2+1⋅32⋅2+2⋅3)(xy)=(46710)(xy)
二段階の連立方程式が2個の行列の積で簡潔に表記できました。
これが行列の掛け算の強みです。
今回はまだ2段階でしたが、3段階4段階と連立方程式が連なっていく場合、
行列で表記したほうが簡潔でわかりやすい表記ができます。
連立方程式がそんなに何個も連なることは滅多にないだろうと思われるかもしれませんが、
3DCGを扱っていると頻繁にでてきます。
それについてはこれからの説明で分かると思います。
行列の利点として、行列の計算はGPUで高速に行えるというのもあります。
行列はGPU上で大量の頂点の座標変換を行うのに適した形ということですね。
計算の仕方がややこしくて覚えられない人も気にすることはありません。
計算は全部コンピュータがやってくれます。
行列と座標変換
行列の計算についてはいったんおいて3DCGのモデルについて説明をします。
モデルの頂点座標はモデルの原点からの相対座標で保持されています。
このモデルの原点からの相対座標のことをローカル座標と呼ぶことがあります。
Unityなどでモデルを特定の座標に配置したり拡大縮小や回転などを行うことがあります。
上の立方体のモデルを特定の座標に配置したり拡大縮小や回転を行う場合を
考えてみましょう。
立方体のモデルを(2,2,0)の位置に配置した場合、
各頂点の座標は(2,2,0)だけ足されたものになります。
この配置したあとの座標をワールド座標とよんだりグローバル座標と呼んだりします。
立方体のモデルを2倍に拡大した場合、
各頂点のローカル座標を2倍したものになります。
立方体のモデルをy軸中心に45度回転した場合、
次の図のようになります。
立方体を1/2倍して(2,2,0)に設置した場合は
次の図のようになります。
これらの例のようなモデルの平行移動と回転、拡大縮小を行うものを
モデル変換と呼びます。
ローカル座標とをモデル変換することでワールド座標に変換されます。
これらの座標変換は行列で簡単に表せます。
説明を簡単にするために2次元で説明をしていきます。
今回は次の正方形のモデルを使って説明していきます。
まず最初に拡大縮小について考えてみましょう。
正方形のモデルを原点中心に2倍に拡大することを考えてみます。
モデルのローカル座標(x,y)を2倍拡大する変換によって(x′,y′)に変換したとすると、
次のような連立方程式がたてられます。
{x′=2xy′=2y
すべての頂点がきちんとこの連立方程式のとおりになっていることが分かります。
この連立方程式を行列に直すと次のようになります。
(x′y′)=(2002)(xy)
次に正方形のモデルを原点中心にx方向に2倍、
y方向に21倍することを考えてみます。
モデルのローカル座標(x,y)をx方向に2倍、y方向に21拡大する変換によって
(x′,y′)に変換したとすると、次のような連立方程式がたてられます。
{x′=2xy′=21y
この連立方程式を行列に直すと次のようになります。
(x′y′)=(20021)(xy)
一般に原点中心にx方向にSx倍、y方向にSy倍する拡大縮小は次のように表現できます。
(x′y′)=(Sx00Sy)(xy)
次に原点中心の回転について考えます。
正方形のモデルを30度回転した場合を考えてみます。
次の図でOP=rとします。
OPとx軸のなす角が4πなので次の式がたてられます。
x=rcos(4π),y=rsin(4π)
またOQから次の式が得られます。
{x′=rcos(4π+6π)y′=rsin(4π+6π)
加法定理を利用すると次のように変形できます。
{x′=r(cos(4π)cos(6π)−sin(4π)sin(6π))y′=r(sin(4π)cos(6π)+cos(4π)sin(6π))
ここにx=rcos(4π),y=rsin(4π)を代入すると
連立方程式はこのようになります。
{x′=cos(6π)x−sin(6π)yy′=sin(6π)x+cos(6π)y
この連立方程式を行列に直すと次のようになります。
(x′y′)=(cos(6π)sin(6π)−sin(6π)cos(6π))(xy)
一般にθだけ回転する変換を考えてみます。
OPとx軸のなす角をαとします。
すると次の式がたてられます。
x=rcosα,y=rsinα
またOQから次の式が得られます。
{x′=rcos(α+θ)y′=rsin(α+θ)
加法定理を利用すると次のように変形できます。
{x′=r(cosαcosθ−sinαsinθ)y′=r(sinαcosθ+cosαsinθ)
ここにx=rcosα,y=rsinαを代入すると
連立方程式はこのようになります。
{x′=xcosθ−ysinθy′=xsinθ+ycosθ
これを行列になおすと次のようになります。
(x′y′)=(cosθsinθ−sinθcosθ)(xy)
最後に平行移動について考えてみます。
これはちょっと曲者です。
正方形のモデルをx方向に1、y方向に2動かした場合を考えてみましょう。
この場合の連立方程式は次のようになります。
{x′=x+1y′=y+2
この連立方程式は、2×2の行列では表現できません。
そこで同次座標というのを導入します。
同次座標というのは大雑把にいうと要素を一個足したベクトルです。
(1,2)は(1,2,1)の様に最後に1を足して表現します。
同次座標はひとつの座標に対して複数の表現があります。
(1,2,1)と(2,4,2)、(3,6,3)などはすべて等しい座標を表現しています。
ちょうど分数と同じですね。
21は42、63も同じものであるのと同様です。
最後の付け加えた要素が分数の分母にあたるものとなっています。
通常は1を付け加えます。
同次座標を使ってこの平行移動を表すと次のようになります。
⎝⎜⎛x′y′1⎠⎟⎞=⎝⎜⎛100010121⎠⎟⎞⎝⎜⎛xy1⎠⎟⎞
一般にx方向にTx、y方向にTyだけ平行移動する場合、次のような行列で表現できます。
⎝⎜⎛x′y′1⎠⎟⎞=⎝⎜⎛100010TxTy1⎠⎟⎞⎝⎜⎛xy1⎠⎟⎞
拡大縮小と回転についても同次座標系に拡張してみます。
拡大縮小は次のとおり。
⎝⎜⎛x′y′1⎠⎟⎞=⎝⎜⎛Sx000Sy0001⎠⎟⎞⎝⎜⎛xy1⎠⎟⎞
回転は次のとおりです。
⎝⎜⎛x′y′1⎠⎟⎞=⎝⎜⎛cosθsinθ0−sinθcosθ0001⎠⎟⎞⎝⎜⎛xy1⎠⎟⎞
左上の2×2成分がそのまんまですね。
複数の要素を組み合わせたモデル変換について考えてみましょう。
ここらへんから行列の威力が発揮されてきます。
2倍拡大してx方向に2、y方向に2平行移動する変換を考えてみます。
(x,y)を2倍に拡大して(x′,y′)に写し、
その(x′,y′)を平行移動して(x′′,y′′)に写したものと考えます。
まず最初に2倍に拡大するのは次のような式で表現できます。
⎝⎜⎛x′y′1⎠⎟⎞=⎝⎜⎛200020001⎠⎟⎞⎝⎜⎛xy1⎠⎟⎞
次に平行移動については次のように表現できますね。
⎝⎜⎛x′′y′′1⎠⎟⎞=⎝⎜⎛100010221⎠⎟⎞⎝⎜⎛x′y′1⎠⎟⎞
この2つの式をまとめると次のようになります。
⎝⎜⎛x′′y′′1⎠⎟⎞=⎝⎜⎛100010221⎠⎟⎞⎝⎜⎛200020001⎠⎟⎞⎝⎜⎛xy1⎠⎟⎞
この式で2倍拡大してから平行移動している式になっています。
拡大縮小が原点中心なので、拡大縮小をしてから平行移動していることに注意です。
順番を逆にすることはできません。
行列の掛け算で変換を順番に行っていくのがそのまま式に表現できますね。
次に21倍拡大し、30度回転してx方向に2、
y方向に−2平行移動する変換を考えてみます。
これも行列の積を使えば次のような式で表せます。
⎝⎜⎛x′y′1⎠⎟⎞=⎝⎜⎛1000102−21⎠⎟⎞⎝⎜⎛cos6πsin6π0−sin6πcos6π0001⎠⎟⎞⎝⎜⎛21000210001⎠⎟⎞⎝⎜⎛xy1⎠⎟⎞
行列の積で連立方程式を表現する強みがわかってきたのではないでしょうか。
行列の計算自体はプログラムでコンピュータに任せられます。
面倒な計算自体はしなくても最初の式さえたてられれば問題ありません。
そう考えるととても便利なことが分かるでしょう。
次にもっと複雑な例で斜め45度方向に拡大する変換を考えてみます。
単純な拡大縮小ではx方向かy方向にしか拡大できません。
この場合はいったん逆方向に45度回転してからx方向に拡大し、その後45度回転してもとに戻します。
式にすると次のとおりです。
⎝⎜⎛x′y′1⎠⎟⎞=⎝⎜⎛cos4πsin4π0−sin4πcos4π0001⎠⎟⎞⎝⎜⎛Sx00010001⎠⎟⎞⎝⎜⎛cos(−4π)sin(−4π)0−sin(−4π)cos(−4π)0001⎠⎟⎞⎝⎜⎛xy1⎠⎟⎞
行列を使わないと複雑な連立方程式になるものが、
簡単に掛け算を重ねていくことで作れるのは面白くなってきませんか?
もう一つ、例を上げておきましょう。
正方形を(1,1)中心に2倍拡大し回転する変換について考えます。
回転も拡大も原点中心にしか行なえません。
この場合はいったん平行移動して原点中心にしてから拡大と回転を行い、
その後平行移動でもとに戻します。
式にすると次のとおりです。
⎝⎜⎛x′y′1⎠⎟⎞=⎝⎜⎛100010111⎠⎟⎞⎝⎜⎛Sx000Sy0001⎠⎟⎞⎝⎜⎛cosθsinθ0−sinθcosθ0001⎠⎟⎞⎝⎜⎛100010−1−11⎠⎟⎞⎝⎜⎛xy1⎠⎟⎞
ここまで話を簡単にするために2次元で進めてきました。
ここで3次元についても考えておきましょう。
x方向にSx倍、y方向にSy倍、z方向にSz倍にする拡大行列は次のとおりです。
⎝⎜⎜⎜⎛x′y′z′1⎠⎟⎟⎟⎞=⎝⎜⎜⎜⎛Sx0000Sy0000Sz00001⎠⎟⎟⎟⎞⎝⎜⎜⎜⎛xyz1⎠⎟⎟⎟⎞
次は回転について考えてみます。
x軸を中心にθ度回転させる回転行列は次のとおりです。
⎝⎜⎜⎜⎛x′y′z′1⎠⎟⎟⎟⎞=⎝⎜⎜⎜⎛10000cosθsinθ00−sinθcosθ00001⎠⎟⎟⎟⎞⎝⎜⎜⎜⎛xyz1⎠⎟⎟⎟⎞
y軸を中心にθ度回転させる回転行列は次のとおりです。
⎝⎜⎜⎜⎛x′y′z′1⎠⎟⎟⎟⎞=⎝⎜⎜⎜⎛cosθ0−sinθ00100sinθ0cosθ00001⎠⎟⎟⎟⎞⎝⎜⎜⎜⎛xyz1⎠⎟⎟⎟⎞
z軸を中心にθ度回転させる回転行列は次のとおりです。
⎝⎜⎜⎜⎛x′y′z′1⎠⎟⎟⎟⎞=⎝⎜⎜⎜⎛cosθsinθ00−sinθcosθ0000100001⎠⎟⎟⎟⎞⎝⎜⎜⎜⎛xyz1⎠⎟⎟⎟⎞
最後に平行移動について考えてみます。
x軸方向にTx、y軸方向にTy、
z軸方向にTzだけ平行移動する拡大行列は次のとおりです。
⎝⎜⎜⎜⎛x′y′z′1⎠⎟⎟⎟⎞=⎝⎜⎜⎜⎛100001000010TxTyTz1⎠⎟⎟⎟⎞⎝⎜⎜⎜⎛xyz1⎠⎟⎟⎟⎞
3次元の場合もこれらの行列の積によって複雑な変換を表現できます。
Model行列
ここで改めてモデル変換について考えます。
モデル変換はモデルのローカル座標をワールド座標に変換するものです。
モデルのx軸y軸z軸方向の拡大縮小と回転、そして平行移動について考えます。
ちょうどUnityのTransformで行える変換ですね。
これは次のような行列で表せます。
⎝⎜⎜⎜⎛100001000010TxTyTz1⎠⎟⎟⎟⎞⎝⎜⎜⎜⎛R11R21R310R12R22R320R13R23R3300001⎠⎟⎟⎟⎞⎝⎜⎜⎜⎛Sx0000Sy0000Sz00001⎠⎟⎟⎟⎞
これを計算した結果の次の行列について考えます。
⎝⎜⎜⎜⎛m11m21m310m12m22m320m13m23m330TxTyTz1⎠⎟⎟⎟⎞
左上の3×3成分が拡大縮小と回転を表していて、
右側の(Tx,Ty,Tz)が平行移動成分になっています。
4行目は(0,0,0,1)で固定になります。
この行列でモデルのローカル座標からワールド座標に変換できることがわかりました。
このモデル変換を行う行列のことをモデル行列と呼んだりします。
Unityではシェーダ内でunity_ObjectToWorld
という変数でこの行列にアクセスできます。
オブジェクトのローカル座標からワールド座標に変換するということで
こういう名前がついています。
View行列
モデル変換によってモデルのローカルの座標からワールド座標に変換できました。
しかし、ワールド座標のままレンダリングは行なえません。
3DCGをレンダリングする際にはカメラから見てどこに頂点があるかというのが重要になります。
このカメラから見た相対座標のことをカメラ座標といったりアイ・スペースと呼んだりします。
このカメラからみた相対座標を求めるために、ワールド座標からカメラ座標に変換するのが
ビュー変換となります。
ビュー変換は、カメラの位置と回転が与えられたときに、
それと逆方向の変換になります。
説明を簡略化するために2次元で説明します。
カメラがz方向にTz、y方向にTy平行移動したときについて考えてみます。
この場合、カメラ座標はワールド全体をz方向に−Tz、
y方向にTy平行移動したものになります。
カメラの変換と逆方向に動かしてカメラを原点に持っていくことで
ワールド座標からカメラ座標を求められるということですね。
カメラをθ回転させた場合を考えてみます。
これもワールド全体にカメラの変換を戻す変換をかけることで
ワールド座標からカメラ座標を求められます。
カメラがθ回転し(Ty,Tz)移動した場合についても考えてみます。
この場合も同様に逆方向の変換をワールド全体にかけてあげればよいことになります。
カメラの変換には拡大縮小は考えません。
カメラの回転と位置の逆方向の変換がビュー変換となります。
回転と平行移動が行列で表現できることは説明しました。
ビュー変換を表現する行列のことをビュー行列と呼びます。
Unityのシェーダ内ではUNITY_MATRIX_V
というビュー行列を取得できます。
Projection行列
MVP行列の最後の要素はProjection行列です。
Projection行列はいわゆるパースを扱うものになります。
最初にパースのかかった投影について軽く説明をします。
絵を描くにも3DCGを表示するにも3次元の物体を2次元に落とし込む作業が必要になります。
この3次元を2次元に落とし込む方法のことを投影といいます。
主だった投影方法には、透視投影と平行投影の2種類があります。
ここでは透視投影について説明をします。
透視投影のわかりやすい例はピンホールカメラです。
大きさを無視できるピンホールを使うことで、光の直進性により投影面に像ができます。
この像は近くのものは大きく遠くのものは小さく写ります。
ピンホールを通る光の量が少ないので、実際の撮影を行うカメラでは
ピンホールの代わりにレンズを用いて像を作ります。
3DCGの投影の計算においては
ピンホールの位置を目やカメラの位置(視点)とし、
視点より前に投影面を置きます。
ピンホールカメラでは投影面は視点より後ろでしたが、
これだと像が上下左右逆になって扱いにくいため
3DCGで投影の計算を行う際には投影面は視点の前に置きます。
平面z=1を投影面としたときのyz座標の図は次のようになります。
三角形の頂点PはQに投影されます。
Pのyz座標を(y,z)、Qのyz座標を(y′,1)とすると、
三角形の相似からy:z=y′:1となります。
x座標についても同様なので、投影面上の点(x′,y′)は次のようになります。
{x′=zxy′=zy
実際に投影の計算をする際には、投影面上に長方形を考え、
その範囲に投影される図形のみを描きます。
この長方形をウィンドウといいます。
ウィンドウの大きさに合わせて視点からウィンドウをカバーする角度である画角を考えます。
画角が小さいと狭い範囲しか描画されません。
画角が大きくなると広い範囲が描画され遠近感が強調されます。
3DCGにおける透視投影はレンズの近くのものから無限遠まで描画することはなく、
前後にクリッピングした視錐台と呼ばれる領域の内部のもののみを描画します。
前後にクリッピングした面のうち視点に近いものを前方クリッピング面とよび、
視点から遠いものを後方クリッピング面とよびます。
3DCGではラスタライザに渡された頂点座標を平面x=±1、y=±1、z=0、z=1で
囲まれた直方体でクリッピングして、その範囲のものだけを表示します。
この直方体の範囲がクリッピングされ描画される範囲になります。
Projection変換はさきほどの視錐台をクリッピングの直方体に押し込む変換だといえます。
押し込んだあとの座標系を投影座標系と呼びます。
このProjection変換は、ビューボリュームの正規化する変換と
正規化ビューボリュームを透視投影する変換を行います。
ビューボリュームの正規化は、後方クリッピング面がz=1に、z=1でのx、yの範囲がちょうど
−1≤x≤1、−1≤y≤1になるように
もとのビューボリュームを拡大・縮小するものです。
ウィンドウの横幅が2aでウィンドウの縦幅が2bのとき、
ビューボリュームを正規化する変換を行列で表すと次のようになります。
⎝⎜⎜⎜⎛X′Y′Z′1⎠⎟⎟⎟⎞=⎝⎜⎜⎜⎛azmax10000bzmax10000zmax100001⎠⎟⎟⎟⎞⎝⎜⎜⎜⎛xyz1⎠⎟⎟⎟⎞
次に正規化ビューボリュームを透視投影する変換を考えます。
z~min=zmaxzminと置くと
透視投影の行列は次のようになります。
⎝⎜⎜⎜⎛X′Y′Z′W′⎠⎟⎟⎟⎞=⎝⎜⎜⎜⎛10000100001−z~min1100−1−z~minz~min1⎠⎟⎟⎟⎞⎝⎜⎜⎜⎛xyz1⎠⎟⎟⎟⎞
x′とy′についてはちゃんとzで除算されていることが確認できます。
{x′=W′X′=zxy′=W′Y′=zy
z′の値は次のようになります。
z′=W′Z′=(1−z~min1z−1−z~minz~min)z1=1−z~min1−1−z~minz~minz1
z=z~nearでz′=0に、z=1でz′=1になることが確認できます。
ビューボリュームの正規化と透視投影を行う行列を合わせた
Projection変換を行う行列をProjection行列と呼びます。
Unityではシェーダ内でUNITY_MATRIX_P
という変数で受け取ることができます。
MVP行列
MVP行列と呼ばれるものはModel行列、View行列、Projection行列をかけ合わせたものです。
MVP=P∗V∗M
モデル行列はモデルのローカル座標をワールド座標に変換するものでした。
ビュー行列はワールド座標をカメラから見た相対座標であるカメラ座標に変換するものでした。
プロジェクション行列はカメラ座標を投影座標に変換するものでした。
頂点シェーダ内でモデル座標から投影座標系に変換し、
ラスタライザでクリッピング座標のx=±1、y=±1、z=0、z=1の直方体の範囲内のものを
ラスタライズし、フラグメントシェーダに渡します。
頂点シェーダ内で入力された頂点座標にMVPを掛けて次のステージに渡すのは
このクリッピングの座標変換を行っていたのでした。
UnityのShader内ではMVP行列はUNITY_MATRIX_MVP
という変数で受け取れます。
頂点シェーダ内にmul(UNITY_MATRIX_MVP, v)
と記述すると、
Shaderファイルを保存した際にUnityObjectToClipPos(v)
と直されます。
UnityObjectToClipPos(v)
はmul(UNITY_MATRIX_MVP, v)
より効率がよいので
修正されるようですが、やっていることは同じことです。
これで前回の記事で解説を飛ばした頂点シェーダ内のプログラムについて解説ができました。
おわりに
今回は前回の記事の頂点シェーダ内で行っていた座標変換について解説しました。
わかりにくいところや間違いなどがあれば私のTwitterアカウント(@MatchaChoco010)まで連絡をお願いします。