使用OpenGL进行透视投影

10

我对透视投影感到困惑。

以下情况让我感到迷惑。我的视景体前平面基本上位于正z轴,后平面位于负轴并绕正z轴旋转了一定角度。

现在,每当我查看示例时,我发现近和远平面都存在于负z轴中。

在这种情况下,我的处理方法基本上是:

glMatrixMode(GL_PROJECTION);    
glLoadIdentity();
glFrustrum(-xval,+xval,-yval,+yval,-10,+10);
gluLookAt(); // some point lying on this axis of symmetry about the point
glMatrixMode(GL_MODELVIEW);

那么,在上述情况下,如果使用glFrustum并且z的值为正数和负数,我应该期望什么样的行为呢?也就是说,在这种情况下z的值为-10到+10。


“-ive”轴上的背板。我从未听说过“ive”轴。您能详细说明一下吗,还是这只是一个打字错误?此外,“lookat”矩阵永远不要放在GL_PROJECTION矩阵中,而应该放在GL_MODELVIEW矩阵中。 - Nicol Bolas
我的意思是前平面沿着+Z轴存在,而后平面沿着-Z轴存在。类似于glFrustrum(-xval,+xval,-yval,+yval,-10,+10);其中近平面沿z轴变为+10,远平面沿z轴变为-10。 - John Cassidy
'+ive'表示'positive',而'-ive'表示'negative'。 - Bart
2
我已经做了十多年的图形设计。我在大学里通过了两个学期的图形设计课程。但我从未听说过“+ive z轴”或“-ive z轴”。实际上,只有一个Z轴,可以向正方向和负方向延伸。 - Nicol Bolas
是的,确切地说,抱歉语言有些奇怪。正Z轴和负Z轴。 - John Cassidy
让我们了解透视投影的概念,查看这个漂亮的交互式演示,展示三维点如何投影到二维空间中。http://www.mathdisk.com/pub/safi/worksheets/Perspective_Projection - user1509461
3个回答

7
视景体定义了你实际看到世界的范围,视景体外的每个对象都不可见,而视景体内的一切都有可能是可见的(如果没有被前面的物体遮挡)。视景体的形状由所使用的投影类型确定。有两种投影类型:正交投影和透视投影。正交投影不考虑观察者距离(不太自然但对CAD软件等很有用),而透视投影考虑了观察者距离,因此更远的物体看起来更小。在正交投影中,视景体是一个立方体,在透视投影中,视景体呈一个棱锥形状(近裁剪平面比远裁剪平面小)。无论哪种情况,视景体的内容都被“投影”到近裁剪平面上。当然,这个过程比简单的投影矩阵乘以视景体中的每个顶点要复杂一些;但基本上在几乎所有与OpenGL相关的书籍中都有解释。视景体形状在某种程度上模拟了相机的属性...你能看到多宽,能看多远等等。

这本红书在专门的视角章节中很好地解释了这一点。

当谈论一个棱台时,意味着你正在使用透视投影。

要构建一个棱台,你需要8个点,并且通常希望构建对称的棱台来简化投影矩阵。

你将使用辅助方法(如gluPerspective(fovy,aspect_ratio,near,far)),而不是直接手动指定8个点来构造棱台;它使用“更直观”的参数进行棱台构造; 它基本上是glFrustum的包装器,为您计算8个点,然后调用glFrustum而不是您自己。

对于OpenGL 3.0及更高版本,您将提供自己的gluPerspective实现,您可以简单地通过谷歌搜索代码。

只需记住,投影使3D变成2D。

关于视图,OpenGL使用右手坐标系(x轴向左,y轴向上,z轴向屏幕外); DirectX使用左手坐标系。

请记住,在3D空间中,您只有2种坐标系方向(左手和右手)。

区别在于z轴的方向;如果你让z轴指向内部,那么它是一个左手坐标系,如果你让z轴指向外部,那么它是一个右手坐标系。
任何其他方向的z轴都不会使z轴垂直于x和y轴,因此你就没有了一个坐标系。
左右手定则决定了一些东西,比如正旋转的方向等等。
你的相机最初位于原点(0,0,0),默认情况下面对着-z轴;除非你应用某种变换,否则它将一直保持这样。
你的视锥体是围绕观察方向构建的,近裁剪平面位于距离相机初始位置z=-near的位置。
当您将nearfar指定为正值时,使用glFrustum函数时,您并没有指定它们的z位置,只是因为相机默认沿着负z轴方向,且相机最初位于原点(0,0,0),所以近裁剪平面位于z=-near处,而您的近裁剪平面始终与观察者眼睛位置(即相机位置)相距near

每当更改视图(更改相机位置或更改相机方向或两者同时更改)时,您的视锥体仍将“围绕新视图方向”旋转,并且近裁剪平面仍将与新相机位置相距“near”。

希望您能理解这个概念。

视锥体定义了多少空间。

无论相机在哪里并指向何处。


4
在上述情况下,如果使用glFrustum并且z的值为正数和负数,我应该期望什么行为。即在此情况下为-10到+10。
破碎的。你应该期望行为是破碎的。
文档(链接)非常清楚:
nearVal,farVal:指定近和远深度剪切平面的距离。两个距离必须为正数。
(强调添加)
传递这些值的负数(或零)将产生不良后果。

谢谢你的回答。所以,基本上这需要使用平移和旋转来处理。我还有一个问题。请问你能帮我吗?为了解决我上面的问题,我应该在什么时候保留我的gluLookAt呢?正如你上面提到的,我应该将我的gluLookAt放在我的MODELVIEW部分。那么平移和旋转部分是在gluLookAt之前还是之后呢? - John Cassidy
查看变换是在应用所有建模变换之后应用的。建模变换将对象相对于彼此和视图变换定位/定向,而视图变换是在之后应用的,因为您首先想要安排一切,然后再对场景进行“查看”。由于OpenGL使用列主序来表示其矩阵,这些矩阵代表变换,因此您在代码中编写gluLookAt之前的所有建模变换,但生成的视图变换是在应用所有建模变换之后应用的。 - Mandark

2
现在,每当我看到示例时,我都看到近平面和远平面都存在于-z轴。

当然了。否则你会得到这样的结果。

:enter image description here

所有的投影都是相对于原点0进行的。近裁剪面和远裁剪面决定了它们距离原点的距离。左右定义了视锥的开口角度,与近裁剪面一起。如果你在原点的两侧放置一个“近”裁剪面和远裁剪面,你的投影空间就会形成一个沙漏形状。
glMatrixMode(GL_PROJECTION);    
glLoadIdentity();
glFrustrum(-xval,+xval,-yval,+yval,-10,+10);
gluLookAt(); // some point lying on this axis of symmetry about the point
glMatrixMode(GL_MODELVIEW);
投影不是用来放置视图的,它是你虚拟相机的“镜头”。你可以使用它来倾斜和移动你的镜头并设置“焦距”,但它不是用来“放置你的相机”的。这应该通过模型矩阵完成。
引用:
在上述情况下,我应该对glFrustum使用负值和正值的z期望什么行为,即在这种情况下-10到+10。
从远平面到“近”平面,随着物体靠近0,它们会变得越来越大,当Z=0时,它们处于奇异点并无限扩大,然后越靠近近平面,它们将变小但会被反转,即绕Z轴旋转180°,并且深度值被翻转,即深度测试将拒绝比0更接近近平面的片段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接