Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
宇治社中 〜パースペクティブコレクト〜
[go: Go Back, main page]


パ−スペクティブコレクト

副題:線形ということ


■流れるテクスチャ

前回テクスチャを貼る準備まで辿り着きました。擬似床描画の第二回目になります。

まず、テクスチャを貼るということから考えます。画面上のある点を描画する際に、描画対象となるポリゴン上の点の位置情報よりテクスチャ上の対応座標を求め、テクスチャ上の該当色を用いて画面上の描画色とすることですね。ここまでの文脈の中で、異なる座標系が三種類出てきました。

最初は「画面上の座標」、次は「ポリゴン上の座標」、最後は「テクスチャ上の座標」です。画面上の座標が線形に変化していく間に、ポリゴン上の座標、ついでテクスチャ上の座標が変化していくことになります。こうして画面上の該当範囲を塗りつぶしてゆけばテクスチャの貼られたポリゴンの描画が完了します。

いちいちテクスチャの座標を再計算するわけにもいかないので、大抵補間して間を埋めていくことになります。まずシンプルに思い付く方法が線形補間ですね。描画開始時のテクスチャ座標と描画終了時のテクスチャ座標を線形補間する。ところが単純にこうしてしまうと、正しく描画されなくなってしまいます。

例えばDOOM型のゲームやなんかで、眼に近い壁のテクスチャが妙に引き伸ばされた状態を見たことはありませんか?この引き伸ばされる、別の表現でいえば「流れる」現象が、先に述べた線形補間での不具合なのです。

では、どうすれば正しく描画できるのでしょうか。少し計算式で見て行きましょう。

■線形ということ

まず、線形という事の定義を書いて見ましょう。今は3Dでの話をしているので、3D空間内で線形である状態を書いてみます。

ix + jy + kz + l = m

これが、「線形である(変化の速度が一定である)」という式です。関係式をごちゃごちゃひねくり回して、この形になったら、線形という関係が成り立っているという事になります。

次に3D空間内での平面の定義を書いてみましょう。実は、ほぼ同じ式です。

Ax + By + Cz = D

これが平面の定義です。これより平面上での点の変化は線形であるということがいえますね。ここで、透視投影変換の式から、画面上の点とカメラ座標系上の点との関係式を書いてみましょう。カメラ座標系でのzでxとyを割って投影していたので、

X = x/z
Y = y/z

の関係式が導き出されます。ここでXとYが画面上の点となります。この関係式を先程の平面の定義にぶち込みます。

AXz + BYz + Cz = D

zだけくくると、

(A/D)X + (B/D)Y + (C/D) = 1/z

さて、この式が線形の関係を為していることから、画面上の位置とカメラ座標系での1/zとが線形の関係を為していると言えます。いわば反比例の状態にあることがわかります。これで「画面上」と「ポリゴン上」の関係が分かりました。まぁここまでは当たり前です。次は「テクスチャ上」の関係を見てみましょう。

■テクスチャ座標との関係は?

テクスチャ座標のuvはポリゴンのxyzより一意に決まります。これを関係式にすると、

u = ax + by + cz + d
v = ex + fy + gz + h

こうなります。さっそく画面座標との関係式を放り込むと、

u = aXz + bYz + cz + d
v = eXz + fYz + gz + h

または、

u/z = aX + bY + c + d/z
v/z = eX + fY + g + h/z

ここで、両辺にzが現れるのが癪なので、右辺の1/zに画面とポリゴンの関係で求めた式を代入します。

u/z = aX + bY + c + d( (A/D)X + (B/D)Y + (C/D) )
v/z = eX + fY + g + h( (A/D)X + (B/D)Y + (C/D) )

まとめると、

u/z = (a + d(A/D))X + (b + d(B/D))Y + (c + d(C/D))
v/z = (e + h(A/D))X + (f + h(B/D))Y + (g + h(C/D))

こうなって、見事に線形の関係が導き出されます。「画面上」と「ポリゴン上」との関係は、u/zやv/zと線形ということになります。

ネタばらしをすると、ここまでの証明は、Mikael Kalms氏の3DReviewより引用しました。加えて原典にはコーディングに関するテクニックも説明されています。是非当たって見てください。

■で、どうするの?

コーディングする際に、uやvを線形に補間していたからおかしくなっていたんですね。実際に線形なのはu/zやv/zなので、不具合が生じていたのです。先程は「眼に近い壁」という表現を使いましたが正確には「視線方向との角度の差が少ない平面」つまり眼に突き刺さるように存在している面ほど、不具合の影響が大きくなります。もちろん、画面上変位あたりのzの変化量が大きいからですね。

ということで、画面上のドットを進める毎に、1/zを線形補間し逆数であるzを算出し、同じく線形補間したu/zやv/zに掛けて、uやvを求め、テクスチャ上の色を拾ってドット描画すれば良いのです……。とはいうものの、割り算一回に掛け算二回を毎ドット繰り返すのは大変そうです。これが、今でも流れるテクスチャを見かける理由の一つです。重いですから。

よく見られる解決策の一つとして、毎ドットではなく数ドット毎に正確な値を算出し、それ以外では線形補間で埋めるという方法があります。これはなかなか頭のいい方法です。計算間隔を狭めると精度が増し、広げると精度が落ちるという操作が可能だからです。試した訳で無いので分かりませんが、視線との角度によって間隔を変える、つまり、流れやすいポリゴンは細かめに計算し、流れそうもないポリゴンは荒く計算するという手加減が出来そうです。

今何気なく使った「流れそうも無いポリゴン」とはどういう事でしょうか?簡単なことです。眼からの距離zが常に一定のポリゴン、真正面ポリゴンの事です。これなら何も気を遣わなくても線形ですね。でも、そんなこと滅多にありません。

話はいきなり前回に戻ります。前回の擬似床の項でバンクしないでくれという理由の所で2点ほど挙げておいた事を思い出してみましょう。「水平線が常に水平」ということと「スキャンライン上では視点からのZ距離が一定」という理由でした。この2つめの理由が重要な意味を持ってくるのです。

そうです。画面上を横切っている間は眼からのzが変化しないのです。つまり、ここまで述べてきた1/zやu/zやv/z等のややこしい、しかし正確な計算はスキャンラインごとに一度やれば済むということになります。

今回描画する擬似床もこういう利点があるのでバンク禁止にしてきたわけです。バンクしないカメラにも深い(?)訳があったんですね。

■納得した?

実装は次回のサンプルを参照していただくことにします。今回のような作戦は、パースペクティブコレクトテクスチャマッピング(Perspective Correct Texture Mapping)と呼ばれるものです。また、数ドット飛ばしの作戦は、スキャンラインサブディブジョン(Scanline Subdivision)等と呼ばれているみたいです。さらなる高みを目指す方は、これらの言葉で検索してみるのもいいんではないでしょうか。


<戻る>

devilman/team-UJI 1998/08/13