所以我正在编写自己的自定义3D转换管道,以便更好地理解它是如何工作的。我可以正确地将所有内容渲染到屏幕上,现在我要回去查看裁剪。
根据我的理解,如果透视分割后的x或y值超出[-1,1]的范围,我应该剪切一个顶点,如果z值超出[0,1的界限],我应该剪裁一个顶点。 ,1]。
当我实现它时,我的z值始终为-1.xxxxxxxxxxx,其中xxxxxxx是一个非常小的数字。
这有点长,我道歉,但我想确保我提供了所有可能的信息。
第一个约定:
我正在使用左手系统,其中矩阵看起来像这样:
[m00, m01, m02, m03]
[m10, m11, m12, m13]
[m20, m21, m22, m23]
[m30, m31, m32, m33]
我的矢量是这样的列:
[x]
[y]
[z]
[w]
我的相机设置为:
以PI / 4为单位的垂直FOV。
1的宽高比:(方形视口)
近剪辑值为1。
远剪辑值为1000。
初始世界x位置为0。
初始世界y位置为0。
初始世界z位置为-500。
摄像机向下看Z轴(0,0,1)
给定一个顶点,管道的工作方式如下:
第1步:将顶点乘以相机矩阵。
第2步:将顶点乘以投影矩阵。
投影矩阵是:
[2.41421, 0, 0, 0]
[0 2.41421, 0, 0]
[0, 0, 1.001001, 1]
[0, 0, -1.001001, 0]
第3步:将x,y和z分量乘以1 / w。
第4步: [这就是问题所在]如果外边界,请剪切顶点。
第5步:转换为屏幕坐标。
我有一个示例顶点
(-100, -100, 0, 1)
乘以相机矩阵后,我得到:
(-100, -100, 500, 1)
这是有道理的,因为相对于相机,该顶点是左侧和下侧100个单位,前方500个单位。它也在1的近剪辑和1000的远剪辑之间.W仍然是1.
乘以投影矩阵后得到:
(-241.42135, -241.42135, 601.600600, -600.600600)
我不确定这是否有意义。 x和y看起来是正确的,但是我对于z和w感到不满,因为透视分割的下一步是奇数。
在透视划分后,我得到:
(0.401966, 0.401966, -1.001665, 1)
x和y再次有意义,它们都在[-1,1]的范围内。但是z值明显超出了界限,尽管我认为它仍然应该在最佳状态之内。 W又回到了1,这也是有道理的。
再次为小说道歉,但我希望有人可以帮助我弄清楚我做错了什么。
谢谢!
答案 0 :(得分:3)
好吧,看起来我弄清楚它是什么问题。
我的投影矩阵是:
[2.41421, 0, 0, 0]
[0 2.41421, 0, 0]
[0, 0, 1.001001, 1]
[0, 0, -1.001001, 0]
但它确实应该转换成:
[2.41421, 0, 0, 0]
[0 2.41421, 0, 0]
[0, 0, 1.001001, -1.001001]
[0, 0, 1, 0]
使用此矩阵时,我的x和y值保持与预期相同,现在我的z值被限制在[0,1]范围内,并且如果它们位于远剪裁平面附近,则仅超出该范围。 / p>
现在唯一的问题是,我很困惑我是使用右手还是左手系统。
我所知道的是现在它有效......
答案 1 :(得分:2)
我可能不在这里,但我认为投影矩阵和透视分界的目的是发现屏幕上该点的2D位置。在这种情况下,剩下的z值不一定具有任何意义,因为数学都是为了找到那两个x和y值。
更新: 我想我已经弄清楚了。你的数学都是正确的。您描述的相机和frustum在Z = 1处具有近剪裁平面,因此您在(-100,100,0)处的示例点实际上是剪裁平面的外,因此z-buffer值略低于-1非常有意义。
尝试在平截头体内部使用z坐标的样本点,例如z坐标为2。