本文同時發布在我的個人博客上:https://dragon_boy.gitee.io
光照貼圖
??在實際應用中,一個模型包含不同的組件,每個組件都有不同的材質表現。如果用上一節的內容來實現這一特點是不夠的,接下來介紹漫反射貼圖和高光貼圖。
漫反射貼圖
??我們以紋理為基礎來實現漫反射貼圖。我們用下面的帶金屬邊緣的箱子圖片來進行學習:
??為了使用漫反射貼圖,我們同樣定義一個材質結構體,但不同的是,我們將diffuse屬性設置為sampler2D類型,我們不在需要環境光屬性(由于簡化了環境光的定義,這里使用環境光屬性對結果沒有什么影響,當然,我們可以同樣定義環境光貼圖來影響結果):
struct Material
{
smapler2D diffuse;
vec3 specular;
float shininess;
};
...
in vec2 TexCoords;
??這樣我們就可以計算漫反射的結果:
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
??這里我們將材質的環境光設置為材質漫反射的值:
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
??這里提供新增紋理坐標的頂點數組:
float vertices[] = {
// 位置 // 法線 //紋理
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
??更新一下 頂點著色器:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
...
out vec2 TexCoords;
void main()
{
...
TexCoords = aTexCoords;
}
??同時記住更新VAO的設置,并為漫反射貼圖設置ID,并激活和綁定紋理:
lightingShader.setInt("material.diffuse", 0);
...
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuseMap);
??運行結果如下:
高光貼圖
??從上面的結果我們可以發現一些問題,金屬邊的高光與木紋的高光沒什么區別,這是不符合實際的。同樣的,為解決這個問題,我們為高光的顯示設置高光貼圖(通過灰度值來控制高光的強弱)。我們使用下面的圖片來作為高光貼圖:
??原則上木紋處也有高光,但這里我們暫時忽略掉。
??接下來的操作就與漫反射貼圖一樣了。修改結構體:
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
??修改片元著色器的main函數:
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
FragColor = vec4(ambient + diffuse + specular, 1.0);
??設置貼圖ID,并激活和綁定貼圖:
lightingShader.setInt("material.specular", 1);
...
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, specularMap);
??運行結果如下:
??可以看到結果比較真實了。這里貼出原文代碼:Code。
??使用漫反射貼圖和高光貼圖我們可以為模型增添許多細節,當然,還有許多諸如法線貼圖,凹凸貼圖,反射貼圖的技術來為模型增添更多的細節,這些將在之后講解。
??最后,請多多關注原文:https://learnopengl.com/Lighting/Lighting-maps