【OpenGL】LearnOpenGL学习笔记09 - 材质、光照贴图
上接:https://blog.csdn.net/weixin_44506615/article/details/150411373?spm=1001.2014.3001.5501
完整代码:https://gitee.com/Duo1J/learn-open-gl
一、材质
材质就是用来描述一个物体"应该是什么样的",它具备什么视觉特征、物理特性的一系列参数和纹理的集合
在这之前,我们使用了objectColor变量来定义我们的立方体的颜色,接下来我们将其抽离出来,封装成一个材质结构体,为光照模型的每一个分量提供一个颜色,以便之后我们应用贴图来进行更细颗粒度的控制
直接上代码
FragmentShader.fs
#version 330 core// 物体材质结构体
struct Material {vec3 ambient;vec3 diffuse;vec3 specular;float shininess;
};// 物体受光照强度结构体
struct Light {vec3 position;vec3 ambient;vec3 diffuse;vec3 specular;
};in vec3 FragPos;
in vec3 Normal;out vec4 FragColor;uniform vec3 lightColor;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;void main()
{// 环境光vec3 ambient = lightColor * material.ambient * light.ambient;// 漫反射vec3 normal = normalize(Normal);vec3 lightDir = normalize(light.position - FragPos);vec3 diffuse = max(dot(normal, lightDir), 0.0) * lightColor * material.diffuse * light.diffuse;// 镜面反射vec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, normal);vec3 specular = pow(max(dot(viewDir, reflectDir), 0), material.shininess) * lightColor * material.specular * light.specular;FragColor = vec4(ambient + diffuse + specular, 1.0f);
}
Main.cpp
// 传入材质参数
shader.SetVec3("material.ambient", glm::vec3(1.0f, 0.5f, 0.31f));
shader.SetVec3("material.diffuse", glm::vec3(1.0f, 0.5f, 0.31f));
shader.SetVec3("material.specular", glm::vec3(0.5f, 0.5f, 0.5f));
shader.SetFloat("material.shininess", 32.0f);
shader.SetVec3("light.ambient", glm::vec3(0.2f, 0.2f, 0.2f));
shader.SetVec3("light.diffuse", glm::vec3(0.5f, 0.5f, 0.5f));
shader.SetVec3("light.specular", glm::vec3(1.0f, 1.0f, 1.0f));
shader.SetVec3("light.position", lightPos);
编译运行,顺利的话可以看见以下图像
二、光照贴图
现在我们的立方体看起来还是一个纯色的塑料小方块,如果我们想要为我们的立方体赋予更多的细节,比如让我们的立方体变成一个木条箱,那么我们就需要用到光照贴图
1. 漫反射贴图 (Diffuse Map)
首先我们需要一张贴图资产,可以右键保存以下图片或是在顶部的git仓库中的Resource目录找到所有需要用到的资产
我们将图片命名为T_Box_Diffuse.png
接下来修改我们的Material结构体以及片段着色器
FragmentShader.fs
struct Material {// 将ambient和diffuse颜色改为sampler2D采样器sampler2D diffuse;vec3 specular;float shininess;
};in vec2 TexCoords;// ...
// 修改环境光和漫反射计算
void main()
{// 环境光vec3 ambient = lightColor * vec3(texture(material.diffuse, TexCoords)) * light.ambient;// 漫反射vec3 normal = normalize(Normal);vec3 lightDir = normalize(light.position - FragPos);vec3 diffuse = max(dot(normal, lightDir), 0.0) * lightColor * vec3(texture(material.diffuse, TexCoords)) * light.diffuse;// ...
}
在片段着色器中,我们又将用到TexCoords,也就是UV坐标,所以我们需要修改下顶点数组、顶点属性以及顶点着色器
VertexShader.vs
#version 330 corelayout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);FragPos = vec3(model * vec4(aPos, 1.0));Normal = mat3(transpose(inverse(model))) * aNormal;TexCoords = aTexCoords;
}
Main.cpp
float vertices[] = {// positions // normals // texture coords-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
};int step = 8, curStep = 0;
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, step * sizeof(float), (void*)curStep);
glEnableVertexAttribArray(0);
curStep += 3;
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, step * sizeof(float), (void*)(curStep * sizeof(float)));
glEnableVertexAttribArray(1);
curStep += 3;
// UV坐标
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, step * sizeof(float), (void*)(curStep * sizeof(float)));
glEnableVertexAttribArray(2);
curStep += 2;
接下来我们需要在c++中加载这张漫反射贴图并传递到着色器中
之后我们会经常处理纹理贴图,方便起见,我们现在来封装一个简单的纹理类
Texture.h 新建
#pragma once#include <iostream>#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "stb_image.h"/**
* 纹理类
*/
class Texture
{
public:/*** 纹理宽度*/int width = 0;/*** 纹理高度*/int height = 0;/*** 纹理通道数*/int channel = 0;private:/*** 纹理ID*/unsigned int textureID = 0;public:explicit Texture(const char* path);/*** 获取纹理ID*/unsigned int GetTextureID();
};
Texture.cpp 新建
#include "Texture.h"Texture::Texture(const char* path)
{unsigned char* textureData = stbi_load(path, &width, &height, &channel, 0);glGenTextures(1, &textureID);if (textureData){glBindTexture(GL_TEXTURE_2D, textureID);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);if (channel == 4){glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);}else{glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData);}glGenerateMipmap(GL_TEXTURE_2D);stbi_image_free(textureData);std::cout << "Load texture: " << path << " success, with: " << width << " height: " << height << " channel: " << channel << std::endl;}else{std::cout << "[Error] Failed to load texture: " << path << std::endl;}
}unsigned int Texture::GetTextureID()
{return textureID;
}
接下来加载贴图并传入到着色器
Main.cpp
Texture boxTex("F:/Scripts/Cpp/LearnOpenGL/learn-open-gl/Resource/T_Box_Diffuse.png");while (!glfwWindowShouldClose(window))
{// ...shader.SetInt("material.diffuse", 0);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, boxTex.GetTextureID());glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 36);// ...
}
编译运行,顺利的话可以看见以下图像
如果遇到什么问题,可以参考顶部的git仓库
2. 镜面反射贴图 (Specular Map)
我们注意到,箱子上的高光部分,无论是金属边框还是中间的木条上都有高光,但是木条是比较粗糙的,我们不希望木条上有这么强烈的高光表现,接下来就要用到镜面反射贴图
同样,你可以右键保存或是在顶部的git仓库的Resource目录找到
这张贴图通过颜色值来表示某一像素是否需要受到高光 (黑或白),以及受到高光的强度 (灰)
首先修改我们的片段着色器
FragmentShader.fs
#version 330 core// 物体材质结构体
struct Material {sampler2D diffuse;sampler2D specular;float shininess;
};// ...void main()
{// ...// 镜面反射vec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, normal);vec3 specular = pow(max(dot(viewDir, reflectDir), 0), material.shininess) * lightColor * vec3(texture(material.specular, TexCoords)) * light.specular;// ..
}
接着,加载镜面反射贴图并传递到着色器中
Texture boxSpecularTex("F:/Scripts/Cpp/LearnOpenGL/learn-open-gl/Resource/T_Box_Specular.png");// ...while (!glfwWindowShouldClose(window))
{// ...shader.SetInt("material.specular", 1);// ...glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, boxSpecularTex.GetTextureID());glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 36);// ...
}
编译运行,顺利的话可以看见以下图像
只有木箱的边缘金属部分会受到高光表现
完整代码可在顶部git仓库中找到
下接:https://blog.csdn.net/weixin_44506615/article/details/150446490?spm=1001.2014.3001.5502