本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正
我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject
这点需结合代码全部才好理解,可以跳过此点直接看程序代码
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
ReadFile的第二个参数是一些后期处理(Post-processing)的选项
代码
void processNode(aiNode *node, const aiScene *scene)
{// 处理节点所有的网格(如果有的话)for(unsigned int i = 0; i < node->mNumMeshes; i++){aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; meshes.push_back(processMesh(mesh, scene)); }// 递归接下来对它的子节点重复这一过程for(unsigned int i = 0; i < node->mNumChildren; i++){processNode(node->mChildren[i], scene);}
}
说明
本可以不用递归处理任何节点,渲染时只需要遍历场景对象的所有网格即可
为什么要递归处理网格
使用节点的最初想法是将网格之间定义一个父子关系。通过这样递归地遍历这层关系,我们就能将某个网格定义为另一个网格的父网格了。
例子
位移一个汽车的网格时,你可以保证它的所有子网格(比如引擎网格、方向盘网格、轮胎网格)都会随着一起位移。这样的系统能够用父子关系很容易地实现。
大多数场景都会在多个网格中重用部分纹理,所以不需要每次加载网格用的纹理,应该存储到vector中判断是否加载过,是加载过就只需将加载过的纹理放到vector的后面就行
vector loadMaterialTextures(aiMaterial *mat, aiTextureType type, string typeName)
{vector 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(), directory);texture.type = typeName;texture.path = str.C_Str();textures.push_back(texture);textures_loaded.push_back(texture); // 添加到已加载的纹理中}}return textures;
}
代码
model.h
#pragma once
#include #include
#include
#include
#include
#include
#include //#include
//#include
#include "Mesh.h"
#include "Core/Shader/Shader.h"#include
#include
#include
#include
#include
cpp
#include
#include
#include #include
#include
#include #include "Core/Shader/Shader.h"
#include "Core/Camera/Camera.h"
#include "Core/LoadModel/Model.h"#include
#include "MyFileSystem.h"void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);
unsigned int loadTexture(const char* path);// settings
const unsigned int SCR_WIDTH = 1920;
const unsigned int SCR_HEIGHT = 1080;// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;
// lighting
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);int main()
{// glfw: initialize and configure// ------------------------------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// glfw window creation// --------------------GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);glfwSetCursorPosCallback(window, mouse_callback);glfwSetScrollCallback(window, scroll_callback);// tell GLFW to capture our mouseglfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);// glad: load all OpenGL function pointers// ---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// configure global opengl state// -----------------------------glEnable(GL_DEPTH_TEST);// build and compile our shader zprogram// ------------------------------------//Shader lightingShader("1.colors.vs", "1.colors.fs");// 物体的光照shaderShader ourShader("assest/shader/3模型/3.1.模型加载.vs", "assest/shader/3模型/3.1.模型加载.fs");// 加载模型Model ourModel(FileSystem::getPath("assest/model/nanosuit/nanosuit.obj"));// render loop// -----------while (!glfwWindowShouldClose(window)){// per-frame time logic// --------------------float currentFrame = static_cast(glfwGetTime());deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;// input// -----processInput(window);// render// ------glClearColor(0.1f, 0.1f, 0.1f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// be sure to activate shader when setting uniforms/drawing objectsourShader.use();// view/projection transformationsglm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);glm::mat4 view = camera.GetViewMatrix();ourShader.setMat4("projection", projection);ourShader.setMat4("view", view);// 渲染这个模型glm::mat4 model = glm::mat4(1.0f);model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f));ourShader.setMat4("model", model);ourModel.Draw(ourShader);// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}// glfw: terminate, clearing all previously allocated GLFW resources.// ------------------------------------------------------------------glfwTerminate();return 0;
}
....
glsl
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;out vec2 TexCoords; uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{TexCoords = aTexCoords;gl_Position = projection * view * model * vec4(aPos, 1.0);
}
#version 330 core
out vec4 FragColor;in vec2 TexCoords;uniform sampler2D texture_diffuse1;void main(){FragColor = texture(texture_diffuse1, TexCoords);
}
效果
代码
#version 330 core
layout (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;
}
#version 330 core
out vec4 FragColor;in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;// 纹理坐标uniform vec3 viewPos;uniform sampler2D texture_diffuse1;// 纹理单元
uniform sampler2D texture_specular1;// 纹理单元// 点光源
struct PointLight {vec3 position; vec3 ambient;vec3 diffuse;vec3 specular;float constant; // 常数float linear; // 一次项float quadratic;// 二次项
};#define NR_POINT_LIGHTS 2
uniform PointLight pointLights[NR_POINT_LIGHTS];// 计算点光源影响当前片段的颜色
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir){vec3 lightDir = normalize(light.position - fragPos);// 漫反射光照分量float diff = max(dot(normal, lightDir), 0.0);// 镜面光光照分量vec3 reflectDir = reflect(-lightDir, normal);float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);// 衰减float distance = length(light.position - fragPos);float attenuation = 1.0 / (light.constant + light.linear * distance +light.quadratic * distance * distance);// 合并结果vec3 ambient = light.ambient * vec3(texture(texture_diffuse1, TexCoords));vec3 diffuse = light.diffuse * diff * vec3(texture(texture_diffuse1, TexCoords));vec3 specular = light.specular * spec * vec3(texture(texture_specular1, TexCoords));ambient *= attenuation;diffuse *= attenuation;specular *= attenuation;return (ambient + diffuse + specular);
}void main(){ // 属性vec3 norm = normalize(Normal);vec3 viewDir = normalize(viewPos - FragPos);vec3 result;// 点光源for(int i = 0; i < NR_POINT_LIGHTS; i++){result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);}//vec4 diffuse = texture(texture_diffuse1, TexCoords);//vec4 specular = texture(texture_specular1, TexCoords);FragColor = vec4(result, 1.0);
}
// 点光源
ourShader.use();
ourShader.setVec3("pointLights[0].position", pointLightPositions[0]);
ourShader.setVec3("pointLights[0].ambient", 0.4f, 0.4f, 0.4f);
ourShader.setVec3("pointLights[0].diffuse", 0.8f, 0.8f, 0.8f);
ourShader.setVec3("pointLights[0].specular", 1.0f, 1.0f, 1.0f);
ourShader.setFloat("pointLights[0].constant", 1.0f);
ourShader.setFloat("pointLights[0].linear", 0.09f);
ourShader.setFloat("pointLights[0].quadratic", 0.032f);ourShader.setVec3("pointLights[1].position", pointLightPositions[1]);
ourShader.setVec3("pointLights[1].ambient", 0.4f, 0.4f, 0.4f);
ourShader.setVec3("pointLights[1].diffuse", 0.8f, 0.8f, 0.8f);
ourShader.setVec3("pointLights[1].specular", 1.0f, 1.0f, 1.0f);
ourShader.setFloat("pointLights[1].constant", 1.0f);
ourShader.setFloat("pointLights[1].linear", 0.09f);
ourShader.setFloat("pointLights[1].quadratic", 0.032f);
while (!glfwWindowShouldClose(window))
{ ourShader.use();ourShader.setVec3("viewPos", camera.Position);// view/projection transformationsglm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);glm::mat4 view = camera.GetViewMatrix();ourShader.setMat4("projection", projection);ourShader.setMat4("view", view);// 渲染这个模型glm::mat4 model = glm::mat4(1.0f);model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));model = glm::scale(model, glm::vec3(0.1f, 0.1f, 0.1f));ourShader.setMat4("model", model);ourModel.Draw(ourShader);
......
// 上一节自定义mesh写的函数
void Draw(Shader& shader) {// 绑定适合的纹理unsigned int diffuseNr = 1;unsigned int specularNr = 1;unsigned int normalNr = 1;unsigned int heightNr = 1;for (unsigned int i = 0; i < textures.size(); i++) {glActiveTexture(GL_TEXTURE0 + i);string number;string name = textures[i].type;if (name == "texture_diffuse") {number = std::to_string(diffuseNr++);}else if (name == "texture_specular") {number = std::to_string(specularNr++);}else if (name == "texture_normal") {number = std::to_string(normalNr++);}else if (name == "texture_height") {number = std::to_string(heightNr++);}// 给shader的采样器设置纹理单元glUniform1i(glGetUniformLocation(shader.ID, (name + number).c_str()), i);glBindTexture(GL_TEXTURE_2D, textures[i].id);}// 绘画glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, static_cast(indices.size()), GL_UNSIGNED_INT, 0);// 绘画完设为默认值glActiveTexture(GL_TEXTURE0);
}
效果