0%

从零开始的软渲染生活-第三话(番外)

(距离上一话竟然隔了将近一个月。。。罪过)

前情提要:上一话我们搞定了深度的问题,让不同深度的面可以正确地显示,这回要搞定的部分是纹理贴图了。就是这个样子:
效果图

我们知道obj文件中以vt开头的行代表的就是每个顶点对应的纹理uv信息,那么我们也像之前的读取方法一样用一个vector保存下来这些信息。然后一样地,在以f开头的面信息中,顶点索引/纹理坐标索引/法线索引, 我们可以像读顶点索引一样读取纹理坐标索引。

对于每一个面片中每个点的uv值,我们也是向之前一样去做一个重心坐标插值就可以了。

然后我们唯一需要新增的操作就是把我们读到的uv坐标对应到纹理贴图中的对应点,然后取这个对应点的颜色作为我们上色时的颜色,具体来说就是,u值乘以贴图的宽度,v值乘上贴图的高度。于是我们的程序要增加两个函数:

首先是贴图的加载函数:

1
2
3
4
void Obj::load_texture(const char* filename,TGAImage& img){
std::cout << "loading " <<(img.read_tga_file(filename) ? "ok": "failed") << std::endl;
img.flip_vertically();
}

然后是uv坐标的转换,并返回转换后贴图上对应像素的颜色:

1
2
3
4
5
6
TGAColor Obj::diffuse(Vec2f uv){
Vec2i uvwh(uv.x*diffusemap.get_width(), uv.y*diffusemap.get_height());//find the pixel color by turning the uv coordinate to xy coordinate
//std::cout<<uv.x<<" "<<uv.y<<std::endl;
//std::cout<<uvwh.x<<" "<<uvwh.y<<std::endl;
return diffusemap.get(uvwh.x,uvwh.y);
}

在main函数里我们修改三角形的着色方法:

1
2
3
4
5
6
7
8
9
10
11
Vec2f texture_p(0,0);

texture_p.x = t0.x*bc.x + t1.x*bc.y + t2.x*bc.z;
texture_p.y = t0.y*bc.x + t1.y*bc.y + t2.y*bc.z;

if (zbuffer[int(P.x+P.y*width)]<P.z) {
zbuffer[int(P.x+P.y*width)] = P.z;

TGAColor color = obj.diffuse(texture_p);
image.set(P.x, P.y, color);
}

大功告成!