ZBufferはそれとは何の関係もありません。
ZBufferは、三角形が重なっていて、三角形が正しく描画されていることを確認したい場合にのみ役立ちます(たとえば、Zで正しく順序付けられている)。ZBufferは、三角形のすべてのピクセルについて、以前に配置されたピクセルがカメラに近いかどうかを判断し、近い場合は、三角形のピクセルを描画しません。
重ならない2つの三角形を描いているので、これが問題になることはありません。
固定小数点でソフトウェアラスタライザーを一度作成しましたが(携帯電話用)、ラップトップにソースがありません。それで、今夜、私がそれをどのようにしたかを確認させてください。本質的に、あなたが持っているものは悪くありません!このようなことは、非常に小さなエラーが原因である可能性があります
これをデバッグする際の一般的なヒントは、いくつかのテスト三角形(左側の傾斜、右側の傾斜、90度の角度など)を用意し、デバッガーを使用してステップスルーし、ロジックがケースをどのように処理するかを確認することです。
編集:
私のラスタライザーの疑似コード(U、V、およびZのみが考慮されます...グーローシェーディングも実行する場合は、UおよびVおよびZに対して実行するのと同様に、RGおよびBに対してもすべてを実行する必要があります。
三角形は2つの部分に分解できるという考え方です。上部と下部。上部はy[0]からy[1]で、下部はy[1]からy[2]です。両方のセットについて、補間するステップ変数を計算する必要があります。以下の例は、上部の実行方法を示しています。必要に応じて、下部も供給できます。
以下の「擬似コード」フラグメントの下部に必要な補間オフセットをすでに計算していることに注意してください。
- coords(x、y、z、u、v)を、coord [0] .y <coord [1] .y <coord[2].yの順序で最初に並べ替えます。
- 次に、2セットの座標が同一であるかどうかを確認します(xとyのみを確認します)。もしそうなら、描画しないでください
- 例外:三角形の上部は平らですか?もしそうなら、最初の勾配は無限になります
- 例外2:三角形の底は平らですか(はい、三角形もこれらを持つことができます; ^))、最後の勾配も無限になります
- 2つの勾配(左側と右側)を計算します
leftDeltaX =(x [1] --x [0])/(y [1] -y [0])およびrightDeltaX =(x [2] --x [0])/ (y [2] -y [0])
- 三角形の2番目の部分は、次の条件に従って計算されます。三角形の左側が実際に左側にあるかどうか(またはスワッピングが必要かどうか)
コードフラグメント:
if (leftDeltaX < rightDeltaX)
{
leftDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
rightDeltaX2 = rightDeltaX
leftDeltaU = (u[1]-u[0]) / (y[1]-y[0]) //for texture mapping
leftDeltaU2 = (u[2]-u[1]) / (y[2]-y[1])
leftDeltaV = (v[1]-v[0]) / (y[1]-y[0]) //for texture mapping
leftDeltaV2 = (v[2]-v[1]) / (y[2]-y[1])
leftDeltaZ = (z[1]-z[0]) / (y[1]-y[0]) //for texture mapping
leftDeltaZ2 = (z[2]-z[1]) / (y[2]-y[1])
}
else
{
swap(leftDeltaX, rightDeltaX);
leftDeltaX2 = leftDeltaX;
rightDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
leftDeltaU = (u[2]-u[0]) / (y[2]-y[0]) //for texture mapping
leftDeltaU2 = leftDeltaU
leftDeltaV = (v[2]-v[0]) / (y[2]-y[0]) //for texture mapping
leftDeltaV2 = leftDeltaV
leftDeltaZ = (z[2]-z[0]) / (y[2]-y[0]) //for texture mapping
leftDeltaZ2 = leftDeltaZ
}
- currentLeftXとcurrentRightXの両方をx[0]に設定します
- currentLeftUをleftDeltaUに、currentLeftVをleftDeltaVに、currentLeftZをleftDeltaZに設定します。
- 最初のY範囲の開始と終了を計算します。startY=ceil(y [0]); endY = ceil(y [1])
- サブピクセルの精度のためにyの小数部分のプレステップx、u、v、z(これはフロートにも必要だと思います)私の固定小数点アルゴリズムでは、ラインとテクスチャがはるかに細かいステップで移動しているような錯覚を与えるためにこれが必要でしたディスプレイの解像度)
- xがy[1]にあるべき場所を計算します:halfwayX =(x [2]-x [0])*(y [1]-y [0])/(y [2]-y [0])+ x [0]そしてUとVとzについても同じ:halfwayU =(u [2] -u [0])*(y [1]-y [0])/(y [2]-y [0])+ u [0]
- そして、halfwayXを使用して、UとVおよびzのステッパーを計算します。if(halfwayX --x [1] == 0){slopeU = 0、slopeV = 0、slopeZ = 0} else {slopeU =(halfwayU --U [1 ])/(halfwayX --x [1])} //(vとzについても同じ)
- Y上部のクリッピングを実行します(三角形の上部が画面から外れている(またはクリッピング長方形から外れている)場合に、描画を開始する場所を計算します)
- y=startYの場合; y <endY; y ++){
- Yは画面の下を過ぎていますか?レンダリングを停止します!
- 最初の水平線leftCurX=ceil(startx);のstartXとendXを計算します。leftCurY = ceil(endy);
- 画面の左側の水平方向の境界線(またはクリッピング領域)に描画する線をクリップします
- 宛先バッファーへのポインターを準備します(毎回配列インデックスを介して行うのは遅すぎます)unsigned int buf = destbuf +(yピッチ)+ startX; (24ビットまたは32ビットのレンダリングを行う場合はunsigned int)ここでZBufferポインターも準備します(これを使用している場合)
- for(x = startX; x <endX; x ++){
- パースペクティブテクスチャマッピングの場合(bilineair補間を使用しない場合は、次のようにします):
コードフラグメント:
float tv = startV / startZ
float tu = startU / startZ;
tv %= texturePitch; //make sure the texture coordinates stay on the texture if they are too wide/high
tu %= texturePitch; //I'm assuming square textures here. With fixed point you could have used &=
unsigned int *textPtr = textureBuf+tu + (tv*texturePitch); //in case of fixedpoints one could have shifted the tv. Now we have to multiply everytime.
int destColTm = *(textPtr); //this is the color (if we only use texture mapping) we'll be needing for the pixel
「ダミーライン」について申し訳ありません。マークダウンコードを同期させるために必要でした。(意図したとおりにすべてを整理するのにしばらく時間がかかりました)
これがあなたが直面している問題を解決するのに役立つかどうか私に知らせてください!