【发布时间】:2014-10-14 23:29:10
【问题描述】:
我正在用 Java 编写软件渲染器,并尝试使用 Z 缓冲来计算每个像素的深度。但是,它似乎工作不一致。例如,对于犹他茶壶示例模型,手柄可能会拉出一半,这取决于我如何旋转它。
我的 z-buffer 算法:
for(int i = 0; i < m_triangles.size(); i++)
{
if(triangleIsBackfacing(m_triangles.get(i))) continue; //Backface culling
for(int y = minY(m_triangles.get(i)); y < maxY(m_triangles.get(i)); y++)
{
if((y + getHeight()/2 < 0) || (y + getHeight()/2 >= getHeight())) continue; //getHeight/2 and getWidth/2 is for moving the model to the centre of the screen
for(int x = minX(m_triangles.get(i)); x < maxX(m_triangles.get(i)); x++)
{
if((x + getWidth()/2 < 0) || (x + getWidth()/2 >= getWidth())) continue;
rayOrigin = new Point2D(x, y);
if(pointWithinTriangle(m_triangles.get(i), rayOrigin))
{
zDepth = zValueOfPoint(m_triangles.get(i), rayOrigin);
if(zDepth > zbuffer[x + getWidth()/2][y + getHeight()/2])
{
zbuffer[x + getWidth()/2][y + getHeight()/2] = zDepth;
colour[x + getWidth()/2][y + getHeight()/2] = m_triangles.get(i).getColour();
g2.setColor(m_triangles.get(i).getColour());
drawDot(g2, rayOrigin);
}
}
}
}
}
给定三角形和射线原点,计算点z值的方法:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double d = -(A * triangle.getV1().x + B * triangle.getV1().y + C * triangle.getV1().z);
double rayZ = -(A * rayOrigin.x + B * rayOrigin.y + d) / C;
return rayZ;
}
计算光线原点是否在投影三角形内的方法:
private boolean pointWithinTriangle(Triangle triangle, Point2D rayOrigin)
{
Vector2D v0 = new Vector2D(triangle.getV3().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v1 = new Vector2D(triangle.getV2().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v2 = new Vector2D(rayOrigin, triangle.getV1().projectPoint(modelViewer));
double d00 = v0.dotProduct(v0);
double d01 = v0.dotProduct(v1);
double d02 = v0.dotProduct(v2);
double d11 = v1.dotProduct(v1);
double d12 = v1.dotProduct(v2);
double invDenom = 1.0 / (d00 * d11 - d01 * d01);
double u = (d11 * d02 - d01 * d12) * invDenom;
double v = (d00 * d12 - d01 * d02) * invDenom;
// Check if point is in triangle
if((u >= 0) && (v >= 0) && ((u + v) <= 1))
{
return true;
}
return false;
}
三角形曲面法线的计算方法:
private Vector3D getNormal(Triangle triangle)
{
Vector3D v1 = new Vector3D(triangle.getV1(), triangle.getV2());
Vector3D v2 = new Vector3D(triangle.getV3(), triangle.getV2());
return v1.crossProduct(v2);
}
错误绘制的茶壶示例:
我做错了什么?我觉得这一定是一件小事。鉴于三角形完全绘制,我怀疑它是 pointWithinTriangle 方法。背面剔除似乎也可以正常工作,所以我怀疑是这样。对我来说最可能的罪魁祸首是 zValueOfPoint 方法,但我不知道它有什么问题。
【问题讨论】:
-
很难说出你的绘图中发生了什么。看起来我们可能只在看背面。 z 检验也可能相反。如果 z 轴与您认为的相反(镜像),这两种情况都会发生。
-
This 显示了茶壶内部的样子(由于背面剔除而未渲染)。这让我相当有信心不是那样的。至于反转的 z 测试,我尝试过交换它(使最大深度 = 9999,并检查 zDepth
-
我不能说我是否同意,因为我不知道茶壶的实际位置。您需要用两个相交的三角形构建一个小测试。找到一个坏像素。使用调试器逐步完成。找出您认为的数学与实际计算的结果之间的差异。
-
添加了答案顺便说一句,这是光线追踪器?渲染速度有多快(MPix/s) 我最近再次编写了 SW 渲染(使用类似于 API 的 OpenGL),以获取乐趣(32 位 C++ 和 GDI),同时使用:单纹理、无灯光、gourard 着色它高达 4-6 MPix/ sec ...但它尚未针对速度进行编码或优化(并且怀疑它会)...
-
一点也不快,我还没有测试过速度,但它在Java中已经不快了。它不是光线追踪器,仅对 z 深度缓冲区使用光线投射。
标签: java algorithm graphics 3d zbuffer