[英]Calculating the perspective projection matrix according to the view plane
我正在使用openGL,但这基本上是一个数学问题。 我正在尝试计算投影矩阵,我在视图平面R(x,y,z)上有一个点,并且在该平面N(n1,n2,n3)的法线向量上有一个点。 我也知道眼睛在(0,0,0),从技术角度来说,它是透视参考点。 如何从这些数据得出透视投影? 我知道如何以常规方式获取FOV,宽高比和近,远平面。
我认为您通过将这个问题放在“ opengl”标签下引起了一些困惑。 问题在于,在计算机图形学中,术语“ 投影”在严格的数学意义上无法理解。
在数学中,将投影定义为以下内容(以下内容不是精确的数学定义,而只是我自己的措辞),因为两次应用后,它们不会进一步改变结果。 想一想。 当您将3d空间中的点投影到2d平面(仍在该3d空间中)时,每个点的投影将最终在该平面上。 但是已经在该平面上的点不再移动了,因此您可以根据需要多次应用此点,而无需进一步更改结果。
计算机图形学中的经典“投影”矩阵无法做到这一点。 他们transfrom在一般的视锥被映射到一个立方体(或长方体)的方式的空间。 为此,您基本上需要使用所有参数来描述平截头体,通常是纵横比,视角,到近,远平面的距离以及投影方向和中心点(后两个通常是隐式的)。按照惯例定义)。 对于一般情况,还存在水平和垂直不对称性组件(可以认为它就像是投影机的“镜头移位”)。 所有这些都是计算机图形学中典型的投影矩阵所代表的。
从给定的参数构造这样的矩阵实际上是不可能的,因为您缺少很多参数。 另外-我认为这是一种揭示-您给了一个视线 。 但是到目前为止讨论的投影矩阵还没有定义视平面-可以将平行于近视平面或远视平面并且在相机前面的任何平面都可以想象为视平面(在驼峰后面也可以使用,但是图像会被镜像),如果您需要一个。 但是从严格的意义上讲,如果所有投影点也都将落在该平面上,则它只会是一个“视图平面”,而计算机图形透视矩阵显然不会这样做。 相反,它保留其3d距离信息-这也意味着该操作是可逆的,而经典的数学投影通常不是。
综上所述,我只是想知道您正在寻找的是从3D空间到2D平面的透视投影,而不是用于计算机图形的透视变换。 所需的所有参数仅仅是视点和平面。 请注意,这正是您所给的:投影中心应为原点, R
和N
定义平面。
这种投影也可以用4x4均匀矩阵表示。 您的问题中没有定义一件事:法线的方向。 我再次假设使用标准的数学惯例,并假设视图平面定义为<N,x> + d = 0
。 通过在该方程式中使用R
,我们可以得出d = -N_x*R_x - N_y*R_y - N_z*R_z
。 所以投影矩阵就是
( 1 0 0 0 )
( 0 1 0 0 )
( 0 0 1 0 )
(-N_x/d -N_y/d -N_z/d 0 )
此矩阵有一些属性。 列为零,因此不可逆。 还要注意,对于每一个点(s*x, s*y, s*z, 1)
,将其应用到该结果上(当然,除以结果w
之后)无论s
是什么都是一样的-因此每个原点和(x,y,z)
之间的线上的点将产生相同的投影点-这就是透视投影应该做的。 最后要注意w=(N_x*x + N_y*y + N_z*z)/-d
,因此对于每个满足上述平面方程的点,将得到w= -d/-d = 1
。 结合其他维度的标识变换,这仅意味着该点不变。
投影矩阵必须位于(0,0,0)
并沿Z+
或Z-
方向查看
这是必须的,因为OpenGL中的许多东西都取决于它,例如FOG,照明...。因此,如果您的方向或位置不同,则需要将其移动到相机矩阵。 假设您所说的焦点是(0,0,0)
,法向矢量是(0,0,+/-1)
Z附近
是焦点到投影平面之间的距离,因此znear
是平面与(0,0,0)
垂直距离。 如果假设是正确的,那么
znear=Rz
否则,您需要进行计算。 我认为您已经拥有了所需的一切
R
向N
方向投射线 (0,0,0)
R
的距离 Z远
由深度缓冲区的位宽和z附近决定
zfar=znear*(1<<(cDepthBits-1))
如果需要更高的精度,则这是最大可用的zfar
(出于采矿目的),然后降低一点,不要忘记znear
附近的精度更高,而znear
附近的精度则差zfar
。 通常将zfar
设置为最大视野距离,并根据该距离计算出znear
或将其设置为最小对焦范围。
视角
我主要使用60度视角。 zang=60.0
[度]
我所在地区的普通男性最多可以看到90度,但包括60度视图在内的外围视图更舒适。
女性的视野更广...但是我从没有听到过关于60度视角的任何抱怨,所以让我们也对他们感到舒服...
方面
长宽比由OpenGL窗口尺寸xs,ys
aspect=(xs/ys)
这就是我设置投影矩阵的方式:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(zang/aspect,aspect,znear,zfar);
// gluPerspective has inacurate tangens so correct perspective matrix like this:
double perspective[16];
glGetDoublev(GL_PROJECTION_MATRIX,perspective);
perspective[ 0]= 1.0/tan(0.5*zang*deg);
perspective[ 5]=aspect/tan(0.5*zang*deg);
glLoadMatrixd(perspective);
deg = M_PI/180.0
perspective
是投影矩阵副本,我将其用于鼠标位置转换等...
如果不校正矩阵,则在使用高级功能(例如重叠更多的平截头体)以获得高精度深度范围时,您将无法使用。 我使用它来获取具有24位深度缓冲区的<0.1m,1000AU>
截<0.1m,1000AU>
,并且不准确会导致图像无法完美匹配...
[笔记]
如果焦点不是真的(0,0,0)
或者您不是在Z轴上查看(例如您没有相机矩阵,而是使用投影矩阵),则在基本场景/技术上您将看不到任何问题。 他们从使用高级图形开始。 如果使用GLSL,则可以毫无问题地进行处理,但是固定的OpenGL函数无法正确处理。 这也称为PROJECTION_MATRIX滥用
[edit1]几个链接
如果你的观点是标准截然后写矩阵你的自我gluPerspective否则看看这里预测的一些想法如何构建它
[edit2]
从您的评论中,我看到这样的:
f
是您的视点(轴是全局世界轴)
如果R
将是屏幕的中心,则f'
是视点
因此,为f'
位置创建投影矩阵(如上所述),创建转换矩阵以将f'
转换为f
。 转换后的f
必须具有与f'
相同的Z轴,其他轴可以通过叉积获得,并将其用作相机或与多个展位一起使用,并用作滥用的投影矩阵
我先前的评论中的“理解变换矩阵”链接中说明了如何构造矩阵
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.