c++ - opengl - 使用 glOrtho 时相机看不到物体
问题描述
我是OpenGL的新手,我试图了解投影矩阵是如何在其中工作的。
为了创建一个简单的案例,我在世界空间中定义了一个三角形,它的坐标是:
(0,1,0), (1,0,0), (-1,0,0)
我将模型视图矩阵和投影矩阵设置如下:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
0, 0, 2,
0, 0, 0,
0, 1, 0);
glMatrixMode(GL_PROJECTION);
glOrtho(-2, 2, -2, 2, -0.1, -2.0); // does not work
// glOrtho(-2, 2, -2, 2, 0.1, 2.0); // works
据我了解,gluLookAt()
是用来设置查看矩阵的。由于OpenGL
没有“照相机”的概念,因此它改造了整个世界,达到了照相机的效果。在上面的代码中,我假设“相机”在 (0,0,2),看着 (0,0,0)。因此OpenGL在内部将三角形沿z
轴向后移动到z=-2
.
要定义视锥,请glOrtho()
获取 6 个参数。为了使三角形在截锥体中可见,我设置了near
andfar
值分别设置为-0.1
and-2.0
这应该表明截锥体包括[-0.1, -2.0]
在z
轴上。
我搜索了类似的问题,发现有人说最后两个参数实际上glOrtho()
是-near
-far
。但如果这是正确的,下面的代码应该可以工作(但它没有):
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
0, 0, -2, // changed 2 to -2, thus the triangle should be transformed to z=2?
0, 0, 0,
0, 1, 0);
glMatrixMode(GL_PROJECTION);
glOrtho(-2, 2, -2, 2, -0.1, -2.0); // -near=-0.1, -far=-2.0, thus the frustum should include [0.1, 2.0], thus include the triangle
如果我是正确的,应该在屏幕上绘制三角形,所以我的代码一定有问题。任何人都可以帮忙吗?
解决方案
首先请注意,固定函数管道矩阵堆栈和按glBegin
/glEnd
序列绘图已被弃用超过 10 年。阅读Fixed Function Pipeline并查看Vertex Specification了解最先进的渲染方式。
如果您使用这样的视图矩阵:
gluLookAt(0, 0, 2, 0, 0, 0, 0, 1, 0);
然后,当您设置投影矩阵时,近平面和远平面的值必须为正,
glOrtho(-2, 2, -2, 2, 0.1, 2.0);
因为,gluLookAt
将顶点转换到视图空间(在视图空间中,z 轴指向视口外),但投影矩阵反转了 z 轴。
但要小心,因为三角形在z=0
(0,1,0), (1,0,0), (-1,0,0)
并且从相机到三角形的距离为 2,由于视图矩阵,三角形正好放置在远平面上(也是 2.0)。我建议将到远平面的距离从 2.0 增加到(例如)3.0:
glOrtho(-2, 2, -2, 2, 0.1, 3.0);
如果你改变视图矩阵,
gluLookAt(0, 0, -2, 0, 0, 0, 0, 1, 0);
然后(视图空间)z 轴仍然指向视口之外,但您会看到三角形的“后”侧。三角形仍位于视图的中心 (0, 0, 0),但相机位置已更改。三角形仍然在镜头前。
如果你愿意
gluLookAt(0, 0, 2, 0, 0, 4, 0, 1, 0);
然后你会远离三角形。您必须将视图的背面投影到视口才能“看到”三角形 ( glOrtho(-2, 2, -2, 2, -0.1, -3.0);
)。
进一步注意,这glOrtho
将当前矩阵乘以正交投影矩阵。这意味着您应该在使用 之前设置单位矩阵,glOrtho
就像使用模型视图矩阵一样:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2, 2, -2, 2, 0.1, 2.0);
解释
投影、视图和模型矩阵相互作用,以在视口上呈现场景的对象(网格)。模型矩阵定义了场景世界空间中单个对象(网格)的位置方向和比例。视图矩阵定义了观察者(观察者)在场景中的位置和观察方向。投影矩阵定义了相对于投影到视口上的观察者(观察者)的面积(体积)。
在正交投影中,这个区域(体积)由到观察者位置的 6 个距离(左、右、下、上、近和远)定义。
查看矩阵
视图坐标系统描述了观察场景的方向和位置。视图矩阵从世界空间转换到视图(眼睛)空间。
如果视图空间的坐标系是右手系,那么 X 轴指向左侧,Y 轴向上,Z 轴在视野外(注意右手系中的 Z 轴是 X 轴和 Y 轴的叉积)。
投影矩阵
投影矩阵描述了从场景上的 3D 点到视口上的 2D 点的映射。它从眼睛空间变换到剪辑空间,剪辑空间中的坐标通过除以w
剪辑坐标的分量被变换为归一化设备坐标(NDC)。NDC 在 (-1,-1,-1) 到 (1,1,1) 范围内。
每个超出裁剪空间的几何图形都被裁剪。
在正交投影中,视图空间中的坐标线性映射到剪辑空间坐标,剪辑空间坐标等于标准化设备坐标,因为w
分量为 1(对于笛卡尔输入坐标)。
left、right、bottom、top、near 和 far 的值定义了一个框。盒子体积内的所有几何图形在视口上都是“可见的”。
正交投影矩阵如下所示:
r = right, l = left, b = bottom, t = top, n = near, f = far
2/(r-l) 0 0 0
0 2/(t-b) 0 0
0 0 -2/(f-n) 0
-(r+l)/(r-l) -(t+b)/(t-b) -(f+n)/(f-n) 1
z 轴被投影矩阵反转。
推荐阅读
- javascript - 单击传单标记时如何发送页面 URL?
- database - 从 .db 文件中获取数据
- javascript - 在拖动 jquery 可拖动 div 时显示指南并进行捕捉
- authentication - SQL 2016:连接到集群名称而不是单个节点时出现错误 18452
- python - plotly 不显示谷歌合作实验室中的情节
- php - PHP 使用 TCPDF 创建 PDF 并将其发送到 Angular 前端
- python - Eland 向 eland Dataframe 添加参数
- c - 是否存在 %p 格式说明符不会以 0x.. 格式打印地址的情况
- html - 在底部裁剪图像并添加文本
- python - 我可以使用 xlwings 抑制来自 VBA 的消息框吗?