從零開始實現3D軟光柵渲染器 (1) 簡介

如何在2D屏幕上表示3D物體?這是學習3D編程必須要搞明白的事情。大家都知道,調用OpenGL的函數,給定三角形的3個頂點位置,顏色,就能在屏幕上畫一個三角形,再加載一幅圖片,就可以給這個三角形附上紋理,還能讓這個三角形繞某個座標軸發生旋轉… 這些看似簡單的問題的背後,實則是3D編程的內功。大家都知道,學武之人,拼的是內力,花裏胡哨的招式的確很博人眼球,但是從長遠來看,收益遠沒有修煉內力高。

而一個軟光柵渲染器幾乎涵蓋了所有的3D渲染知識,從本篇開始,我們將從零開始實現一個3D軟光柵渲染器,學習3D渲染背後的數學原理。

光柵化

所謂光柵化就是將你想畫的東西轉換到2D屏幕上的像素的過程。這個過程涉及到很多光柵化算法,比如說,畫一條直線,大家都知道直線的方程:y = k * x + b (斜截式) 這裏的 x , y 的取值範圍是全體實數,但是屏幕是像素組成的,你要想在屏幕上顯示,你就得使用一些算法將這些實數集映射到相應的像素集(離散化)。

3D流水線

光柵化是OpenGL渲染流水線的一個階段,而這個階段是由GPU完成的。一方面,由於現在很多成熟的光柵化算法已經被集成到GPU中,基本不用開發人員手動實現了。另一方面,由於GPU具有很強的並行計算能力,相比在CPU中實現這些算法,圖形的渲染會大大提升。

那麼什麼是渲染管線呢?你可以想象一下iphone的生成車間,先製作地板,然後焊接電路,再安裝電池…這就是一條流水線。3D編程中,將物體最終顯示到屏幕上也要經歷類似的過程。

我們以遊戲開發爲例,簡單介紹一下這個流程:

首先,我們需要一個座標系來描述場景中各物體的位置,否則你根本無法確定遊戲角色、道具等的位置,這個座標就叫世界座標。就像它的名字那樣,我們可以把它理解成描述我們構建的3D世界的座標系,它是唯一的,它是固定不變的。

而我們的遊戲模型一般都是在3D軟件中創建的,一般建模的時候,也需要一個座標系用來描述各個頂點的位置,這就是局部座標系。如下圖就是blender中的局部座標系,順便說一下,它是右手座標系,紅綠藍三個箭頭分別對應x,y,z三個座標軸。局部座標系的原點一般是由建模者設置的,比如建一個遊戲人物的模型,有的人喜歡把局部座標系的原點放到模型雙腳中心,而有的人喜歡把它放在角色的腰部位置,這都是可以的。

一個遊戲場景一般包含很多模型(房屋,角色,道具,樹木 etc.),而要將這些分別來自不同建模者的模型繪製到同一個場景(同一個世界座標系)中來,就需要進行座標變換。沒有找到合適的模型,就拿我珍藏的一張合影來舉個例子吧。一圖勝前言,不需要解釋。

好了,現在模型們已經變換到世界座標系了。你玩遊戲的時候,是不是可以控制人物走動,走到不同的位置,會看到不同的景象?此時,你看到視圖,是有一個叫攝像機的東東控制的,又叫虛擬相機。這其實是一個概念,就是爲了方便觀察世界座標系中而抽象出來的一個模型(這裏的模型是一種概念上的模型)。即使不同攝像機,我們照樣也可以觀察世界座標系中各個物體,這個我們在後面介紹。現在你只要知道,有一個叫攝像機東西,我們可以很方便的通過控制它來觀察世界座標系中的物體。此時,我們看到的物體是相對攝像機的位置而言的。比如,你拿手機拍照的時候,雖然你拍的是上海的東方明珠,等你拍下來了,就是你手機上的東方明珠,同一個物體,只是描述的方式不同,這個好好品一下。爲什麼這麼幹,我們以後再說。

現實世界是3D的,而計算機屏幕是2D的。我們怎麼將3D的世界繪製到2D的屏幕上呢?此時,我們就需要選擇一種投影算法,將3D世界中的座標點投影到2D屏幕上。

3D渲染最注重的就是效率。我們其實只要繪製我們人眼能看見的東西就好了。一個三角形,其實是有2個面的,一般在某一時刻,我們只能看到一個面,所以,另一個面就不需要繪製了。比如,一個精細的人物模型,可能有幾千萬個三角形構成的,而我們只能看到遊戲人物的外表,其內部的三角形面片其實就不用繪製了,因爲沒人看。

到這裏,我們就已經拿到了要進行繪製的頂點數據了。接下來,就是前面說的進行光柵化操作了。也就是說,我給你一堆頂點以及頂點之間的連接關係,你要能夠在屏幕上正確顯示出來(決定到底屏幕上哪些像素被着色,哪些不被着色)。假設我就繪製一個三角形,給3個頂點,光柵化的過程,就是將這三個頂點之間的連線映射到屏幕上相應的像素,如果給了顏色信息,還要給三角形區域着色。到這裏,就能夠在屏幕上現實3D圖形了。

接下來,就是一些優化操作了,比如各種測試(像素包含測試、裁剪測試、alpha測試、模板測試、深度測試 etc.)、混合操作等,反正目的就是提升性能、優化渲染效果。

這就是大概的3D渲染流水線。我們的軟光柵渲染器就是要自己編碼實現這一套流程,這樣在調用OpenGL函數的時候,你才知道它背後到底發生了什麼,當你遇到問題的時候,你纔有能力嘗試猜測可能什麼地方出了問題。

開發環境

最後,說一下開發環境。因爲我們是學習3D渲染流水線,這個本身已經夠複雜了。爲了能把注意力放到軟光柵的實現上,我們的開發環境越簡單越好,所以,我們選擇JavaScript開發一個Web-based軟光柵渲染器,開發環境VS code,記事本也可以。

其實,只要你掌握了這一套流程,隨便什麼語言,只是顯示環境不同,核心原理都是相同的。對着我們的教程,你完全可以實現其他語言的軟光柵渲染器。

歡迎大家關注我的公衆號【OpenGL編程】,定期分享OpenGL相關的3D編程教程、算法、小項目。歡迎大家一起交流。

OpenGL編程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章