一、.h
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include “Mesh.h”
//#include “stb_image.h”
using std::vector;
using std::string;
using std::map;
class Model
{
public:
Model(string path);
~Model();
vector meshes;
string directory;
void Draw(Shader* shader);
private:
map
void loadModel(string path);
void processNode(aiNode* node, const aiScene* scene);
Mesh processMesh(aiMesh* mesh, const aiScene* scene);
vector loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName);
unsigned int TextureFromFile(string path, const string& directory);
};
二、.cpp
#include “Model.h”
#include “stb_image.h”
Model::Model(string path)
{
loadModel(path);
}
Model::~Model()
{
}
void Model::Draw(Shader* shader)
{
for (size_t i = 0; i < meshes.size(); i++)
{
meshes[i].Draw(shader);
}
}
void Model::loadModel(string path)
{
//read file via ASSIMP
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
//check for error
if (!scene || (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) || !scene->mRootNode) {
std::cout << “Assimp error:” << importer .GetErrorString()<< std::endl;
return;
}
directory = path.substr(0, path.find_last_of(’\’));
//std::cout << directory << std::endl;
processNode(scene->mRootNode, scene);
}
void Model::processNode(aiNode* node, const aiScene* scene)
{
std::cout << node->mName.data << std::endl;
for (unsigned int i = 0; i < node->mNumMeshes; i++)
{
aiMesh* curMesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(processMesh(curMesh, scene));
}
for (unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(node->mChildren[i], scene);
}
}
Mesh Model::processMesh(aiMesh* mesh, const aiScene* scene)
{
//顶点信息
vector tmpVertices;
//索引信息
vector tmpIndices;
//贴图信息
vector tmpTexture;
for (size_t i = 0; i < mesh->mNumVertices; i++)
{
//vertex
Vertex vertex;
//postion
vertex.Position.x = mesh->mVertices[i].x;
vertex.Position.y = mesh->mVertices[i].y;
vertex.Position.z = mesh->mVertices[i].z;
//normal
vertex.Normal.x = mesh->mNormals[i].x;
vertex.Normal.y = mesh->mNormals[i].y;
vertex.Normal.z = mesh->mNormals[i].z;
//texcoord
if (mesh->mTextureCoords[0]) {
vertex.TexCoord.x = mesh->mTextureCoords[0][i].x;
vertex.TexCoord.y = mesh->mTextureCoords[0][i].y;
}
else {
vertex.TexCoord = glm::vec2(0.0f, 0.0f);
}
// tangent
vertex.Tangent.x = mesh->mTangents[i].x;
vertex.Tangent.y = mesh->mTangents[i].y;
vertex.Tangent.z = mesh->mTangents[i].z;
// bitangent
vertex.Bitangent.x = mesh->mBitangents[i].x;
vertex.Bitangent.y = mesh->mBitangents[i].y;
vertex.Bitangent.z = mesh->mBitangents[i].z;
tmpVertices.push_back(vertex);
}
//indices
for (size_t i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for (size_t j = 0; j < face.mNumIndices; j++)
{
tmpIndices.push_back(face.mIndices[j]);
}
}
//Texture Maps
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
// 1. diffuse maps
vector diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
tmpTexture.insert(tmpTexture.end(), diffuseMaps.begin(), diffuseMaps.end());
// 2. specular maps
vector specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
tmpTexture.insert(tmpTexture.end(), specularMaps.begin(), specularMaps.end());
// 3. normal maps
std::vector normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
tmpTexture.insert(tmpTexture.end(), normalMaps.begin(), normalMaps.end());
// 4. height maps
std::vector heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
tmpTexture.insert(tmpTexture.end(), heightMaps.begin(), heightMaps.end());
return Mesh(tmpVertices, tmpIndices, tmpTexture);
}
vector Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName)
{
vector textures;
for (size_t i = 0; i < mat->GetTextureCount(type); i++)
{
aiString str;
mat->GetTexture(type, i, &str);
if (textures_loaded.find(str.data) != textures_loaded.end()) {
textures.push_back(textures_loaded[str.data]);
}
else {
Texture texture;
texture.id = TextureFromFile(str.C_Str(), directory);
texture.type = typeName;
texture.path = str.data;
textures.push_back(texture);
textures_loaded[str.data] = texture;
}
}
return textures;
}
unsigned int Model::TextureFromFile(string path,const string& directory)
{
string filename = path;
filename = directory + ‘\’ + filename;
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char* data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
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_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
三、Model类的作用
1、void Model::loadModel(string path);
加载指定路径Model对象,使用ASSIMP库的Importerd的ReadFile读取模型
2、void Model::processNode(aiNode* node, const aiScene* scene)
通过递归处理场景中的每个节点aiNode对象,每个节点包含多个aiMesh
3、Mesh Model::processMesh(aiMesh* mesh, const aiScene* scene)
读取aiMesh对象,解析aiMesh总的
方位数据 VBO数据(pos normal textcoord )
EBO数据 indices
贴图数据 texture
然后实现由aiMesh生成Mesh 对象
4、void Model::Draw(Shader* shader)
循环调用Mesh的Draw方法绘制出Model
代码Git地址.