
z-buffer
簡單光
我們現在先複習一下,我們經過了畫點、畫線,填三角形之後已經能畫出來一些東西了,現在我們有好幾條路可以走,那就是
- 光(上帝說“要有光”)
- 紋理(不然就填白色和随機顔色麼?)
- 數學(之前做的所有事情就是簡單的把x,y對應的畫到圖像上來)
這裡我們做的事就是簡單的給我們的模型一點‘方向光’,注意我這裡說了一專有名詞‘方向光’,是以還會有别光(暫且不表)。方向光就是類似太陽光一樣的,我們隻考慮它的方向:
對于一束光,我們到達物體表面的能量實際上是:
它的強度 Icosα, α是物體光與物體的法向量的夾角。
如果我們用
表示光的方向,
指向物體光照處'向内的'法向量,那麼
這裡我們就必須要考慮一些數學問題了,物體我們放在這,然後有光的方向:
那麼'朝内的'法向量可以這樣得到
,然後正交化:
這裡我們先做很多簡化操作:
- 光的方向是 Vec3f light(0, 0, -1), 強度就是1
- 假設每個三角形收到光照的強度相同,都是 Icosα
- 三角形法向量
重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer - 當然我們還要知道 cosα 大于0才有意義,我們不可能減去光o(╯□╰)o
核心代碼:
Vec3f
看效果:
媽媽他是凸嘴。我們換一個光的方向。
更吓人了。。。。他嘴巴怎麼長後面了。。
simplelightgithub.com
compile & run:
$ g++ -std=c++11 main.cpp tgaimage.cpp model.cpp -o main
$ ./main
z-buffer
造成這個問題的原因很簡單,我們就是一股腦的把三角形畫出來了,沒有考慮三角形的先後順序,正如畫畫一樣,我們應該先畫遠處的東西,如果近處有什麼東西把它給覆寫了,我們就不會看到遠處的東西,這裡我們就是畫三角形的時候沒有考慮先後順序。那麼這個問題要怎麼解決呢?
這裡我們先繼續回顧一下三角形重心坐标:
這裡其實有一個很cool的點,就是我們把P表示成三角形三個頂點的線性組合,再回憶一下線性插值,其實對于P點的任何性質,我們都可以利用類似線性插值,把它變成三個頂點的組合:
是以這裡就給了我們提示,對于任意一點P,我們算出它的z值,如果z值更靠近我們,那麼我們就用它來替換已經畫上的點,否則我們則不更新P點。
同樣我們也隻用考慮畫布上的所有的點的P值,可以用一個二維的數組來表示,不過我們這裡偷懶,就用一維的數組,因為畫布上的(x,y)點可以寫成(x + y *width),可以這樣來轉換:
int
同時注意我們在把物體坐标系做映射時,需要保留z值,是以一些計算我們最好就用float.同時我們也需要注意在轉換坐标系的時候我們需要注意還是需要把 x 和 y 變成int,否則有些地方會因為浮點數的原因for loop不會覆寫所有的像素,會有黑色部分産生:
Vec3f
第二個需要注意的點是我們物體的位置和朝向,這裡我們把z-buffer初始化為負無窮大,然後如果P.z更大意味更靠近我們。
void
看結果:
KrisYu/tinyrendergithub.com