
推薦直接閱讀博客原文,更新更及時(shí),閱讀體驗(yàn)更佳
如果你覺得我寫的不錯(cuò),就給我個(gè)點(diǎn)個(gè)贊吧??!謝謝你,這對(duì)我真的很重要!
「十天自制軟渲染器」這個(gè)標(biāo)題我承認(rèn)標(biāo)題黨了.在對(duì)圖形學(xué)一無所知的情況下想十天自制一個(gè)軟渲染器,就好似一節(jié)課沒上過卻試圖一個(gè)晚上看完《30 天精通 C++》然后第二天早上八點(diǎn)考試得滿分一樣,我承認(rèn)世界上有這種天才,但很可惜我不是。
就像前文所說,本系列造的輪子都是站在巨人的肩膀上完成的,需要對(duì)相關(guān)知識(shí)有一定的了解和學(xué)習(xí),如果你是一個(gè)圖形學(xué)大牛,這種軟渲染器肯定是不屑于做的;如果你剛剛進(jìn)入圖形學(xué)的大門,造一個(gè)軟渲染器的輪子,非常利于你鞏固自己的底層知識(shí)。
<br />
本文主要(90%)參考 ssloy 大神的 tinyrenderer 教程,零依賴實(shí)現(xiàn)一個(gè)軟渲染器,通過這個(gè)教程可以實(shí)現(xiàn)一個(gè)簡(jiǎn)易版本的 OpenGL2.0(即 rendering pipeline 只支持 Vertex Shader 和 Fragment Shader 兩種自定義 Shader 類型),了解 OpenGL 這類圖形學(xué) API 在底層是如何工作的。
我自己造的輪子是 toyRenderer,在 tinyrenderer 的基礎(chǔ)上加入了大量的注釋并按自己的理解優(yōu)化了部分代碼(不排除有反向優(yōu)化),如果大家對(duì) tinyrenderer 感興趣,可以參考一下我的實(shí)現(xiàn)和我現(xiàn)在寫的這個(gè)教程,點(diǎn)個(gè) star ?? 就更好不過了~
本專欄的目錄結(jié)構(gòu)和 tinyrenderer 保持一致,方便大家對(duì)比閱讀。
<br />
前置知識(shí)
要想看懂 tinyrenderer 的代碼,需要有一定的知識(shí)儲(chǔ)備,下面是我在造輪子時(shí)的一些總結(jié),大家學(xué)習(xí)前可以參考一下。
1.數(shù)學(xué)
對(duì)于圖形學(xué)來說,數(shù)學(xué)是一道繞不過的坎兒;對(duì)于這個(gè)軟渲染器器輪子來說,并沒有涉及太多的數(shù)學(xué)內(nèi)容,我個(gè)人總結(jié)如下:
1.1 高中數(shù)學(xué)
造一個(gè)軟渲染器需要你還記得一些高中幾何的內(nèi)容,難度都不大,比如說直線的坐標(biāo)公式,重心坐標(biāo)等。
1.2 微積分
微積分其實(shí)只有少量的涉及,原教程里有一點(diǎn)點(diǎn)梯度的內(nèi)容,個(gè)人感覺對(duì)整體學(xué)習(xí)進(jìn)度影響不大。
1.3 線性代數(shù)
線性代數(shù)涉及的內(nèi)容比較多,從最簡(jiǎn)單的向量,再到各種坐標(biāo)系變換,都需要對(duì)線性代數(shù)有比較扎實(shí)的理解。
如果你線性代數(shù)都忘的差不多了,這里我推薦 3Blue1Brown 的教程——《線性代數(shù)的本質(zhì)》,這是我見過最好的線性代數(shù)入門教程了。而且圖形學(xué)里涉及的矩陣變換絕大部分都是三維空間的,基本上看完這門課就可以上手圖形學(xué)的學(xué)習(xí)了。
<br />
2.圖形學(xué)
圖形學(xué)入門課程我只推薦一個(gè),閆令琪大神的《GAMES101-現(xiàn)代計(jì)算機(jī)圖形學(xué)入門》。
閆令琪大神有多厲害我就不多介紹了,最關(guān)鍵的是 GAMES101 優(yōu)點(diǎn)太多了:
- 全中文講解,大大降低國(guó)內(nèi)小伙伴的學(xué)習(xí)門檻
- 課程非常新,2020 年初才開課,不會(huì)存在課程/教案過時(shí)的情況
- 知識(shí)點(diǎn)全面,正如課程名「現(xiàn)代圖形學(xué)入門」,本課程不但講了經(jīng)典的光柵化成像,還講了光線追蹤等相對(duì)較新較前沿的內(nèi)容
學(xué)完這門課可以收獲什么呢?比如說 2077 的圖形設(shè)置面板你都知道是啥意思了
如果跟著這門課學(xué)下來,其實(shí)課下作業(yè)就會(huì)完成一個(gè)小的軟渲染器,但由于我是后期才加入學(xué)習(xí)的,所以作業(yè)也沒有跟著做,經(jīng)過搜索發(fā)現(xiàn) tinyrenderer 這個(gè)教程推薦的人最多,所以最后參照這個(gè)教程實(shí)現(xiàn)了自己的軟渲染器。
閆老師的是視頻教程,大家可以配合他的 PPT 學(xué)習(xí)。如果習(xí)慣看書,我這里推薦兩本,一本是大名鼎鼎的虎書《Fundamentals of Computer Graphics 4th Edition》,另一本是《Real Time Rendering 4th》,都是非常經(jīng)典非常有名的書籍。
這兩本書國(guó)內(nèi)都沒有引進(jìn),我這里有英文版的 PDF,大家可以看我個(gè)人簡(jiǎn)介,關(guān)注「鹵蛋實(shí)驗(yàn)室」后回復(fù)「圖形學(xué)」獲取下載鏈接。
<br />
3.C++
本渲染器是用 C++ 寫的,但用到的都是基礎(chǔ)語法,稍微高級(jí)點(diǎn)兒的知識(shí)就是模版編程和操作符重載。個(gè)人認(rèn)為只要有其他語言基礎(chǔ),看個(gè)半小時(shí)的 C++ 語法就可以上手實(shí)踐了。
<br />
如果上面的三個(gè)知識(shí)點(diǎn)都掌握的差不多了,我打保票十天內(nèi)肯定能寫出一個(gè)軟渲染器;如果沒有掌握好(尤其是圖形學(xué)基礎(chǔ)知識(shí)),十天內(nèi)實(shí)現(xiàn)是有些夠嗆。廢話不多說,我們先去搭環(huán)境吧!
本教程要做的是一個(gè)零依賴的軟渲染器,所以依賴的環(huán)境就是 C++ 的開發(fā)環(huán)境。
注:零依賴意味著這個(gè)項(xiàng)目不依賴任何第三方庫,軟渲染意味著所有計(jì)算都是在 CPU 側(cè)進(jìn)行的,沒有 GPU 參與
C++ 環(huán)境搭建配置有多種方法,最快捷的方式就是直接用高度集成的 IDE,win 電腦可以用 Visual Studio,Mac 用戶可以用 Xcode。當(dāng)然你也可以用 CMake + VSCode 搭建 C++ 運(yùn)行環(huán)境。
我這個(gè)人很懶,平常開發(fā) Xcode 用的又比較多,不想多折騰了,所以直接用 Xcode 構(gòu)建項(xiàng)目了,小伙伴們千萬不要學(xué)習(xí)我這種壞習(xí)慣。
Xcode 創(chuàng)建 C++ 項(xiàng)目
1.新建項(xiàng)目
1.Xcode 創(chuàng)建 C++ 項(xiàng)目非常簡(jiǎn)單,啟動(dòng) XCode 后點(diǎn)擊 Create a new Xcode project,創(chuàng)建一個(gè)新項(xiàng)目
<br />
2.在跳出的彈框里選擇 Command Line Tool,然后點(diǎn)擊 Next
<br />
3.在新的彈窗里填寫好 Product Name,Language 選擇 C++,然后點(diǎn)擊 Next
<br />
4.在新的彈窗里選擇項(xiàng)目路徑,點(diǎn)擊 Create 創(chuàng)建項(xiàng)目
到這里項(xiàng)目就創(chuàng)建好了。
2.配置相對(duì)路徑
軟渲染器需要對(duì)硬盤上的一些文件做一些 IO 操作,這時(shí)候就需要配置項(xiàng)目的相對(duì)路徑。
首先按照 Product -> Scheme -> Edit Scheme 的次序,打開一個(gè)彈窗。
然后在彈窗里勾選 Using custom working directory,并選擇項(xiàng)目文件所在路徑就可:
3.把源代碼拖進(jìn)去
因?yàn)楸卷?xiàng)目是零依賴的,渲染方式是根據(jù)源代碼生成一張 tga 格式的圖片。因?yàn)槲覀兪莵韺戃涗秩酒鞫皇菍憟D片編碼器的,所以直接把源代碼里的 tgaimage.h 和 tgaimage.cpp 拖到我們的項(xiàng)目工程里就可以了。
加上 main.cpp,現(xiàn)在的工程目錄里只有三個(gè)文件
.
├── main.cpp
├── tgaimage.cpp
└── tgaimage.h
然后我們?cè)?main.cpp 里寫一些簡(jiǎn)單的代碼——?jiǎng)?chuàng)建一個(gè) 100x100 的圖片,在 (52, 41) 這個(gè)坐標(biāo)上畫一個(gè)紅的的點(diǎn)(rgb(255, 0, 0))
#include "tgaimage.h"
const TGAColor red = TGAColor(255, 0, 0, 255);
int main(int argc, char** argv) {
TGAImage image(100, 100, TGAImage::RGB);
image.set(52, 41, red);
image.flip_vertically();
image.write_tga_file("output/lesson00.tga");
return 0;
}
點(diǎn)擊 Xcode 左上角三角形的 build 按鈕,如果編譯成功并在 output 這個(gè)文件夾下生成一張名為 lesson00.tga 的圖片,就說明環(huán)境配置成功了!
(紅點(diǎn)只有一個(gè)像素大,看不清可以點(diǎn)擊查看大圖)
<br />
<br />
今天在圖片上畫了一個(gè)點(diǎn),明天我們就學(xué)習(xí)一下如何高性能的畫一條直線。
如果你覺得我寫的不錯(cuò),就給我個(gè)點(diǎn)個(gè)贊吧??!謝謝你,這對(duì)我真的很重要!