图形中的纹理通常表示在表面上生成颜色的函数,我们将首先使所有颜色成为一种纹理。

class texture {
public:
virtual vec3 value(float u, float v, const vec3& p) const = 0;
};

class constant_texture : public texture {
public:
constant_texture() { }
constant_texture(vec3 c) : color(c) { }
//value函数是得到某个点的颜色的函数,会在不同纹理上重写
virtual vec3 value(float u, float v, const vec3& p) const {
return color;
}
vec3 color;
};

我们通过一个指向纹理的指针来替换vec3颜色来制作纹理材质,这样的话我们是赋值的纹理而不是颜色。

//漫反射材质
class lambertian : public material {
public:
lambertian(texture *a) : albedo(a) {}
//将求反射光线的部分放到了材质类的scatter()方法里,每个材质可以自己定义其反射光线
//获取漫反射的反射光线;获取材料的衰减系数;
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const {
vec3 target = rec.p + rec.normal + random_in_unit_sphere();
scattered = ray(rec.p, target-rec.p);
attenuation = albedo->value(0,0, rec.p);
return true;
}

texture \*albedo;

};

我们曾经使用:new lambertian(vec3(0.5, 0.5, 0.5)) 现在我们要把它替换为:new constant_texture(vec3(…)) 例如这样写:new lambertian(new constant_texture(vec3(0.5, 0.5, 0.5))))

我们可以通过正弦和余弦的符号以常规交替来创建一个检查器纹理,下面写一个棋盘纹理,这个纹理会按棋盘格的方式分割两个不同的纹理

class checker_texture : public texture {
public:
checker_texture() { }
checker_texture(texture *t0, texture *t1): even(t0), odd(t1) { }
virtual vec3 value(float u, float v, const vec3& p) const {
float sines = sin(10*p.x())*sin(10*p.y())*sin(10*p.z());
if (sines < 0)
return odd->value(u, v, p);
else
return even->value(u, v, p);
}
texture *odd;
texture *even;
};

上面的棋盘纹理可以是一个恒定的纹理或者一个程序化的纹理,这是Pat Hanrahan在上世纪80年代提出的着色网格原则。 我们将棋盘纹理添加到地面上,也就是添加到我们的第一个球上:

texture *checker = new checker_texture(new constant_texture(vec3(0.2, 0.3, 0.1)), new constant_texture(vec3(0.9, 0.9, 0.9)));
list[0] = new sphere(vec3(0, -1000, 0), 1000, new lambertian(checker));

效果如下:

[

](http://www.wjgbaby.com/wp-content/uploads/2018/07/18070101.jpg)
](http://www.wjgbaby.com/wp-content/uploads/2018/07/18070101.jpg)
我们试下渲染两个带有棋盘纹理的球:

texture *checker = new checker_texture(new constant_texture(vec3(0.2, 0.3, 0.1)), new constant_texture(vec3(0.9, 0.9, 0.9)));
int n = 50;
hitable **list = new hitable*[n + 1];
list[0] = new sphere(vec3(0, -10, 0), 10, new lambertian(checker));
list[1] = new sphere(vec3(0, 10, 0), 10, new lambertian(checker));

return new hitable_list(list, 2);

调整摄像机:

vec3 lookform(13.0f, 2.0f, 3.0f);
vec3 lookat(0, 0, 0);
float dist_to_focus = (lookform - lookat).length();
float aperture = 0.0f;

camera cam(lookform, lookat, vec3(0, 1, 0), 20, float(nx) / float(ny), aperture, 0.7*dist_to_focus,0.0,1.0);

效果如下: 参考书籍:《Ray Tracing The Next Week》 RTTNW系列项目地址:GitHub