文章目录
- 文章说明
- 学习目标
- 目录结构
- 坐标系统
- 局部空间
- 世界空间
- 观察空间
- 裁剪空间
- 正射投影矩阵
- 透视投影矩阵
- 组合
- 进入3D世界
- 顶点数据
- 着色器
- 设置数据
- 矩阵设置
文章说明
本文是学习OpenGL的笔记,主要参考大神JoeyDeVries
的LearnOpenGL第八课《坐标系统》,并将教程中的代码基于Qt进行实现。
学习目标
- 掌握坐标系统中坐标空间以及转换矩阵相关知识
- 掌握如何使用坐标系统绘制图形
目录结构
|-
|-- HelloCoordinateSystems|--- hello_coordinate_systems.cpp|--- hello_coordinate_systems.h|--- main.cpp|--- CMakeLists.txt
|-- CMakeLists.txt
整个项目的全部CMakeLists.txt文件与上一篇《变换》中的内容基本一致,只需要将全部HelloTransformation替换成HelloCoordinateSystems就可以了。
坐标系统
在OpenGL中,坐标系统是图形编程的基础,理解它对于在屏幕上正确地绘制几何图形至关重要。OpenGL使用多个坐标系统来帮助开发者进行3D图形的绘制与变换。这些坐标系统包括本地坐标(或称物体坐标)、世界坐标、观察坐标、裁剪坐标和屏幕坐标。将物体的坐标变换到几个 过渡 坐标系(Intermediate Coordinate System)的优点在于,在这些特定的坐标系统中,一些操作或运算更加方便和容易。
为了将坐标从一个坐标系变换到另一个坐标系,需要用到几个变换矩阵,最重要的几个分别是 模型(Model) 、 观察(View) 、 投影(Projection) 三个矩阵。顶点坐标起始于局部空间(Local Space),在这里它称为局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束。
局部空间
局部空间是指 物体所在的坐标空间 ,即对象最开始所在的地方。不管这个物体移动了什么位置物体的局部空间都是(0,0,0)。你的模型的所有 顶点都是在局部空间中 ,它们相对于你的物体来说都是局部的。
世界空间
如果将所有的物体导入到程序当中,它们有可能会全挤在世界的原点(0, 0, 0)上,因此,需要为每一个物体定义一个位置,从而能在更大的世界当中放置它们。世界坐标空间是指 顶点相对于规定的世界的坐标 ,物体的坐标将会从局部变换到世界空间变换是由模型矩阵(Model Matrix)实现的,模型矩阵是一种变换矩阵,它能通过对物体进行位移、缩放以及旋转来将它置于它本应该在的位置或朝向。
观察空间
观察空间经常被人们称之OpenGL的 摄像机(Camera) 。观察空间是将世界空间坐标转化为用户视野前方的坐标而产生的结果。因此观察空间就是从摄像机的视角所观察到的空间。而这通常是由一系列的位移和旋转的组合来完成,平移/旋转场景从而使得特定的对象被变换到摄像机的前方。这些组合在一起的变换通常存储在一个观察矩阵(View Matrix)里。
裁剪空间
在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个特定的范围内,且任何在这个范围之外的点都应该被裁剪。被裁剪掉的坐标就会被忽略,所以剩下的坐标就将变为屏幕上可见的片段。这也就是裁剪空间(Clip Space)名字的由来。
如果需要被屏幕显示被看到,需要定义一个 投影矩阵(Projection Matrix) 投影矩阵定义了可视化的区域,这个区域称为 观察箱 或被称为 平截头体(Frustum) ,平截头体是一个有六个面、四个侧面和两个平行的底面(前面和后面)的几何体。这个几何体看起来像一个“锥体”被切去顶部的形状,两个平面分别称为 近平面和 远平面 ,两个平面之间的范围是可见范围。
投影矩阵可以为两种不同的形式包括:
- 正射投影矩阵(Orthographic Projection Matrix)
- 透视投影矩阵(Perspective Projection Matrix)
正射投影矩阵
把空间中的物体投射成某个平面的影像,把3D场景转换为2D平面图像,正射投影矩阵的平截头体看上去就像是一个立方体而不是锥体,类似于平行光把物体投射到地面,由于是平行光因此不会有近大远小的效果。
正射投影矩阵的设置需要指定 宽、高、远近平面距离 在Qt中设置如下(同glm):
void QMatrix4x4::ortho(float left, float right, float bottom, float top, float nearPlane, float farPlane);
- 设置正射投影矩阵
- left:视景体左边界在 x 轴坐标 0 的位置,可以设置成NDC坐标-1.0
- right:视景体右边界在 x 轴坐标 800 的位置,可以设置成NDC坐标1.0
- bottom:视景体下边界在 y 轴坐标 0 的位置,可以设置成NDC坐标-1.0
- top:视景体上边界在 y 轴坐标 600 的位置,可以设置成NDC坐标1.0
- nearPlane:近裁剪面距离观察者 0.1 个单位,在该平面之前的物体不会被渲染
- farPlane:远裁剪面距离观察者 100 个单位,在该平面之后的物体不会被渲染
透视投影矩阵
透视投影则会使物体在被渲染的时候更接近真实世界中看物体的样子即会产生近大远小效果,在Qt中设置如下(同glm):
void QMatrix4x4::perspective(float verticalAngle, float aspectRatio, float nearPlane, float farPlane);
- 设置透视投影矩阵
- verticalAngle:垂直方向的视野角度(Field of View,FOV),单位为度。该参数决定了相机垂直方向上能看到的范围大小。
- aspectRatio:视口的宽高比,即窗口宽度与高度的比值。这个参数用于确保渲染的图形不会因窗口的宽高变化而发生拉伸或压缩变形。
- nearPlane:近裁剪面距离观察者 0.1 个单位,在该平面之前的物体不会被渲染
- farPlane:远裁剪面距离观察者 100 个单位,在该平面之后的物体不会被渲染
透视投影矩阵的平截头体示意图如下:
组合
V c l i p = M p r o j e c t i o n ⋅ M v i e w ⋅ M m o d e l ⋅ V l o c a l V_{clip} = M_{projection} \cdot M_{view} \cdot M_{model} \cdot V_{local} Vclip=Mprojection⋅Mvie