天天看點

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

z-buffer

簡單光

我們現在先複習一下,我們經過了畫點、畫線,填三角形之後已經能畫出來一些東西了,現在我們有好幾條路可以走,那就是

  • 光(上帝說“要有光”)
  • 紋理(不然就填白色和随機顔色麼?)
  • 數學(之前做的所有事情就是簡單的把x,y對應的畫到圖像上來)

這裡我們做的事就是簡單的給我們的模型一點‘方向光’,注意我這裡說了一專有名詞‘方向光’,是以還會有别光(暫且不表)。方向光就是類似太陽光一樣的,我們隻考慮它的方向:

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

對于一束光,我們到達物體表面的能量實際上是:

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

它的強度 Icosα, α是物體光與物體的法向量的夾角。

如果我們用

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

表示光的方向,

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

指向物體光照處'向内的'法向量,那麼

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

這裡我們就必須要考慮一些數學問題了,物體我們放在這,然後有光的方向:

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

那麼'朝内的'法向量可以這樣得到

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

,然後正交化:

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

這裡我們先做很多簡化操作:

  • 光的方向是 Vec3f light(0, 0, -1), 強度就是1
  • 假設每個三角形收到光照的強度相同,都是 Icosα
  • 三角形法向量
    重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer
  • 當然我們還要知道 cosα 大于0才有意義,我們不可能減去光o(╯□╰)o

核心代碼:

Vec3f 
           

看效果:

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

媽媽他是凸嘴。我們換一個光的方向。

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

更吓人了。。。。他嘴巴怎麼長後面了。。

simplelight​github.com

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

compile & run:

$ g++ -std=c++11 main.cpp tgaimage.cpp model.cpp -o main
$ ./main
           

z-buffer

造成這個問題的原因很簡單,我們就是一股腦的把三角形畫出來了,沒有考慮三角形的先後順序,正如畫畫一樣,我們應該先畫遠處的東西,如果近處有什麼東西把它給覆寫了,我們就不會看到遠處的東西,這裡我們就是畫三角形的時候沒有考慮先後順序。那麼這個問題要怎麼解決呢?

這裡我們先繼續回顧一下三角形重心坐标:

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

這裡其實有一個很cool的點,就是我們把P表示成三角形三個頂點的線性組合,再回憶一下線性插值,其實對于P點的任何性質,我們都可以利用類似線性插值,把它變成三個頂點的組合:

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

是以這裡就給了我們提示,對于任意一點P,我們算出它的z值,如果z值更靠近我們,那麼我們就用它來替換已經畫上的點,否則我們則不更新P點。

同樣我們也隻用考慮畫布上的所有的點的P值,可以用一個二維的數組來表示,不過我們這裡偷懶,就用一維的數組,因為畫布上的(x,y)點可以寫成(x + y *width),可以這樣來轉換:

int 
           

同時注意我們在把物體坐标系做映射時,需要保留z值,是以一些計算我們最好就用float.同時我們也需要注意在轉換坐标系的時候我們需要注意還是需要把 x 和 y 變成int,否則有些地方會因為浮點數的原因for loop不會覆寫所有的像素,會有黑色部分産生:

Vec3f 
           

第二個需要注意的點是我們物體的位置和朝向,這裡我們把z-buffer初始化為負無窮大,然後如果P.z更大意味更靠近我們。

void 
           

看結果:

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer

KrisYu/tinyrender​github.com

重心模型選址代碼_[500行代碼學懂OpenGL]之四z-buffer