ホーム < ゲームつくろー! < DirectX技術編
その55 そもそも「w」って何なのか?
ローカル座標にある頂点は(x,y,z,w)という4次元のベクトルで定義されます。「w」・・・これ、謎な存在です。しかも、ローカル座標にある状態では、w=1とします。w=1・・・なぜ?どうして0じゃないの?そもそもコレ何?何に使われているの?どうして必要なの?謎な存在の疑問は尽きません。
そこで、この章ではそんな不思議な存在wの値の意義について調べてみたいと思います。
@ wの変化の旅を見てみよう
wが実際にどう作用しているのか、実際にローカルから画面に描画されるまでのプロセスで確かめてみるとよ〜〜くわかります。長い旅に出発です。
まず、ローカル座標にある頂点は、冒頭で出てきたように(x,y,z,w=1)で定義されます。今、この頂点にワールド変換行列を掛け算してみます:
行列中の「m」というのはスケールと回転の要素を含む部分です。この部分だけですと、ローカル空間にある頂点は原点を中心とした回転かスケール変化しかできません。つまり、これだけですとキャラクタは原点でジタバタしてしまうわけです。しかし、w成分があると話は違います。掛け算の結果を見ると「1*Ofs」という部分がw=1とする事によって加えられているのがわかります。ここは「平行移動成分」、つまりワールド空間の好きな位置に移動できる要素になっています。
ローカル座標でw=1とするのは、もうお分かりのように、ワールド空間で平行移動をしたいがために設定されている部分なんです。これがあって初めて、キャラクタはワールド空間内を動き回ることができる(アフィン変換ができる)んです!w=1はとっても大切な設定値なんですね。
さて、ワールド空間に移動した頂点の座標のw成分は相変わらず1です。次に、この頂点にビュー行列を掛け算します・・・なんですが、ビュー行列というのは頂点をカメラの前に持ってくる「変換行列」に過ぎません。要は上と同じような成分構成の行列になっているので、結果は単純に、
となります。未だwは1のままです。
ここからが本番です。続いてこのビュー空間にある頂点に射影変換行列を掛け算します。この射影変換行列が非常に肝となりますので、詳しく説明します。射影変換行列は次のように定義されています:
これは先ほどまでのワールド変換行列などとは様子が違います。成分中のSwやShはスクリーンの幅と高さを表しています。これは実は近平面のサイズと同じと定義されています。
Znは近平面までの距離です。Qというのはビュー空間にある頂点のZ成分に対するスケールです。どういうスケール値になるのかは後述します。_43成分の-QZnはZ軸方向へのオフセットですね。そして突出しているのが_34成分の「1」。これが肝です。
このまま各成分を眺めていても、何をしたいのかちっとも良くわからないと思いますので、先ほどのビュー空間にある頂点Pviewにこの行列を実際に掛け算してみましょう:
複雑そうな感じになりましたが怖くありません。これが何を意味するかを考えるため、例えば、(Xview,
Yview, Zview)=(-Sw/2, -Sh/2, Zn)というビュー空間内の1つの座標を代入してみましょう。ちなみに、この座標は近平面の左下の点です:
XY成分それぞれが-Zn、そしてZが0。何となく近平面の左下と結果がシンクロしている気がしませんか?
他の点でも試してみます。今度は一番遠いところにある遠平面の左下の座標点にしてみます。遠平面までの距離をZfとすると、XY座標は次の図に示すように求められます:
ZnとZfの比率を使えば求まるわけです。この図から、Xview = -Sw/2 * Zf/Zn そしてYview
= -Sh/2 * Zf/Znであることがわかります。これをPprojの式にど〜んと代入すると、一番遠い平面の左下のPprojは、
となります。今度はXY成分が-Zfとなりました。やっぱり何となく遠平面の左下とシンクロしている気がしませんでしょうか?ただ、Z成分はこの見た目ですと何とも言えない感じです。ここはカメラから一番遠い位置にあるわけで「Zf」になって欲しいんです。そこで、Qを次のようにします:
こうするとProjは、
となります。かなり美しく揃っていますね。
そして注目の「w」。ここにはビュー空間にあった頂点のZ成分がそのまま来ています。これはPprojのw成分の式を見れば明らかですね。もうwの意味合いが見えて仕様が無い状態なんですが、このwは「視錐台の拡大率」を表しているんです!!カメラから頂点が遠ければ遠いほど、つまりZ成分がZfに近づけば近づくほどwの値はそれに比例して大きくなります。
wが視錐台の拡大率なのですから、全成分をwで割るとどうなるか?近平面及び遠平面はそれぞれこうなります:
美しい!!両方ともXY成分が同じでZが一番近い0及び一番遠い1となりました。つまり、この状態でカメラから見ると(=スクリーンに投影すると)両方の頂点は重なって見える事になります。近平面も遠平面もカメラの中にぴったり納まる平面(それが視錐台の意味合い)なので、これは理屈どおりになっていますよね。
という事で結論です。wは射影空間(視錐台空間)にある頂点座標をそれで割ることにより「頂点をスクリーンに投影するための立方体の領域(-1≦x≦1、-1≦y≦1そして0≦z≦1)に納める」という大切な役目をしています。wが「同次系」と呼ばれるのは、上の例のように視錐状にカメラの視線方向に広がっている頂点を同じXY座標に投影するためです。
A 頂点シェーダに入ってくる頂点座標とw成分の行く末
頂点シェーダにはローカル座標にある頂点がそのまま入ってきます(POSITIONセマンティクス)。スクリーンにポリゴンを投影させるために、私達はここでローカル座標の頂点にワールドビュー射影行列(WVP行列)を掛け算します。そして、それを頂点シェーダの出力頂点として出力します(POSITIONセマンティクス)。これでモデルはちゃんと画面に出ます。@で長々と述べてきたように、ローカル座標にある頂点にWVP行列を掛け算すると、wで割る前の視錐台空間内の頂点座標になります。つまり、頂点シェーダの出力頂点座標は、視錐台空間内の座標だったんです。
頂点シェーダを抜けた頂点はそこで初めてwで割り算され、スクリーンの投影位置が確定し、どの点を穿つべきか決められてピクセルシェーダに情報が伝わります。ただし、ピクセルシェーダではすでに穿つ点の情報を直接取得できなくなっています。つまり、ここでwはお役御免となるわけです。
DirectX技術編その43「Z値をテクスチャに書き込む鉄板な方法」で、自分で深度テクスチャを作ろうとする時に、頂点のZ座標をW値で割るという作業が必要だとその章のAのちょっと上辺りで示しました。これがなぜ必要か、ここまでの流れをご理解頂ければ納得して頂けると思います。不思議なw成分の正体は、スクリーンに絵を出すために必須の「拡大率」だった。これで、もやもやも解消、すっきり寝られます(^-^)。