由於@ybungalobill已經提到,z-buffer是最容易實現的算法。填充組成立方體的三角形/多邊形時,插入它們之間的Z座標並將其存儲爲每像素。如果稍後填充另一個在同一X,Y座標上呈現的多邊形,請檢查其Z是否小於已存儲在緩衝區中的Z.重繪之前不要忘記將Z緩衝區清除爲無窮大。僞代碼:
foreach (scanline in polygon) {
int length = scanline.right.x - scanline.left.x;
foreach (pixel in scanline) {
float t = (float)pixel.x/length;
float z = (1 - t) * scanline.left.z + t * scanline.right.z; // Interpolate the Z coordinate
if (z < zbuffer[scanline.y][pixel.x])
drawPixel(pixel.x, scanline.y, polygon.color); // The pixel is closer, paint it
}
}
,通過不拉絲,將被覆蓋的像素上執行CPU更好的Z緩存的修訂方法被稱爲段緩衝:http://www.gamedev.net/reference/articles/article668.asp
另一種方法是沃諾克的算法。它使用遞歸,這使得很難在GPU上使用,但如果使用自己的堆棧來避免堆棧溢出,CPU應該會很好。這個想法在於將場景劃分爲4部分並檢查是否只有一個覆蓋整個部分的多邊形。如果不再分割,直到滿足條件(在最壞的情況下它將在像素級別被滿足)。僞代碼:
void warnock(Rectangle rect)
{
float minZ = infinity;
foreach (polygon in polygons) {
if (rect is inside polygon) {
float z = interpolateZ(polygon, rect.x + rect.width/2, rect.y + rect.height/2); // Get Z coordinate at the centre of the rectangle
if (z < minZ) { // If there are more polygons in this rectangle, make sure the topmost one gets drawn last
fillRect(polygon.color);
minZ = z;
}
} else {
// Divide to 4 subrectangles
warnock(Rectangle(rect.x, rect.y, rect.width/2, rect.height/2)); // Top left
warnock(Rectangle(rect.x, rect.y + rect.height/2, rect.width/2, rect.height/2)); // Bottom left
warnock(Rectangle(rect.x + rect.width/2, rect.y, rect.width/2, rect.height/2)); // Bottom right
warnock(Rectangle(rect.x + rect.width/2, rect.y + rect.height/2, rect.width/2, rect.height/2)); // Top right
}
}
}
的畫家算法是您與您的多維數據集做了什麼,唯一的區別是,它排序的多邊形,而不是整個對象。即使這樣,很難解決各種多邊形交集,我個人不會將它用於非平凡的場景。
您可能使用的另一種算法是背面剔除算法。這僅適用於不重疊的凸對象。該算法計算每個多邊形的法線,並且如果它指向相機的方向,則會將其移除。
Raycasting是另一種確定每像素可見性的方法。但是,它的CPU密集程度相當高。基本思想是檢查屏幕的每個像素,哪個多邊形與它相交(哪個多邊形被當前像素投射的光線擊中)。光線的起源是眼睛的位置。僞代碼:
foreach (pixel in screen) {
float minZ = infinity; // Can be zfar from the perspective projection
Color pixelColor = backgroundColor;
foreach (polygon in projectedPolygons) {
if (polygon contains Point(pixel.x, pixel.y)) {
float z = interpolateZ(polygon, pixel.x, pixel.y); // Get the current Z for (x, y) and this polygon using bilinear interpolation
if (z < minZ) {
minZ = z;
pixelColor = polygon.color;
}
}
}
}
段緩衝和Wornock算法看起來很有前途的候選人。我會看看我可以執行哪一個。感謝一堆這樣的詳細答案。我已經在正投影中使用背面剔除,但是我相信它在透視投影中不能正確工作。 – Jayesh 2010-10-10 13:04:48
@Jayesh:背景剔除也適用於透視投影(如果我的答案中提到的其他條件得到滿足)。 – 2010-10-10 13:16:31
啊。你的評論讓我想到了,我想我現在知道爲什麼背面剔除在透視投影中不適用於我。我在極端的範圍內使用了所有立方體都具有相同方向的事實。所以在任何時候,他們的臉上只有3張是可見的。在正交模式的情況下,所有立方體都是相同的3個面。但是現在我只是想到透視投影是不正確的,我應該分別爲每個立方體計算隱藏的背面。我需要驗證它,但我認爲就是這樣。你認爲這會讓準確的z排序成爲不必要的嗎? – Jayesh 2010-10-10 13:43:34