光照贴图
上节中我们给物体添加了材质,使得物体能够对光照做出不同的反应,但是有个问题就是,使用该种材质的物体,只能够表现出我们所定义的一种性质,而实际生活中我们的一个物体往往具有多种材质,因此本节中我们使用漫反射贴图和镜面反射贴图对物体的漫反射分量和镜面反射分量有着更为精确的控制。
一、漫反射贴图
漫反射贴图允许我们对物体的每个点单独指定漫反射颜色。比如我们想让之前的立方体表面看起来像一个木箱子,就可以用下面这张帖图:
可以通过纹理采样来获得该点所对应的漫反射颜色,首先在material 结构体中创建一个采样器 sampler2D 来替换之前创建的 vec3 变量 diffuse:
struct Material {
sampler2D diffuse;
vec3 specular;
float shininess;
};
in vec2 v_texcoord;
同时由于环境光照的颜色和漫反射颜色相同,所以我们移去了环境光照分量。此外,我们还需要获得每一个片元对应的纹理坐标,因此在修改顶点数组之后,重新指定GPU内存布局:
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_normal;
layout(location = 2) in vec2 a_texcoord;
out vec3 v_normal;
out vec3 v_world_pos;
out vec2 v_texcoord;
记得去更新两个VAO的顶点属性指针来匹配新的顶点数据,然后可以将原来 diffuse 变量位置的内容替换为 :
vec3 ambient_color = light.ambient * texture(material.diffuse, v_texcoord).rgb;
vec3 diffuse_color = light.diffuse * max(0.0, dot(normal, light_dir)) * texture(material.diffuse, v_texcoord).rgb;
还需要做的一件事就是给当前的纹理绑定纹理单元,然后赋值到 material.diffuse 采样器:
box_shader.set_int("material.diffuse", 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuse_map);
稍稍运行看一下结果:
此时我们的立方体看上去就像一个木箱子了,这是因为漫反射贴图就像是一张画布一样贴在了立方体的表面。
二、镜面光贴图
镜面光贴图就是能够对物体表面的高光部分进行精准控制的贴图,就比如上面的立方体箱子当中,我们希望木头的部分没有镜面反射,金属的部分有镜面反射,我们就可以利用下面这张帖图:
和之前的操作一样,我们也对镜面高光贴图进行采样,因此修改之前 shader 中的 specular 变量为 samper2D:
struct Material
{
sampler2D diffuse;
sampler2D specular;
float shininess;
};
设置全局变量并绑定纹理单元:
box_shader.set_int("material.specular", 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, specular_map);
重新计算镜面高光部分:
vec3 view_dir = normalize(view_pos - v_world_pos);
vec3 reflect_dir = reflect(-light_dir, normal);
vec3 specular_color = light.specular * pow(max(dot(view_dir, reflect_dir), 0.0), material.shininess) * texture(material.specular, v_texcoord).rgb;
运行结果是这样的:
这次镜面高光只在金属部分出现了。