三角形で満たされた単純なシーンでどのピクセルを描画する必要があるかを判断するために、Z バッファーを実装しています。三角形、頂点、ベクトル (もちろん数学的な (x、y、z) の種類) の構造表現と、個々のピクセルを画面に描画する関数があります。ここに私が持っている構造があります:
struct vertex{
float x, y, z;
... //other members for lighting, etc. that will be used later and are not relevant here
};
struct myVector{
float x, y, z;
};
struct triangle{
... //other stuff
vertex v[3];
};
残念ながら、三角形を画面にスキャン変換すると、深さの計算に依存して表示されるものと描画されるものを決定するため、不正確/非現実的な Z 値が得られます (たとえば、三角形のある点の深さが3 つの頂点すべての深さの境界)! 私は自分のコードを何度も見直してきましたが、数学が間違っているのか、不注意な間違いがあるのか わからないので、他の誰かが何かを見ることができることを期待して、私がやろうとしていることを正確に提示しようとします.私はしません。(そして、浮動小数点値が浮動小数点値のままであること、引数を正しく渡していることなどを注意深く調べたので、これは本当に不可解です!)
全体として、私のスキャン変換アルゴリズムは、次のようにスキャン ライン全体にピクセルを塗りつぶします (疑似コード):
for all triangles{
... //Do edge-related sorting stuff, etc...get ready to fill pixels
float zInit; //the very first z-value, with a longer calculation
float zPrev; //the "zk" needed when interpolating "zk+1" across a scan line
for(xPos = currentX at left side edge; xPos != currentX at right side edge; currentX++){
*if this is first pixel acorss scan line, calculate zInit and draw pixel/store z if depth is less
than current zBuffer value at this point. Then set zPrev = zInit.
*otherwise, interpolate zNext using zPrev. Draw pixel/store z if depth < current zBuffer value at
this point. Then set zPrev = zNext.
}
... //other scan conversion stuff...update x values, etc.
}
各スキャン ラインの zInit の値を取得するには、平面方程式 Ax + By + Cz + D = 0 を考慮し、それを並べ替えて z = -1*(Ax + By + D)/C を取得します。ここで、x と y はそれぞれ、スキャン ライン全体の現在の x 値と現在のスキャン ライン値自体としてプラグインされます。
スキャン ラインを横切る後続の z 値については、zk+1 = zk - A/C として補間します。ここで、A と C は平面方程式から得られます。
これらの z 計算の A、B、および C を取得するにvertex v[3]
は、現在の三角形の 3 つの頂点 (配列 ) によって定義される平面の法線ベクトルが必要です。この法線 (コードでは planeNormal と名付けました) を取得するために、クロス積関数を定義しました。
myVector cross(float x1, float y1, float z1, float x2, float y2, float z2)
{
float crX = (y1*z2) - (z1*y2);
float crY = (z1*x2) - (x1*z2);
float crZ = (x1*y2) - (y1*x2);
myVector res;
res.x = crX;
res.y = crY;
res.z = crZ;
return res;
}
平面方程式/my z 計算の D 値を取得するには、平面方程式 A(x-x1) + B(y-y1) + C(z-z1) = 0 を使用します。ここで、(x1, y1, z1)平面内の基準点にすぎません。参照点として三角形の頂点 v[0] を選択し、再配置しました。
Ax + By + Cz = Ax1 + By1 + Cz1 したがって、D = Ax1 + By1 + Cz1
最後に、z 計算の A、B、C、D を取得するために、三角形ごとにこれを行いました。ここで、trianglelist[nt]
はシーンの三角形配列全体の現在のインデックス nt にある三角形です。
float pA = planeNormal.x;
float pB = planeNormal.y;
float pC = planeNormal.z;
float pD = (pA*trianglelist[nt].v[0].x)+(pB*trianglelist[nt].v[0].y)+(pC*trianglelist[nt].v[0].z);
ここから、説明したスキャン変換アルゴリズム内で、zs を計算しました。
zInit = -1*((pA*cx)+(pB*scanLine)+(pD))/(pC); //cx is current x value; scanLine is current y value
...
...
float zNext = zPrev - (pA/pC);
残念ながら、慎重に作業した結果、何かがおかしくなっています。一部の三角形では、深さの値がリアルになります (記号を除く)。頂点 (200, 10, 75)、(75, 200, 75)、および (15, 60, 75) によって与えられる三角形では、すべての深さは -75 になります。すべての頂点が同じ深さの他の三角形でも同じことが起こりました。しかし、頂点 (390, 300, 105)、(170, 360, 80)、(190, 240, 25) では、すべての z 値が 300 を超えています! 最初のものは 310.5 になり、残りは大きくなり、最大値は約 365 になります。これは、最も深い頂点が z = 105 にある場合には発生しません!!! それで、とりとめのないすべての後、誰かがこれを引き起こした可能性のあるものを見ることができますか? それが記号に関連するものである場合、私は驚かないでしょうが、どこで(結局のところ、絶対値は一定の深さの場合に正しいのですか)?