スキャンラインを使用したZバッファーの深度補間


10

私は独自のソフトウェア3dラスタライザを作成する必要があります。これまでのところ、三角形で作られた3dモデルを2d空間に投影できます。

ポイントを回転、移動、投影して、各三角形の2D空間表現を取得します。次に、3つの三角形のポイントを取り、スキャンラインアルゴリズムを実装して(線形補間を使用)、三角形のエッジ(左と右)に沿ってすべてのポイント[x] [y]を見つけて、三角形を水平にスキャンできるようにします。行ごとに、ピクセルで塗りつぶします。

これは機能します。ただし、zバッファリングも実装する必要があります。これは、三角形の3つの頂点の回転および変換されたz座標がわかっているため、スキャンラインアルゴリズムで見つけた他のすべての点のz座標を補間する必要があることを意味します。

概念は十分にはっきりしているように見えます。私はまずこれらの計算でZaとZbを見つけます。

var Z_Slope = (bottom_point_z - top_point_z) / (bottom_point_y - top_point_y);
var Za = top_point_z + ((current_point_y - top_point_y) * Z_Slope);

次に、各Zpに対して水平方向に同じ補間を行います。

var Z_Slope = (right_z - left_z) / (right_x - left_x);
var Zp = left_z + ((current_point_x - left_x) * Z_Slope);

ここに画像の説明を入力してください

そして、現在のzがそのインデックスで以前のzよりもビューアに近い場合は、カラーをカラーバッファに書き込み、新しいzをzバッファに書き込みます。(私の座標系はx:左->右、y:上->下、z:あなたの顔->コンピュータ画面です;)

問題は、それが問題になることです。プロジェクトがここにあり、「Z-Buffered」ラジオボタンを選択すると、結果が表示されます(「Z-Buffered」モードでは、ペインターのアルゴリズム(ワイヤフレームを描画する場合のみ)を使用していることに注意してください)デバッグ用

PS:補間する前にzを逆数(つまり)に変換する必要があることをここで読みましz = 1/z。試してみましたが、変化はないようです。何が欠けていますか?(正確にどこをzを1 / zに変換する必要があるか、どこに(もしそれを)元に戻すには?)

[編集]ここに、私が得たzの最大値と最小値に関するデータがあります。

    max z: 1;                  min z: -1;                 //<-- obvious, original z of the vertices of the triangles
    max z: 7.197753398761272;  min z: 3.791703256899924;   //<-- z of the points that were drawn to screen (you know, after rotation, translation), by the scanline with zbuffer, gotten with interpolation but not 1/z.
    max z: 0.2649908532179404; min z: 0.13849507306889008;//<-- same as above except I interpolated 1/z instead of z.
//yes, I am aware that changing z to 1/z means flipping the comparison in the zBuffer check. otherwise nothing gets drawn.

綿密なデバッグに入る前に、誰かが私のこれまでの概念が正しいことを確認できますか?

[編集2]

Zバッファリングを解決しました。結局のところ、描画順序はまったく混乱していません。z座標が正しく計算されていました。

問題は、フレームレートを上げるために、画面上の実際のピクセルではなく、4ピクセルごとに4px / 4pxのボックスを描画していたことです。したがって、ピクセルあたり16pxを描画していましたが、zバッファーをチェックして、そのうちの1つだけを確認しました。私はそのようなおっぱいです。

TL / DR:問題はまだ残っています:Zの代わりにZの逆数(1 / zのように)をどのように/なぜ/いつ使用する必要がありますか?現在、すべてがどちらの方法でも機能するためです。(目立った違いはありません)。


Re:「もちろん、現在のzがそのインデックスの以前の値よりもビューアに近い場合は、zBufferに追加します。」どのように意図していたのか、しかしその意味が「現在のzがそのインデックスで前のzよりもビューアに近い場合は、カラーバッファにカラーを書き込み、そしてzバッファへの新しいz」zバッファの目的は、そのピクセルの色が既にカメラの目の近くに書き込まれている場合に、色の書き込みをブロックすることです。
Alturis、2012年

それは正しいです。申し訳ありませんが、質問をするのが遅くなりました。改定します。
Spectraljump、2012年

回答:


5

簡単な答え:Zは(X '、Y')の線形関数ではありませんが、1 / Zは線形関数です。線形に内挿するため、1 / Zでは正しい結果が得られますが、Zでは得られません。

Z1とZ2の比較が正しい限り、両方の値が間違っていても、zbufferは正しい動作をするため、気付かないでしょう。テクスチャマッピングを追加すると、確実に気付くでしょう(そして、次の質問に答えるために、1 / Z、U / Z、V / Zを補間し、これらの値からUとVを再構築します:U =(U / Z) /(1 / Z)、V =(V / Z)/(1 / Z。後で感謝します)

例。一枚の紙を入手してください。トップダウンビューなので、Y座標は忘れてください。Xは水平軸、Zは垂直軸、カメラは(0、0)にあり、投影面はz = 1です。

点A(-2、2)とB(2、4)を考えます。線分ABの中点Mは(0、3)です。ここまでは順調ですね。

AをA 'に投影します。X' = X / Z = -1なので、A 'は(-1、1)です。同様に、B 'は(0.5、1)です。ただし、Mの射影は(0、1)であり、A'B 'の中点ではないことに注意してください。どうして?セグメントの右半分が左半分よりもカメラから離れているため、小さく見えるからです。

では、線形補間を使用してM 'のZを計算しようとするとどうなりますか?dx =(0.5--1)= 1.5、dz =(4-2)= 2なので、M 'がX' = 0の場合、線形補間されたZはzA +(dz / dx)(x-xA)= 2 +(2 / 1.5)(0--1)= 2 + 1.333 = 3.3333-3ではありません!

どうして?X '方向のすべてのステップで、Z方向に同じ量を移動しないためです(つまり、ZはX'の線形関数ではありません)。どうして?右に行くほど、セグメントはカメラから離れているため、1ピクセルは空間内のより長い距離を表します。

最後に、代わりに1 / Zを補間するとどうなりますか?まず、AとBで1 / Zを計算します。それぞれ0.5と0.25です。次に、内挿します:dx =(0.5--1)= 1.5、dz =(0.25-0.5)= -0.25、X '= 0では、1 / Z = 0.5 +(-0.25 / 1.5)*(0- -1)= 0.3333。しかし、それは1 / Zなので、Zの値は...正確に、3です。

ええ、数学は素晴らしいです。


1
ああ、「いつ」に関して:三角形のラスタライズを開始する前に(たとえば、垂直ループの直前)1 / Z値を計算して、スキャンラインの左と右で1 / Zを補間します。これらを線形に補間し(再度1 / Zを行わないでください-補間された値はすでに1 / Zです!)、zbufferをチェックする直前に変換を元に戻します。
ggambett 2012年

1
そして最後に、その理由。平面(三角形が埋め込まれている)はAx + By + Cz + D = 0です。zは明らかに(x、y)の線形関数です。x '= x / zおよびy' = y / zと投影します。そこから、x = x'zおよびy = y'zです。これらを元の方程式で置き換えると、Ax'z + By'x + Cz + D = 0になります。今度はz = -D /(Ax '+ By' + C)で、zは線形関数ではないことがわかります。の(x '、y')。ただし、1 / zは(Ax '+ By' + C)/ -Dであり、(x '、y')の一次関数です。
ggambett 2012年

1
ご存知のように、私はかなりの数の記事とコースを読みましたが、どれもあなたの答えほど明確ではありませんでした。後世のために、「X」、「Y」、「Z」はモデル内の3Dオブジェクトの軸を表すためにすでに使用されているため、「文字「U」と「V」は2Dテクスチャの軸を表すことにも注意してください。空間。UVテクスチャリングを使用すると、3Dオブジェクトを構成するポリゴンを画像の色でペイントできます。」-ウィキペディア-UVマッピング
Spectraljump、

それを聞いてうれしい。実際、私は前の人生でコンピューターグラフィックスを教えました:)
ggambett

どうもありがとう-私はいつもこれに興味を持っていました-そして、私がこれまでより良い答えを見つけたかどうかはわかりません!+1
Codesmith
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.