關於計算機圖形學的一些介紹(一)基本要素與空間變換

w4ngzhen發表於2024-07-31

寫在前面

筆者前段時間開啟了一個新的系列《Wgpu圖文詳解》,在編寫的過程中,發現使用wgpu只是應用層面的內容。要想很好的介紹wgpu,不得不將圖形學中的一些理論知識進行講解。但是放在《Wgpu圖文詳解》這個系列裡又有點喧賓奪主之意,所以決定單獨用另一個系列來放置關於圖形學的一些內容。另外,本系列的內容並不是按照某種順序來編寫的,而是想到哪些要點就介紹一些,算是帶有科普性質的知識筆記。

筆者並非圖形學專業人士,只是將目前理解到的一些內容整理成文,如有內容上的問題,還請讀者指出。

本文內容主要為概念介紹,所以不會有程式碼產生。

三維世界基礎

我們都知道,兩點組成一直線,三線(三點)組成一平面。所以,假設在三維空間中有這樣三個點:(0, 1, 0)(-1, 0, 0)(1, 0, 0),透過簡單的思考,我們知道它們可以組成一個沒有厚度的三角形,當然,我們可以使用更多的點組成更多的面,來創造一個更加立體的物體:

010-things

對於一個三維空間的物體,我們一般分為兩個階段來“感知”它。

第一階段是“創造”這個物體。我們首先在空間的某處定義好一些“頂點”;然後,透過將這些“頂點”兩兩直線相連,我們會得到一個物體的框架;最後,我們給框架上的每一面“糊”上一層“紙”,就得到了一個不透明的立體物體。

020-cube

第二階段則是“觀察”這物體。在第一階段,我們僅僅是將一個三維物體創造了出來,它存在於空間的某處。為了讓我們感知到它的存在,我們會用眼睛從某些角度去看它,或使用一臺攝像機將它拍攝並呈現在一張照片上。但無論哪種方式,我們會發現我們都將一個空間中三維的物體“投射”一個“面”上,即將三維物體“降維”到了二維面上。

當然,將三維物體投影到二維平面上,一般有兩種投影方式:正射投影、透視投影,二者最大的區別在於透視投影需要考慮近大遠小的成像機制。例如,上圖的立方體場景下,我們在站在z軸上俯看立方,正射投影和透視投影會出現不同的效果:

030-projection

從上圖可以看出,透視投影明顯是最符合我們通常認知的投影方式。對於三維世界有了基本的認識以後,讓我們接下開始對圖形學的一些內容進行介紹。

圖形學的要素

在上節中,我們簡單介紹了在現實的三維世界中如何構造並觀察到一個三維物體。在計算機圖形學中其實也並沒有完全的跳出這個過程。在計算機圖形學中同樣會有點、線、面,以及最終要呈現到螢幕上的“投影”。我們將從本節開始,深入淺出計算機圖形學的一些重要概念以及它們的核心作用。

頂點 vertex

什麼是頂點?讀者初識“頂點”這個詞的時候,可能會覺得“頂點”就是上面三維物體在構建過程的第一步中,我們進行定義的各個“點”。這樣的理解對但不完全對,因為幾何物體上的各個點是狹義上的頂點,它們僅僅表示三維空間中的一些位置。

040-only-points

而計算機圖形學中的頂點vertex,則是一個包含有更多內容的資料合集,包括不限於該點的:位置座標、顏色資訊等(為了不然讀者產生過多的疑惑,我們先只提較為理解兩個屬性)。也就說,幾何中的頂點幾乎等同於位置座標,而計算機圖形學中的頂點,除了位置座標以外,還可以包含該點的顏色等其他資訊。

050-vertex-more-info

讀者一定要記住,從現在開始,只要談到了“頂點”,都指的是包含位置、顏色以及其他額外資訊的整個頂點資料,如果僅僅是描述位置,我們一定使用全稱:“頂點位置”。

頂點包含顏色資料的意義是什麼?筆者在第一次接觸計算機圖形學的時候,能夠很自然的理解頂點包含位置座標資料,但是對於包含顏色資訊(甚至是法線資訊等)百思不得其解,直到後來瞭解的越來越多以後,才漸漸的理解了這其中的奧妙。當然,這裡筆者先賣個關子,等到後續的圖元、片元介紹完成以後,再回過頭來就能夠很好的理解了。

圖元 primitive

在計算機圖形學中,圖元(Primitives)是構成影像的基本元素,它們是圖形渲染過程中最基礎的幾何形狀。圖元可以是點、線、多邊形(如三角形或四邊形)等。

圖元裝配

要得到圖元,我們需要將上一小節介紹的“頂點”作為輸入,進行一系列的操作,才能得到圖元,這個過程就叫做圖元裝配。讓我們用更加形象的例子來理解這個過程。

假設現在有三個點:(0, 1)(-1, 0)以及(1, 0)。這三個點可以組成什麼圖形呢?需要我們用不同的方式來看:

  1. 點方式(Points):每個頂點都作為一個單獨的點來渲染。
  2. 線方式(Line):連續的兩個頂點形成一條線段。
  3. 三角形方式(Triangles):每三個頂點組成一個三角形。

下圖是上述三種方式下,結合上面三個點得到圖形結果:

060-point-line-face

圖元裝配還遠遠不止上述提到的三種方式,根據頂點資料的不同,還有其他形式的裝配方式

所以,讀者現在應該能夠理解圖元裝配的核心邏輯是,將n個頂點透過某種圖元裝配的方式來得到最終的圖形(不同的裝配方式往往伴隨著不同的演算法邏輯)。

當然,在生成圖元的時候,還包含了一些操作,不過為了幫助讀者更好的理解,我們暫時放一放,後面統一講解。

片元 fragment

在介紹片元前,我們需要先提到一個操作概念:光柵化。光柵化是將幾何資料經過一系列變換後轉換為畫素,並呈現在顯示裝置上的過程。我們常見的顯示裝置是由物理畫素點按照一定的寬高值組成一塊完整的螢幕。也就是說,螢幕上的畫素點不是“連續”的。然而,我們的影像是“連續”的,這就意味著對於幾何圖形,一條線,特別是非水平非垂直的線,這條線上的每一點我們總是需要透過一定的近似處理,來得到其在螢幕上的物理畫素的座標。

我們以呈現一個三角形為例。假設現在有下圖三角形,從幾何的角度來看,它的斜邊沒有任何的異常:

070-a-triangle然而,我們的物理裝置畫素是整數值且有限,假設有一塊解析度為 20x20 的螢幕,為了呈現斜邊,我們可能需要按照如下的形式來找到對應的畫素點填色:

080-rasterization-triangle

注意看,筆者在幾何三角形上選取了1個點,幾何座標為(0.5, 0.5)。在 20x20 的螢幕上,其螢幕座標為(10, 10)

光柵化邏輯就是對於幾何圖形上每一個“點”,在螢幕裝置上找到對應的畫素點的過程。對於光柵化的實現,就不在本文的討論範圍內了,對於這塊感興趣的同學可以自行查閱相關資料進行深入研究。

簡單瞭解完光柵化後,讓我們回到本節的核心:片元fragment。片元實際上就是圖元primitive經過光柵化處理後的一個或多個畫素大小的樣本。在這有兩點值得注意:

  1. 儘管叫做片元,但通常指的是一個或少許多個畫素大小的單位。也就是說,圖元是一個整體幾何圖形,經過光柵化會被分解為多個片元。
  2. 光柵化後得到的片元只是接近畫素點,但並不完全等於畫素點。片元是與畫素相關的、待處理的資料集合,包括顏色、深度、紋理座標等資訊(深度和紋理座標等先簡單理解為一些額外資料,後續會講解)。這個地方有點類似於前面我們說的,圖形學中的頂點,並不是簡單的幾何的頂點,而是包含有頂點位置、顏色資訊等的一個資料集合。

片元並非畫素點,它只是接近畫素點,所以通常來說,我們還會有一個步驟來對片元進行進一步的處理,好讓它最終轉換為螢幕上的畫素點來進行呈現(此時基本就是帶有rgba顏色的點了)。

至此,我們簡單瞭解了圖形學中的三個要素:頂點、圖元與片元。本來,接下來的內容應該介紹渲染管線了。但是筆者思考以後始終覺得,直接搬出一些概念,還是不夠直觀,初學者很容易被勸退。所以在介紹渲染管線之前,筆者決定先介紹一下在圖形學中的空間變換。

圖形學中的空間變換

模型空間與世界空間

假設我們製作了一個邊長為2的立方體,如下圖所示:

090-simple-cube-model

此時,這個立方體我們是在當前座標系中建立出來的。所以它的各個點的位置就如上圖所示(例如圖中標識的三個點:(1, 0, 1)(1, 1, -1)以及(-1, 1, 1)等)。

隨後,我們將這個立方體放置到一個“世界”場景中,在此之前,“世界”場景中已經有了一個球體:

100-a-ball-in-world

為了不讓他們重疊,我們將這個立方體先將邊長從原來的2縮小到1個單位,然後放置到如下位置:

110-cube-and-ball

注意看,此時我們的立方體的座標在此刻與球體共存的世界中的ABC三個點的座標就不再是原有的座標,而是在這個“世界”下的座標(A(3, 0.5, -0.5)B(3, 0, 0.5)C(2, 1, 0.5)),這個過程,其實就是將“模型空間”轉換到“世界空間”(的座標)的過程。

“模型空間”的意義是每個三維物體本身在自己的一個空間座標系下(又叫“區域性座標空間”),我們去定義這個物體的三維資料的時候,不依賴於外部,而是一個純粹的當前物體的一個空間。

然而,我們將一個物體創造好以後,我們一般都需要將它放置到一個和其他的物體在一起的一個地方,組成一個場景,使之更有意義,而這個地方就是“世界空間”,在這個過程中,我們一般會對某個單獨的模型物體進行旋轉、縮放等操作,以便讓它更加協調的存在於這個“世界空間”中。

觀察空間

當得到世界空間下的座標的時候,我們會進一步將其變換為“觀察空間”。介紹“觀察空間”前,我們需要先引入一個角色:攝像機。既然我們已經將“世界”準備好了(例如上面的一個立方體加上一個球體的場景),我們總是需要“觀察”它,不然就沒有意義了。因此,我們就會需要一個類似“攝像機”的角色。這個攝像機會包含有3個要素:1、攝像機的位置;2、攝像機看向的目標方向;3、攝像機的向上方法。對於攝像機的位置和看向的目標方向容易理解,對於攝像機的向上方向,用下面的示例應該也很好理解了:

120-camera-direction

上圖中,我們首先在空間的某處放置一個攝像機,讓它“看向”一棵樹,我們使用藍色向量表示出這個方向;透過這個藍色的向量的方向和攝像機所在的位置,我們可以確定唯一一個讓藍色向量垂直的平面。在這個平面上, 我們可以找到無限組相互垂直的向量(例如上圖左右兩個攝像機的的紅、綠色向量,我們可以繞著藍色向量方向轉動,還能得到更多的紅、綠向量),其中,我們會把紅色的向量定義為攝像機的右向量,那麼垂直於紅、藍向量平面的綠向量就是向上的向量。攝像機向上方向的不同,會導致影像攝像機拍攝的物體的向上方向不同。

注意,這裡的紅綠藍向量,其實和一些教程(例如《[攝像機 - LearnOpenGL CN (learnopengl-cn.github.io)](https://learnopengl-cn.github.io/01 Getting started/09 Camera/)》)是不太一致的。本文只是從現實出發,使用一種容易理解的方式來介紹概念,並不是完全的考慮計算層面的事情。

有了確定的攝像機以後,我們需要進行這樣的操作。將攝像機和整個世界做一次整體的位移操作,讓攝像機移動到原點,觀察方向與Z軸重合,上方向與Y軸重合,同時讓“世界”中的物體保持與攝像機相對不變:

130-camera-transform

140-camera-transform-animation

在完成移動以後,原先的物體的座標在攝像機處於原點的座標空間下有了新的座標位置(例如,原本我們的球體最頂部的點座標是(0, 2, 0),經過將世界空間轉變為觀察空間,就成了(0, 2, -2)),而這個過程就是“世界空間”轉變為“觀察空間”,攝像機處於原點的座標空間就是“觀察空間”。

為什麼有觀察空間?因為將攝像機放到原點的過程後,對於後續的觀察投影處理很方便。

經過一系列的操作,我們已經將一個2x2x2的立方體,從模型空間變換到了觀察空間:

150-point-transform-flow

注意看上圖立方體A點的左邊經過一系列變換的結果

在觀察空間的基礎上(此時攝像機就在觀察空間的原點),我們就會開始進行投影處理。正如一開始介紹的,投影一般來說分為兩種:1)正射投影;2)透視投影。

對於上面我們建立的球體和立方體,攝像機放在原點,分別使用正攝像投影和透視投影的效果大致如下:

160-projection

容易理解的是,經過投影以後,我們將三維立體的物體轉變為了二維影像。原先三維空間中任意一個點,都“投射”到了二維空間上。如果我們將這個二維空間視為我們的顯示器螢幕。那麼很顯然,我們需要將“觀察空間”中某一個三維座標點透過一定的方式的計算變換,得到在螢幕上某個具體位置的畫素。

170-projection-to-screen

對於上圖,原本在觀察空間中的點A的座標,會透過一定的上下文(攝像機的距離、FOV視野等)透過一定的資料計算,來得到A',而這個A'是螢幕上的某個x、y均為整數的畫素座標。

寫在最後

本文就大致介紹關於圖形學中的一些基本要素,以及空間變換。在後面的文章中,會逐步介紹計算機圖形學中的一些內容,例如渲染管線等。

相關文章