聊聊我是怎麼開發軟渲染器的


3樓貓 發佈時間:2022-12-30 18:02:07 作者:煤問題 Language

本文首次發表於CG世界,內容經過重新編輯

介紹

大概是從去年8月份,我開始一邊自學圖形學一邊開發軟渲染器foolrenderer。除了模型加載用了開源代碼以外,其他所有功能都是自己開發的。目前實現了基本的光柵化渲染,還添加了可編程渲染流水線、基於物理的材質等功能。
foolrenderer演示了GPU的大致工作原理和一些實時渲染技術,可以作為遊戲開發者和圖形愛好者瞭解渲染基礎知識的學習性項目。大夥可以在Github上找到源代碼
使用自制渲染器得到的一些渲染結果
1 / 8
截取自視頻中的一些渲染結果
首先解釋一下什麼是軟渲染器?
軟渲染器(Software Renderer)是一類完全依靠軟件驅動,不使用圖形硬件加速的渲染器的統稱。原本集成在顯卡里的功能需要全部由開發者自己實現,軟渲染的速度也遠遠比不上利用了硬件加速的渲染器。雖然軟渲染器缺點很多,但也有一些實際應用場景:例如軟渲染器有很好的兼容性,一些系統上的圖形編程接口有軟渲染層作為硬件不兼容時的後備渲染方案;可以用軟渲染器實現一些顯卡不支持的功能,早期的光線追蹤就是純軟件實現的。

動機

雖然我之前一直在開發遊戲,但主要集中在玩法制作上,圖形方面的知識其實瞭解的不多,這就導致我在製作遊戲的時候遇到不少問題。比如,色彩貼圖一般要用sRGB空間,為啥金屬度、法線這類貼圖不用;PBR材質裡常說的分佈函數是個啥,什麼是GGX。諸如此類,看了網上的解釋還是雲裡霧裡。還有個問題是不會寫著色器,很多視覺效果需要自定義的著色器實現,但我一直不熟悉渲染流水線,對著教程也寫不出來。
所以我慢慢覺得有必要了解一些計算機圖形的概念,於是乎開始找相關資料學習。經過了解之後發現,圖形學的基礎原理並沒有想象中那麼複雜,用學到的知識完全可以自己寫一個軟渲染器。我覺得邊學邊做個小軟件挺有意思的,連帶這樣學稍微更有動力一點,所以就決定開發一個基於光柵化算法的軟渲染器,也就是現在的foolrenderer項目。
foolrenderer的開發過程(模型作者Suushimi)

foolrenderer的開發過程(模型作者Suushimi)

開發過程

因為是邊學邊做,所以foolrenderer的開發是按照自學進度走的,我學到哪裡就給程序添加相應的功能。
首先就是為foolrenderer實現三角形光柵化功能,用人話說就是把三角形繪製到屏幕上。原理很簡單:檢查屏幕上的每一個像素,如果像素剛好落在三角形裡面,就給這個像素設置對應顏色。當然了,每畫一個三角形都要檢查屏幕上的所有像素顯然沒有必要,最簡單的優化方法是隻檢查三角形所在的矩形範圍內的像素。
有了三角形光柵化,我接著添加了插值功能。接觸過三維軟件的老哥都知道,模型是由一個個點構造的三角形組成(多邊形可以分解成若干個三角形)。這些點就叫頂點,頂點除了包括這個點的位置信息外還可以存儲顏色、UV座標、法線等等其他數據。插值說的就是把三角形三個頂點的數據均勻的過渡到三角形表面上。舉個例子,如果三角形頂點都是紅色,插值會得到一個紅色三角形;如果三角形頂點分別是紅、綠、藍,經過差值得到的三角形呈現漸變色,越接近綠色頂點的地方顏色也越接近綠色。
三角形光柵化以及頂點顏色差值

三角形光柵化以及頂點顏色差值

到這裡就已經可以渲染一個簡單的模型了,只需要讀取模型文件裡的數據,然後一個個的把三角形畫出來就行——當然事情也沒有這麼簡單,得到的結果還有很多問題:比如,程序沒有考慮三角形的前後位置關係,模型背面的三角形可能擋住前面的三角,那就用深度緩衝記錄每個像素的前後位置,不畫靠後的面;渲染器肯定要有調整模型位置大小的功能,還要模擬人眼近大遠小的透視觀察效果。這就需要利用線性代數提供的數學工具修改頂點位置;還應該給foolrenderer開發一個可編程渲染流水線,這樣才方便給模型添加貼圖和光照效果。
從這兒就可以看出來,圖形學的各種技術就是在討論現有方案存在的問題時自然而然發展起來的,非常符合直覺。這裡我要特別推薦《Tiny renderer》這個教程,內容就是在教你怎麼開發一個最基本的軟渲染器,非常適合沒有基礎的菜鳥學習,這個教程也算是一個讓我開始寫軟渲染器的契機。
《Tiny renderer》可以手把手教你渲染個人頭

《Tiny renderer》可以手把手教你渲染個人頭

上面提到,渲染模型時要對所有頂點做位置變換,這需要提供相應的線性代數函數。網上現成的代碼有很多,但本著儘量自己做的原則我還是自己寫了一套。《線性代數的本質》是我找到的一個不錯的入門視頻,如果還有高中數學的那點底子,看這個視頻就不成問題。一共只有十幾集,每集平均10分鐘,作者講解的非常清楚,看完以後應付圖形方面的問題足夠了。
一番折騰foolrenderer逐漸像模像樣起來,能真正能稱得上是個渲染器了。在這個基礎上可以開始添加一些常見的實時渲染技術,像什麼法線貼圖、陰影、基於物理的渲染等等。當然難度也開始慢慢變高了。實際開發這些功能後才發現,我們經常在軟件中使用的技術,其實遠比看起來的要複雜。
使用PBR材質渲染得到的小提琴(模型作者Virtual Museums of Małopolska)

使用PBR材質渲染得到的小提琴(模型作者Virtual Museums of Małopolska)

印象比較深的是計算頂點的切線向量,用切線空間的法線貼圖時就要用到切線。乍一看計算切線很簡單,按照推倒的公式算就行。但琢磨一下會發現不對勁的地方——一個頂點可能會被多個三角形共用,怎麼計算平均切線就有很多方法了。如果建模軟件用的方法和遊戲引擎中的不一樣,通過法線貼圖計算得到的最終法線就會有區別,渲染結果就會有差異。為了避免差異,有人甚至提出計算切線的標準,MikkTSpace就是一種算法,實現方式非常複雜。
常用的法線貼圖技術其實比看起來的要複雜(圖片來自Tiny renderer)

常用的法線貼圖技術其實比看起來的要複雜(圖片來自Tiny renderer)

總之製作一個軟渲染器算是不錯的學習經歷。開發的時候有個體會:找到合適的資料也挺費功夫的,同一內容的類似資料能在網上找到很多,只能都看看,橫向比較一下才能知道好壞。我把找到的資料整理成了一個清單,希望對那些想要充電的朋友多少有點幫助。
開發foolrenderer時收集到的資料

開發foolrenderer時收集到的資料

後續打算

foolrenderer算是完成了嗎?emmm從功能上來說恐怕還有很長一段距離,目前這個軟渲染器只能說還很基礎,甚至一些技術已經在現有的生產力工具裡淘汰了。
隨便舉個例子,光是紋理這項功能到目前還只能用“殘疾”來形容,最基本的雙線性差值和Mipmap都沒有,所以能在渲染的動畫裡看到明顯的走樣。更別提其他一些常見優化手段,更高級的全局照明,都還沒來得及加進去。
同樣的,圖像方面的學習也才剛剛開始,繼續練級唄還能咋整啊?

© 2022 3樓貓 下載APP 站點地圖 廣告合作:asmrly666@gmail.com