文章目錄
- 文章說明
- 學習目標
- 目錄結構
- 坐標系統
- 局部空間
- 世界空間
- 觀察空間
- 裁剪空間
- 正射投影矩陣
- 透視投影矩陣
- 組合
- 進入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