2 - 进阶操作(可能)
接下来我们试着给场景加点光源,然后导入其他模型,完善一下代码。
增添代码细节
丰富顶点信息
除了位置,法线和纹理坐标,顶点还有切线(Tangent),副切线(Bitangent)等信息:
#define MAX_BONE_INFLUENCE 4
struct Vertex
{
glm::vec3 Position;
glm::vec3 Normal;
glm::vec2 TexCoords;
glm::vec3 Tangent;
glm::vec3 Bitangent;
// bone indexes
int m_BoneIDs[MAX_BONE_INFLUENCE];
// weight from each bone
float m_Weights[MAX_BONE_INFLUENCE];
};
记得修改一下顶点属性:
// 顶点位置属性
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
glCheckError();
// 顶点法线属性
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
glCheckError();
// 顶点纹理坐标属性
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
glCheckError();
// 顶点切线属性
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));
glCheckError();
// 顶点副切线属性
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent));
glCheckError();
// 顶点骨骼属性-ids
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, MAX_BONE_INFLUENCE, GL_INT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, m_BoneIDs));
glCheckError();
// 顶点骨骼属性-weight
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, MAX_BONE_INFLUENCE, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, m_Weights));
glCheckError();
这里为了方便debug,使用了这里提供的glCheckError()
宏定义,方便定位是哪个文件哪一行有问题。
然后改一下读取顶点属性的代码:
// 处理顶点信息(位置,法线,纹理坐标)
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
// 位置
glm::vec3 vector;
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;
// 法线
if (mesh->HasNormals())
{
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.Normal = vector;
}
else
{
vertex.Normal = glm::vec3(0.0f, 0.0f, 0.0f);
}
// 纹理坐标
if (mesh->mTextureCoords[0])
{
glm::vec2 vec;
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoords = vec;
}
else
{
vertex.TexCoords = glm::vec2(0.0f, 0.0f);
}
// 切线
if (mesh->HasTangentsAndBitangents())
{
vector.x = mesh->mTangents[i].x;
vector.y = mesh->mTangents[i].y;
vector.z = mesh->mTangents[i].z;
vertex.Tangent = vector;
vector.x = mesh->mBitangents[i].x;
vector.y = mesh->mBitangents[i].y;
vector.z = mesh->mBitangents[i].z;
vertex.Bitangent = vector;
}
else
{
vertex.Bitangent = glm::vec3(0.0f, 0.0f, 0.0f);
vertex.Tangent = glm::vec3(0.0f, 0.0f, 0.0f);
}
vertices.push_back(vertex);
}
有关法线和切线的计算,可以通过aiProcess_GenSmoothNormals
和aiProcess_CalcTangentSpace
这两个后处理参数来获得。
丰富材质信息
除了高光贴图和漫反射贴图外,还有法线贴图,高度贴图等。在读取贴图时,把它们加上去:
std::vector<Texture> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
std::vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());
然后将贴图信息写入着色器:
// ...
else if (name == "texture_normal")
{
number = std::to_string(normalNr++);
}
else if (name == "texture_height")
{
number = std::to_string(heightNr++);
}
加点光源
可以加两个点光源,看看模型效果怎么样
载入其他模型
教程的背包
参考资料
- 模型 - LearnOpenGL CN (learnopengl-cn.github.io)
- 调试 - LearnOpenGL CN (learnopengl-cn.github.io)