我正在尝试创建一个简单的3D图形引擎,并找到并使用了我在此处找到的公式:http://en.wikipedia.org/wiki/3D_projection#cite_note-0。 (我计算了Dx,Dy,Dz和Bx,By)
我工作,但是当我旋转相机时,足够的线条开始飞到整个地方,最终你会看到屏幕上的多边形开始回到屏幕的另一侧(你可以到这里:{{3并使用W,A,S和D键旋转相机,看看我在说什么)
我读了这个讨论:http://mobile.sheridanc.on.ca/~claassen/3d.html他谈到了使用剪辑矩阵,但我仍然对如何使用剪辑矩阵感到困惑。此外,我不确定我是否正在使用讨论中所述的“齐次坐标”。
答案 0 :(得分:22)
在乘以透视投影矩阵(也称为剪辑矩阵)之后,您最终会得到一个同质的4向量[x,y,z,w]。这称为npc(标准化投影坐标),也称为剪辑坐标。要在屏幕上获取2D坐标,通常使用类似
的内容xscreen = (x/w) * screen_width
yscreen = (y/w) * screen_width
对于相机前面的点,这可以满足您的需求。但是相机后面的点将具有w <0并且即使该点位于相机后面,您也将获得映射到有效屏幕坐标的值。为了避免这种情况,你需要剪辑。需要剪裁具有w <0的任何顶点。
一个快速的尝试是,如果任一顶点的w <0,则不绘制任何线。这应该可以修复场景中出现的奇怪多边形。但它也会删除一些应该可见的行。
要完全解决问题,您需要剪切在摄像机前面有一个顶点和摄像机后面有一个顶点的所有线条。剪切意味着将线切成两半并丢掉相机后面的一半。该线被穿过相机并平行于显示屏的平面“剪切”。问题是在线上找到与该平面相对应的点(即线与平面相交的位置)。这将发生在w == 0的行上。你可以找到这一点,但是当你试图找到屏幕坐标时
xscreen = (x/w) * screen_width
yscreen = (y/w) * screen_width
你最终除以0(w == 0)。这就是“近剪裁平面”的原因。近剪裁平面也与显示屏平行,但位于摄像机前方(摄像机和场景之间)。相机与近剪裁平面之间的距离是投影矩阵的“近”参数:
[ near/width ][ 0 ][ 0 ][ 0 ]
[ 0 ][ near/height ][ 0 ][ 0 ]
[ 0 ][ 0 ][(far+near)/(far-near) ][ 1 ]
[ 0 ][ 0 ][-(2*near*far)/(far-near)][ 0 ]
要剪切到近平面,您必须找到与近剪裁平面相交的直线上的点。这是w == near的点。因此,如果你有一个顶点为v1,v2的行
v1 = [x1, y1, z1, w1]
v2 = [x2, y2, z2, w2]
您需要检查每个顶点是否在近剪裁平面的前面或后面。如果w1&gt; =接近和落后,如果w1 <1,则V1在前面。近。如果v1和v2都在前面,那么画线。如果v1和v2都落后,则不要画线。如果v1在前面且v2在后面,那么你需要找到线与近剪裁平面相交的vc:
n = (w1 - near) / (w1 - w2)
xc = (n * x1) + ((1-n) * x2)
yc = (n * y1) + ((1-n) * y2)
zc = (n * z1) + ((1-n) * z2)
wc = near
vc = [xc, yc, zc, wc]
现在画出v1和vc之间的界限。
答案 1 :(得分:4)
这可能是对术语的误解。剪辑矩阵更适合称为投影矩阵。至少在OpenGL中,投影矩阵将视图坐标空间(VCS)中的4D齐次坐标转换为剪切坐标空间(CCS)。从CCS到归一化设备协调空间(NDCS)的投影需要透视划分,即,将每个分量除以W分量。在此步骤之前正确完成剪切。因此,“剪切矩阵”不会消除在投影之前剪切几何体的需要。我希望我能理解你,这听起来不是居高临下。
那就是说,我认为你的投影矩阵显然是正确的 - 它有效。我怀疑通过 eye 后面的顶点有负W,这意味着它们应该被剪裁;但我也怀疑他们有负Z,所以分裂产生正Z值。如果您确实要剪切几何体,而不是丢弃整个三角形,请搜索“均匀剪切”。如果你真的没有在4D同质空间工作,你可以先看看'Sutherland-Hodgman'的3D裁剪。