![68a3fc52449c37bc8f2ef8bb29971000.png](https://i-blog.csdnimg.cn/blog_migrate/7fe1001034ab5d66b598a7789ee1ccb0.jpeg)
z-buffer
简单光
我们现在先复习一下,我们经过了画点、画线,填三角形之后已经能画出来一些东西了,现在我们有好几条路可以走,那就是
- 光(上帝说“要有光”)
- 纹理(不然就填白色和随机颜色么?)
- 数学(之前做的所有事情就是简单的把x,y对应的画到图像上来)
这里我们做的事就是简单的给我们的模型一点‘方向光’,注意我这里说了一专有名词‘方向光’,所以还会有别光(暂且不表)。方向光就是类似太阳光一样的,我们只考虑它的方向:
![3f9bb9a8e91683db34f92c30cf77bc1e.png](https://i-blog.csdnimg.cn/blog_migrate/44e27452fba4e72bc3934154b038dbd2.jpeg)
对于一束光,我们到达物体表面的能量实际上是:
![ee18202f990b6207401488052f2ca473.png](https://i-blog.csdnimg.cn/blog_migrate/e11df39eb1f787416c340aa39cc9098a.jpeg)
它的强度 Icosα, α是物体光与物体的法向量的夹角。
如果我们用
这里我们就必须要考虑一些数学问题了,物体我们放在这,然后有光的方向:
![f8bada1a6c4e3c822b0c248b3123b36e.png](https://i-blog.csdnimg.cn/blog_migrate/675714f3ba0fea512ce87b0c65e5b89e.jpeg)
那么'朝内的'法向量可以这样得到
![1bfcb688194c2e6e7c9588bc0bd844dd.png](https://i-blog.csdnimg.cn/blog_migrate/05159f00419322ab1a41eca16bcb309e.jpeg)
这里我们先做很多简化操作:
- 光的方向是 Vec3f light(0, 0, -1), 强度就是1
- 假设每个三角形收到光照的强度相同,都是 Icosα
- 三角形法向量
- 当然我们还要知道 cosα 大于0才有意义,我们不可能减去光o(╯□╰)o
核心代码:
Vec3f
看效果:
![3925dbc7c93be614a3fb9bc2f2a676ba.png](https://i-blog.csdnimg.cn/blog_migrate/ab01260f45289083f59fb9387ea42cad.jpeg)
妈妈他是凸嘴。我们换一个光的方向。
![855d3be2d5fa2fc3301598cd0436a5a2.png](https://i-blog.csdnimg.cn/blog_migrate/969976ac4266eff5d69d60b6727a6823.jpeg)
更吓人了。。。。他嘴巴怎么长后面了。。
simplelightgithub.com![b1088e51545ada5749a87d9ac2b09e44.png](https://i-blog.csdnimg.cn/blog_migrate/0774a0378ffb6ae50668d73aea471513.jpeg)
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
看结果:
![5cee166d6a0698052398bee05de510ef.png](https://i-blog.csdnimg.cn/blog_migrate/8205db2664c943f8b5a077efd1de4ffe.jpeg)
![b1088e51545ada5749a87d9ac2b09e44.png](https://i-blog.csdnimg.cn/blog_migrate/0774a0378ffb6ae50668d73aea471513.jpeg)