由于@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