我正在使用openGL,但这基本上是一个数学问题。 我试图计算投影矩阵,我在视平面R(x,y,z)上有一个点和该平面N的法向量(n1,n2,n3)。 我也知道眼睛在(0,0,0),我猜在技术术语中它是透视参考点。 如何从这些数据中获得透视投影?我知道如何以常规方式进行FOV,纵横比以及近距离和远距离飞行。
答案 0 :(得分:6)
我认为你把这个问题置于" opengl"之下会造成一些混乱。标签。问题是在计算机图形学中,术语投影在严格的数学意义上是不被理解的。
在数学中,定义一个投影(并且以下不是确切的数学定义,而只是我自己的释义)作为在应用两次时不会进一步改变结果的东西。想一想。当您将3d空间中的点投影到2d平面(仍然在该3d空间中)时,每个点的投影将最终在该平面上。但是已经在这个平面上的点已经不再移动了,所以你可以根据需要多次应用它,而不用再改变结果。
经典"投影"计算机图形学中的矩阵不会这样做。它们以一般截头体被映射到立方体(或立方体)的方式转换空间。为此,您基本上需要所有参数来描述平截头体,其通常是纵横比,视角,与近平面和远平面的距离,以及投影方向和中心点(后两者通常是隐含的)按惯例定义)。对于一般情况,还有水平和垂直不对称组件(想象它像#34;镜头移位"有投影仪)。所有这些都是计算机图形学中典型的投影矩阵所代表的。
从你给出的参数构造这样的矩阵是不可能的,因为你缺少很多参数。此外 - 我认为这有点透露 - 你已经给出了一个视图平面。但到目前为止讨论的投影矩阵并没有定义一个视图平面 - 任何平行于近或远平面并且在摄像机前面的平面可以被想象为观察平面(在摄像机后面也可以工作,但图像将被镜像) ),如果你需要一个。但从严格意义上说,它只是一个观看平面"如果所有的投影点也会在那个平面上结束 - 计算机图形透视矩阵显然是这样做的。相反,它保留了它们的三维距离信息 - 这也意味着操作是可逆的,而经典的数学投影通常不是。
从所有这些,我只是猜测你正在寻找的是从3D空间到2D平面的透视投影,而不是用于计算机图形的透视变换。您需要的所有参数只是视点和平面。请注意,这是完全您所拥有的内容:投影中心应为原点,R
和N
定义平面。
这种投影也可以用4×4同质矩阵表示。在你的问题中有一件事没有定义:正常的方向。我再次假设标准数学约定并假设视图平面定义为<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
。结合其他维度的身份变换,这意味着这一点不变。
答案 1 :(得分:0)
投影矩阵必须位于(0,0,0)
,并且可以Z+
或Z-
方向查看
这是必须的,因为OpenGL中的很多东西都依赖它,比如FOG,灯光......所以如果你的方向或位置不同,那么你需要将它移动到相机矩阵。假设您的焦点为(0,0,0)
,如您所述,法线向量为(0,0,+/-1)
Z附近
是焦点和投影平面之间的距离,因此znear
是平面与(0,0,0)
的垂直距离。如果假设是正确的那么
znear=R.z
否则你需要计算它。我认为你得到了所需的一切
R
的方向N
(0,0,0)
R
Z远
由深度缓冲区位宽和z
决定zfar=znear*(1<<(cDepthBits-1))
这是最大可用zfar
(用于我的目的)如果你需要更高的精度然后降低一点不要忘记精度在znear
附近更高而在zfar
附近更差。 zfar
通常设置为最大视图距离,znear
从中计算或设置为最小焦距范围。
视角
我主要使用60度视角。 zang=60.0
[deg]
我所在地区的普通男性最多可以看到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
是投影矩阵副本我用它来进行鼠标位置转换......
如果你没有校正矩阵,那么在使用高级材料(如重叠更多的frustrum)以获得高精度深度范围时,您将会关闭。我使用它来获得具有24位深度缓冲区的<0.1m,1000AU>
frustrum,并且不准确会导致图像不能完美贴合...
<强> [注释] 强>
如果焦点不是真正的(0,0,0)
或你没有在Z轴上观看(就像你没有相机矩阵而是使用投影矩阵那么)那么在基本场景/技术上你会看到没有问题。他们从使用高级图形开始。如果您使用GLSL,那么您可以毫无问题地处理这个问题,但修复OpenGL功能无法正确处理。这也称为PROJECTION_MATRIX abuse
[edit1] 少数链接
如果你的观点是标准的截头,那么写下你自己的矩阵gluPerspective,否则在这里Projections看看如何构建它的一些想法
<强> [EDIT2] 强>
从你的评论我看到它是这样的:
f
是您的观察点(轴是全球世界轴)
如果f'
是屏幕的中心,R
是观察点
因此,为f'
位置创建投影矩阵(如上所述),创建转换矩阵以将f'
转换为f
。变换后的f
必须与f'
中的Z轴相同,其他轴可以通过叉积获得,并将其用作相机或乘法摊位并用作滥用的投影矩阵
如何构建矩阵在我之前的评论
中的了解变换矩阵链接中进行了解释