Reference
Lesson 3: Hidden faces removal (z buffer) · ssloy/tinyrenderer Wiki (github.com)
深度测试-透明测试 | AncientElement (gitee.io)
深度缓冲
在上一节中我们已经加载了模型,但是可以发现模型的嘴巴和眼睛被模型后面的空腔覆盖了。
在obj文件中实际上已经存在了每个顶点的z
值,但是在上一课我们没有去使用,这里我们用到z_buffer
算法来记录每个像素的深度值。
当有距离更加近的元素时更新z_buffer
中对应的像素的深度值,并且更新颜色值。
但是这里只有顶点的z值,没有每一个像素的z值,怎么办呢?
使用上节课的重心坐标,用计算出来的 $\alpha$ $\beta$ $\gamma$ ,可以对三个顶点进行插值。
重心坐标有多种计算方法,除了上节课中的叉乘法,还有面积法。
这里我们继续用上节课的方法。
在三角形光栅化的函数中添加一个z_buffer
参数,用于读取深度值和写入。
1
| void triangle_foreach(Vec3f* pts, float* z_buffer, TGAImage& image, TGAColor color)
|
并且得到 $\alpha$ $\beta$ $\gamma$ ,如果在三角形内则计算深度值。
1 2 3 4 5 6 7
| Vec3f uvw = barycentric(pts[0], pts[1], pts[2], point); if (uvw.x < 0 || uvw.y < 0 || uvw.z < 0) continue; point.z = 0;
point.z += pts[0].z * uvw.x; point.z += pts[1].z * uvw.y; point.z += pts[2].z * uvw.z;
|
进行深度测试,通过(较于深度缓冲中的值距离相机更加近)则写入深度值,并且写入颜色。
因为这里我们的相机在z的负半轴,所以z越大反而越接近相机。
1 2 3 4 5 6 7 8
| int index = int(point.x + point.y * width);
if (z_buffer[index] < point.z) { z_buffer[index] = point.z; image.set(point.x, point.y, color); }
|
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| void triangle_foreach(Vec3f* pts, float* z_buffer, TGAImage& image, TGAColor color) { int width = image.get_width(); int height = image.get_height(); Vec2f left_down(width - 1, height - 1); Vec2f right_up(0, 0); for (int i = 0; i < 3; i++) { left_down.x = std::min(left_down.x, pts[i].x); left_down.y = std::min(left_down.y, pts[i].y);
right_up.x = std::max(right_up.x, pts[i].x); right_up.y = std::max(right_up.y, pts[i].y); } Vec3f point; for (point.x = left_down.x; point.x <= right_up.x; point.x++) { for (point.y = left_down.y; point.y <= right_up.y; point.y++) { Vec3f uvw = barycentric(pts[0], pts[1], pts[2], point);
if (uvw.x < 0 || uvw.y < 0 || uvw.z < 0) continue;
point.z = 0;
point.z += pts[0].z * uvw.x; point.z += pts[1].z * uvw.y; point.z += pts[2].z * uvw.z;
int index = int(point.x + point.y * width); if (z_buffer[index] < point.z) { z_buffer[index] = point.z; image.set(point.x, point.y, color); } } } }
|