参考:这里
这一节主要封装模型类:用来加载各种格式的模型。
复制代码
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
241
242
243
244
245
246#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 <learnopengl/mesh.h> #include <learnopengl/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; // stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once. vector<Mesh> meshes; string directory; bool gammaCorrection; // constructor, expects a filepath to a 3D model. 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: // loads a model with supported ASSIMP extensions from file and stores the resulting meshes in the meshes vector. 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); } // processes a node in a recursive fashion. Processes each individual mesh located at the node and repeats this process on its children nodes (if any). void processNode(aiNode *node, const aiScene *scene) { // process each mesh located at the current node for(unsigned int i = 0; i < node->mNumMeshes; i++) { // the node object only contains indices to index the actual objects in the scene. // the scene contains all the data, node is just to keep stuff organized (like relations between nodes). aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; meshes.push_back(processMesh(mesh, scene)); } // after we've processed all of the meshes (if any) we then recursively process each of the children nodes for(unsigned int i = 0; i < node->mNumChildren; i++) { processNode(node->mChildren[i], scene); } } Mesh processMesh(aiMesh *mesh, const aiScene *scene) { // data to fill vector<Vertex> vertices; vector<unsigned int> indices; vector<Texture> textures; // walk through each of the mesh's vertices for(unsigned int i = 0; i < mesh->mNumVertices; i++) { Vertex vertex; glm::vec3 vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first. // positions vector.x = mesh->mVertices[i].x; vector.y = mesh->mVertices[i].y; vector.z = mesh->mVertices[i].z; vertex.Position = vector; // normals if (mesh->HasNormals()) { vector.x = mesh->mNormals[i].x; vector.y = mesh->mNormals[i].y; vector.z = mesh->mNormals[i].z; vertex.Normal = vector; } // texture coordinates if(mesh->mTextureCoords[0]) // does the mesh contain texture coordinates? { glm::vec2 vec; // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't // use models where a vertex can have multiple texture coordinates so we always take the first set (0). vec.x = mesh->mTextureCoords[0][i].x; vec.y = mesh->mTextureCoords[0][i].y; vertex.TexCoords = vec; // tangent vector.x = mesh->mTangents[i].x; vector.y = mesh->mTangents[i].y; vector.z = mesh->mTangents[i].z; vertex.Tangent = vector; // bitangent 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); } // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices. for(unsigned int i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; // retrieve all indices of the face and store them in the indices vector for(unsigned int j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } // process materials aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; // we assume a convention for sampler names in the shaders. Each diffuse texture should be named // as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER. // Same applies to other texture as the following list summarizes: // diffuse: texture_diffuseN // specular: texture_specularN // normal: 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()); // return a mesh object created from the extracted mesh data return Mesh(vertices, indices, textures); } // checks all material textures of a given type and loads the textures if they're not loaded yet. // the required info is returned as a Texture struct. 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); // check if texture was loaded before and if so, continue to next iteration: skip loading a new texture 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; // a texture with the same filepath has already been loaded, continue to next one. (optimization) break; } } if(!skip) { // if texture hasn't been loaded already, load it 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); // store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures. } } 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
程序代码:就比较简单了,直接利用Model类加载和绘制。
Model类只设置漫反射和高光贴图,而且shader里的名字要和Model里设置的对应。
一些其他的uniform变量还需我们自己设置。
复制代码
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//顺序不能错 #include <glad/glad.h> #include <GLFW/glfw3.h> #include <stb_image.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <learnopengl/Shader.h> #include <learnopengl/Camera.h> #include <learnopengl/Model.h> #include <iostream> using namespace std; void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow* window); void mouse_callback(GLFWwindow* window, double x, double y); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); unsigned int loadTexture(const char* path); const int SCR_WIDTH = 800; const int SCR_HEIGHT = 600; Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); float lastX = SCR_WIDTH / 2, lastY = SCR_WIDTH / 2; bool firstMouse = true; float deltaTime = 0.0f; float lastFrame = 0.0f; glm::vec3 lightPos(1.2f, 1.0f, 2.0f); int main() { //Init glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "hahaha", NULL, NULL); if (window == NULL) { cout << "Failed to create GLFW window !" << endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { cout << "Failed to init GLAD !" << endl; } //configure glEnable(GL_DEPTH_TEST); //反转贴图Y轴:如果模型贴图Y轴显示颠倒,需要反转 //stbi_set_flip_vertically_on_load(true); //隐藏光标 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); //build and compile shader Shader shader("Shaders/Learn17.vs", "Shaders/Learn17.fs"); Model ourModel("Models/1/nanosuit.obj"); //render loop while (!glfwWindowShouldClose(window)) { float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; //input processInput(window); //render glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shader.use(); shader.setVec3("viewPos", camera.Position); //绕Y轴旋转 shader.setVec3("dirLight.direction", glm::vec3(sin(glfwGetTime()*5),0.0f, cos(glfwGetTime() * 5))); shader.setVec3("dirLight.ambient", 1.0f, 1.0f, 1.0f); shader.setVec3("dirLight.diffuse", 1.0f, 1.0f, 1.0f); shader.setVec3("dirLight.specular", 1.0f, 1.0f, 0.0f); shader.setFloat("material.shininess", 32); glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); glm::mat4 view = camera.GetViewMatrix(); shader.setMat4("projection", projection); shader.setMat4("view", view); glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(0.0f, -5.0f, -10.0f)); model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f)); shader.setMat4("model", model); ourModel.Draw(shader); //swap buffer glfwSwapBuffers(window); //call event glfwPollEvents(); } //terminate clearing all previously allocated GLFW resources glfwTerminate(); return 0; } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); } void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera.ProcessKeyboard(FORWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera.ProcessKeyboard(BACKWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera.ProcessKeyboard(LEFT, deltaTime); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera.ProcessKeyboard(RIGHT, deltaTime); } void mouse_callback(GLFWwindow* window, double x, double y) { if (firstMouse) { lastX = x; lastY = y; firstMouse = false; } float xoffset = x - lastX; float yoffset = lastY - y; lastX = x; lastY = y; camera.ProcessMouseMovement(xoffset, yoffset); } void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { camera.ProcessMouseScroll(yoffset); } unsigned int loadTexture(const char* path) { unsigned int textureID; glGenTextures(1, &textureID); 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); //load int width, height, channels; auto data = stbi_load(path, &width, &height, &channels, 0); if (data) { //根据通道数判断图片格式 GLenum format; if (channels == 1) format = GL_RED; if (channels == 3) format = GL_RGB; if (channels == 4) format = GL_RGBA; glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); } else { cout << "failed to load texture!" << path << endl; } stbi_image_free(data); return textureID; }
顶点着色器:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#version 330 core layout(location=0)in vec3 aPos; layout(location=1)in vec3 aNormal; layout(location=2)in vec2 aTexcoord; out vec3 normal; out vec3 fragPos; out vec2 uv; 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; uv=aTexcoord; }
片元着色器:
复制代码
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#version 330 core out vec4 fragColor; struct Material { sampler2D texture_diffuse1; sampler2D texture_specular1; float shininess; }; //定向光 struct DirLight { vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform Material material; uniform DirLight dirLight; in vec2 uv; in vec3 normal; in vec3 fragPos; uniform vec3 viewPos; vec3 CalcDirLight(DirLight light,vec3 normal,vec3 viewDir) { vec3 lightDir=normalize(-light.direction); //环境光 vec3 ambient=light.ambient* vec3(texture(material.texture_diffuse1,uv)); //漫反射 float dif=max(dot(normal,lightDir),0.0); vec3 diffuse=light.diffuse*dif*vec3(texture(material.texture_diffuse1,uv)); //高光 vec3 reflectDir=reflect(-lightDir,normal); float spe=pow(max(dot(reflectDir,viewDir),0.0),material.shininess); vec3 specular=light.specular*spe*vec3(texture(material.texture_specular1,uv)); return ambient+diffuse+specular; } void main() { vec3 worldNormal=normalize(normal); vec3 viewDir=normalize(viewPos-fragPos); //定向光 vec3 result=CalcDirLight(dirLight,worldNormal,viewDir); fragColor=vec4(result,1.0); }
最后
以上就是踏实台灯最近收集整理的关于OpenGL模型加载篇--模型--17的全部内容,更多相关OpenGL模型加载篇--模型--17内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复