-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path0modelreflect
240 lines (228 loc) · 9.3 KB
/
0modelreflect
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#ifndef MODEL_H
#define MODEL_H
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "stb_image.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include "meshreflect.h"
#include "shader.h"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
unsigned int TextureFromFile(const char* path, const string& directory, bool gamma = false);
class Model
{
public:
// model data
vector<Texture> textures_loaded; // 存储到目前为止加载的所有纹理,优化以确保纹理不会加载超过一次。
vector<Mesh> meshes; //一个模型由许多网格组成
string directory;
bool gammaCorrection;//伽马矫正
// 构造函数,需要一个3D模型的文件路径。
Model(string const& path, bool gamma = false) : gammaCorrection(gamma)
{
loadModel(path);
}
// draws the model, and thus all its meshes
void Draw(Shader& shader)
{
for (unsigned int i = 0; i < meshes.size(); i++)
meshes[i].Draw(shader);
}
private:
//从文件中加载一个支持ASSIMP扩展的模型,并将结果网格存储在网格向量中。
void loadModel(string const& path)
{
// read file via ASSIMP
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
// check for errors
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
{
cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl;
return;
}
// retrieve the directory path of the filepath
directory = path.substr(0, path.find_last_of('/'));
// process ASSIMP's root node recursively
processNode(scene->mRootNode, scene);
}
// 以递归方式处理节点。处理位于节点上的每个单独的网格,并在其子节点上重复此过程(如果有的话)。
void processNode(aiNode* node, const aiScene* scene)
{
// 处理位于当前节点的每个网格
for (unsigned int i = 0; i < node->mNumMeshes; i++)
{
//节点对象只包含索引来索引场景中的实际对象。
//场景包含所有的数据,节点只是保持东西的组织(像节点之间的关系)。
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];//node->mMeshes[i]表示索引
meshes.push_back(processMesh(mesh, scene));
}
//在我们处理完所有的网格(如果有的话)之后,我们递归地处理每个子节点
for (unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(node->mChildren[i], scene);
}
}
Mesh processMesh(aiMesh* mesh, const aiScene* scene)
{
// 数据填充
vector<Vertex> vertices;
vector<unsigned int> indices;
vector<Texture> textures;
// 遍历每个网格的顶点
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
glm::vec3 vector; // assimp使用自己的vector类,不能直接转换为glm的vec3类,所以我们首先将数据传输到这个占位符glm::vec3
// 位置
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;
}
// 纹理坐标
if (mesh->mTextureCoords[0]) //判断网格是否包含纹理坐标。纹理坐标的处理也大体相似,但Assimp允许一个模型在一个顶点上有最多8个不同的纹理坐标,我们不会用到那么多,我们只关心第一组纹理坐标
{
glm::vec2 vec;
//一个顶点最多可以包含8个不同的纹理坐标。因此,我们假设我们不会使用一个顶点可以有多个纹理坐标的模型,所以我们总是取第一组(0)。
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoords = vec;
// 切线
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.TexCoords = glm::vec2(0.0f, 0.0f);
vertices.push_back(vertex);
}
// 现在遍历每个网格的面(面是一个网格的三角形)并检索相应的顶点索引。
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
// 检索面的所有索引并将它们存储在索引向量中
for (unsigned int j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
// process materials
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
//我们假设在着色器中采样器名称有一个约定。每个漫反射纹理都应该命名
//作为'texture_diffuseN',其中N是一个从1到MAX_SAMPLER_NUMBER的序列号。
//同样适用于其他纹理,如下所示:
//漫反射材质贴图:texture_diffuseN
// 镜面反射材质贴图: texture_specularN
// 法线材质贴图: texture_normalN
// 1. diffuse maps
vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
// 2. specular maps
vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
// 3. normal maps
std::vector<Texture> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
// 4. height maps
std::vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());
// 5. reflection maps
std::vector<Texture> reflectionMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_reflection");
textures.insert(textures.end(), reflectionMaps.begin(), reflectionMaps.end());
// 返回从提取的网格数据创建的网格对象
return Mesh(vertices, indices, textures);
}
//检查给定类型的所有材质纹理,并加载尚未加载的纹理。
//所需的信息作为一个纹理结构返回。
vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName)
{
vector<Texture> textures;
for (unsigned int i = 0; i < mat->GetTextureCount(type); i++)
{
aiString str;
mat->GetTexture(type, i, &str);
// 检查之前是否加载了纹理,如果是,继续下一个迭代:跳过加载新纹理
bool skip = false;
//for (unsigned int j = 0; j < textures_loaded.size(); j++)
//{
// if (std::strcmp(textures_loaded[j].path.data(), str.C_Str()) == 0)
// {
// textures.push_back(textures_loaded[j]);
// skip = true; //具有相同文件路径的纹理已经加载,继续下一个。(优化)
// break;
// }
//}
if (!skip)
{ //如果纹理尚未加载,加载它
Texture texture;
texture.id = TextureFromFile(str.C_Str(), this->directory);
texture.type = typeName;
texture.path = str.C_Str();
textures.push_back(texture);
textures_loaded.push_back(texture); //将其存储为整个模型加载的纹理,以确保我们不会不必要地加载重复的纹理。
}
}
return textures;
}
};
////加载纹理
//unsigned int TextureFromFile(const char* path, const string& directory, bool gamma)
//{
// string filename = string(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;
//}
#endif