learnOpenGL-model loading


The data structure Scene loaded by Assimp contains the scene root node
. The Mesh object itself contains all relevant data required for rendering, such as vertex positions, normal vectors, texture coordinates, faces (Face) and the material of the object. The mesh contains multiple faces
. Face represents the rendering primitive (Primitive) of the object (triangle, square, point). A face contains
the indices of the vertices that make up the primitive. The mesh also contains a Material object, which contains functions that allow us to obtain the material properties of the object, such as color and texture maps (such as diffuse and specular maps).
Process: Load scene, traverse nodes, obtain corresponding mesh, obtain vertex data, index and material through mesh.
Insert image description here
Several pitfalls:
1. What is passed to the shader in the tutorial is a material material plus a diffuse reflection map and a specular map. The material is not defined in the actual code, texture_diffuse and texture_specular are passed directly.
2. In the mTangents attribute in the sample code, aiProcess_CalcTangentSpace must be added when reading scene data, otherwise the triangle data is empty. 3.
Various data are passed in the mesh code, but only one texture_diffuse1 parameter is defined in the actual shader. The addresses of uniform variables obtained in glGetUniformLocation are all -1, and the codes for transmitting data are invalid. Only texture_diffuse1 is passed into the shader

main.cpp

#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "shader.h"
#include "stb_image.h"
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>
#include "Camera.h"
#include "Model.h"

Camera* myCamera = new Camera(glm::vec3(0.0f, 10.0f, 3.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f));

void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
    
    
	myCamera->mouseCb(xpos, ypos);
};

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
    
    
	myCamera->scrollCb(xoffset, yoffset);
}

GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;

void processInput(GLFWwindow* window) {
    
    
	GLfloat currentFrame = glfwGetTime();
	deltaTime = currentFrame - lastFrame;
	lastFrame = currentFrame;
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
    
    
		myCamera->pressKeyW(deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
    
    
		myCamera->pressKeyS(deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
    
    
		myCamera->pressKeyA(deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
    
    
		myCamera->pressKeyD(deltaTime);
	}
}

glm::vec3 pointLightPositions[] = {
    
    
	glm::vec3(2.0f,  10.2f,  2.0f),
	glm::vec3(-2.3f, 7.3f, -4.0f)
};

GLfloat vertices[] = {
    
    
	// positions          // normals           // texture coords
   -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
	0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 0.0f,
	0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
	0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
   -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 1.0f,
   -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,

   -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,
	0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 0.0f,
	0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
	0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
   -0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 1.0f,
   -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,

   -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
   -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
   -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
   -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
   -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
   -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

	0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
	0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
	0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
	0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
	0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
	0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

   -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,
	0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 1.0f,
	0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
	0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
   -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 0.0f,
   -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,

   -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f,
	0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 1.0f,
	0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
	0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
   -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 0.0f,
   -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f
};

int main()
{
    
    
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	GLFWwindow* window = glfwCreateWindow(800, 600, "test", nullptr, nullptr);
	if (window == nullptr)
	{
    
    
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	//glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetScrollCallback(window, scroll_callback);

	glewExperimental = GL_TRUE;
	if (glewInit() != GLEW_OK)
	{
    
    
		std::cout << "Failed to initialize GLEW" << std::endl;
		glfwTerminate();
		return -1;
	}

	glViewport(0, 0, 800, 600);


	GLuint lightVAO;
	glGenVertexArrays(1, &lightVAO);
	glBindVertexArray(lightVAO);

	GLuint VBO;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
	glEnableVertexAttribArray(2);

	glEnableVertexAttribArray(0);

	glBindVertexArray(0);

	glm::mat4 model;
	glm::mat4 view;
	glm::mat4 projection;

	glEnable(GL_DEPTH_TEST);

	Shader* testShader = new Shader("test.vert", "test.frag");

	Shader* lightShader = new Shader("test.vert", "light.frag");

	Model* testModel = new Model("model/nanosuit.obj");

	while (!glfwWindowShouldClose(window))
	{
    
    
		processInput(window);
		glfwPollEvents();

		glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		testShader->Use();

		glUniform3f(glGetUniformLocation(testShader->getProgram(), "pointLights[0].position"), pointLightPositions[0].x, pointLightPositions[0].y, pointLightPositions[0].z);
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "pointLights[0].ambient"), 0.5f, 0.5f, 0.5f);
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "pointLights[0].diffuse"), 0.8f, 0.8f, 0.8f);
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "pointLights[0].specular"), 1.0f, 1.0f, 1.0f);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "pointLights[0].constant"), 1.0f);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "pointLights[0].linear"), 0.09);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "pointLights[0].quadratic"), 0.032);

		glUniform3f(glGetUniformLocation(testShader->getProgram(), "pointLights[1].position"), pointLightPositions[1].x, pointLightPositions[1].y, pointLightPositions[1].z);
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "pointLights[1].ambient"), 0.5f, 0.5f, 0.5f);
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "pointLights[1].diffuse"), 0.8f, 0.8f, 0.8f);
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "pointLights[1].specular"), 1.0f, 1.0f, 1.0f);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "pointLights[1].constant"), 1.0f);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "pointLights[1].linear"), 0.09);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "pointLights[1].quadratic"), 0.032);

		view = myCamera->getViewMat4();
		glUniformMatrix4fv(glGetUniformLocation(testShader->getProgram(), "view"), 1, GL_FALSE, glm::value_ptr(view));

		projection = glm::perspective(glm::radians(myCamera->getFov()), 800.0f / 600.0f, 0.1f, 100.0f);
		glUniformMatrix4fv(glGetUniformLocation(testShader->getProgram(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));

		model = glm::mat4();
		model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));
		model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f));
		glUniformMatrix4fv(glGetUniformLocation(testShader->getProgram(), "model"), 1, GL_FALSE, glm::value_ptr(model));

		glm::vec3 viewPos = myCamera->getCameraPos();
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "viewPos"), viewPos.x, viewPos.y, viewPos.z);
			
		testModel->Draw(*testShader);

		glBindVertexArray(lightVAO);
		lightShader->Use();
		glUniformMatrix4fv(glGetUniformLocation(lightShader->getProgram(), "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(lightShader->getProgram(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		for (GLuint i = 0; i < 2; i++)
		{
    
    
			model = glm::mat4();
			model = glm::translate(model, pointLightPositions[i]);
			model = glm::scale(model, glm::vec3(0.2f));
			glUniformMatrix4fv(glGetUniformLocation(lightShader->getProgram(), "model"), 1, GL_FALSE, glm::value_ptr(model));
			// 绘制灯立方体对象
			glDrawArrays(GL_TRIANGLES, 0, 36);
		}

		glfwSwapBuffers(window);
	}


	glfwTerminate();
	return 0;
}

Model.h

#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "shader.h"
#include "Mesh.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>

using namespace std;
//Model类
class Model
{
    
    
public:
    /*  函数   */
    Model(const GLchar* path)
    {
    
    
        loadModel(path);
    }
    void Draw(Shader shader);
private:
    /*  模型数据  */
    vector<Mesh> meshes;
    string directory;

    vector<Texture> textures_loaded;

    /*  函数   */
    void loadModel(string path);
    void processNode(aiNode* node, const aiScene* scene);
    Mesh processMesh(aiMesh* mesh, const aiScene* scene);
    vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type,
        string typeName);
};

Model.cpp

#include "Model.h"
#include "stb_image.h"

void Model::Draw(Shader shader) {
    
    
	for (GLuint i = 0; i < meshes.size(); i++) {
    
    
		meshes[i].Draw(shader);
	}
}

void Model::loadModel(string path)
{
    
    
    Assimp::Importer import;
    //参数:1.文件路径,2后处理选项。获取scene对象数据结构,是Assimp数据结构的根对象
    /*aiProcess_Triangulate:如果模型不是(全部)由三角形组成,应该转换所有的模型的原始几何形状为三角形
    * aiProcess_FlipUVs基于y轴翻转纹理坐标(通常是必须的,OpenGL大多数图像会被沿着y轴反转)
    * aiProcess_GenNormals : 如果模型没有包含法线向量,就为每个顶点创建法线。
    * aiProcess_SplitLargeMeshes : 把大的网格成几个小的的下级网格,当你渲染有一个最大数量顶点的限制时或者只能处理小块网格时很有用。
    * aiProcess_OptimizeMeshes : 和上个选项相反,它把几个网格结合为一个更大的网格。以减少绘制函数调用的次数的方式来优化。
    */
    const aiScene* scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);

    if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
    {
    
    
        //返回错误报告
        cout << "ERROR::ASSIMP::" << import.GetErrorString() << endl;
        return;
    }
    directory = path.substr(0, path.find_last_of('/'));

    //场景的根节点可能也会包含很多子节点和一个指向保存模型点云数据mMeshes[]的索引集合。根节点上的mMeshes[]里保存了实际了Mesh对象,
    // 而每个子节点上的mMesshes[]都只是指向根节点中的mMeshes[]的一个指针
    //递归函数processNode,先处理父节点再处理子节点
    processNode(scene->mRootNode, scene);
}

void Model::processNode(aiNode* node, const aiScene* scene) {
    
    
    // 添加当前节点中的所有Mesh
    for (GLuint i = 0; i < node->mNumMeshes; i++)
    {
    
    
        //用场景的mMeshes数组来检查每个节点的网格索引以获取相应的网格
        aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
        //processMesh返回一个网格对象
        this->meshes.push_back(this->processMesh(mesh, scene));
    }
    // 递归处理该节点的子孙节点
    for (GLuint i = 0; i < node->mNumChildren; i++)
    {
    
    
        this->processNode(node->mChildren[i], scene);
    }
}

//一个Mesh对象本身包含渲染所需的所有相关数据,比如顶点位置、法线向量、纹理坐标、面片及物体的材质
Mesh Model::processMesh(aiMesh* mesh, const aiScene* scene) {
    
    
    vector<Vertex> vertices;
    vector<GLuint> indices;
    vector<Texture> textures;
    for (GLuint i = 0; i < mesh->mNumVertices; i++)
    {
    
    
        Vertex vertex;
        // 处理顶点坐标
        glm::vec3 vector;//Assimp维持自己的数据类型,用于向量,材质,字符串等。转换到glm的数据类型时通常效果不加
        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]) {
    
    
            glm::vec2 vec;
            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);
    }

    // 每个网格有一个以面(faces)为单位的数组,每个面代表一个单独的图元(有点、线、三角面片、矩形面片)。一个面记录了一个图元的基本索引
    // 通过索引可在mMeshes[]中寻找对应顶点位置数据
    // 处理顶点索引
    for (GLuint i = 0; i < mesh->mNumFaces; i++) {
    
    
        aiFace face = mesh->mFaces[i];
        for (GLuint j = 0; j < face.mNumIndices; j++) {
    
    
            indices.push_back(*(face.mIndices + j));
        }
    }
    
    //每个网格还会包含一个Material(材质)对象用于指定物体的一些材质属性。如颜色、纹理贴图(漫反射贴图、高光贴图等)
    // 处理材质
    if (mesh->mMaterialIndex >= 0)
    {
    
    
        aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
        //一个材质存储了一个数组,为每个纹理类型提供纹理位置,不同纹理类型都以 aiTextureType_ 为前缀。
        vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
        textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
        vector<Texture> specularMaps = this->loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
        textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
         3. normal maps
        vector<Texture> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
        textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
        // 4. height maps
        vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
        textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());
    }

    return Mesh(vertices, indices, textures);
}

//加载一个纹理
unsigned int TextureFromFile(const char* path, string directory) {
    
    
    unsigned int texture;
    glGenTextures(1, &texture);

    string filename = string(path);
    filename = directory + '/' + filename;
    int width, height, nrComponents;
    unsigned char* image = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0);
    if (image) {
    
    
        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, texture);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_BYTE, image);
        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);
    }
    else {
    
    
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(image);
    return texture;
}

//遍历所有给定纹理类型的纹理位置,获取纹理的文件位置,然后加载生成纹理,把信息储存到Vertex结构体
vector<Texture> Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName) {
    
    
    vector<Texture> textures;
    for (GLuint i = 0; i < mat->GetTextureCount(type); i++) {
    
    
        aiString str;
        mat->GetTexture(type, i, &str); //纹理的文件位置存储在str
        bool skip = false;
        for (unsigned int j = 0; j < textures_loaded.size(); j++) {
    
    
            if (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;
}

Mesh.h

#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm.hpp>
#include<string.h>
#include <iostream>
#include <vector>
#include "shader.h"
#include <assimp/Importer.hpp>
#include <fstream>
#include <sstream>

using namespace std;
//顶点
struct Vertex {
    
    
	glm::vec3 Position;
	glm::vec3 Normal;
	glm::vec2 TexCoords;
    // tangent
    glm::vec3 Tangent;
    // bitangent
    glm::vec3 Bitangent;
};
//纹理
struct Texture {
    
    
	unsigned int id;
	string type;
	string path;
};
//Mesh类
class Mesh {
    
    
public:
    /*  网格数据  */
    vector<Vertex> vertices;
    vector<unsigned int> indices;
    vector<Texture> textures;
    /*  函数  */
    Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures);
    void Draw(Shader shader);
private:
    /*  渲染数据  */
    unsigned int VAO, VBO, EBO;
    /*  函数  */
    void setupMesh();
};

Mesh.cpp

#include "Mesh.h"

Mesh::Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<Texture>textures) {
    
    
	this->vertices = vertices;
	this->indices = indices;
	this->textures = textures;

	setupMesh();
}

void Mesh::setupMesh() {
    
    
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glGenBuffers(1, &EBO);

	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal));
	glEnableVertexAttribArray(2);
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, TexCoords));

	glEnableVertexAttribArray(3);
	glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));
	// vertex bitangent
	glEnableVertexAttribArray(4);
	glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent));

	glBindVertexArray(0);
}

void Mesh::Draw(Shader shader) {
    
    
	GLuint diffuseNr = 1;
	GLuint specularNr = 1;
	unsigned int normalNr = 1;
	unsigned int heightNr = 1;
	for(GLuint i = 0; i < this->textures.size(); i++) {
    
    
		glActiveTexture(GL_TEXTURE0 + i); // 在绑定纹理前需要激活适当的纹理单元
		// 检索纹理序列号 (N in diffuse_textureN)
		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++); // transfer unsigned int to string
		else if (name == "texture_height")
			number = std::to_string(heightNr++); // transfer unsigned int to string

		GLint id = glGetUniformLocation(shader.getProgram(), (name + number).c_str());
		glUniform1f(id, i);

		glBindTexture(GL_TEXTURE_2D, textures[i].id);
	}

	glBindVertexArray(VAO);
	glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(indices.size()), GL_UNSIGNED_INT, 0);
	glBindVertexArray(0);

	glActiveTexture(GL_TEXTURE0);
}

vertex shader

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;

out vec2 TexCoords;
out vec3 Normal;
out vec3 FragPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    
    
    TexCoords = aTexCoords;    
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    FragPos = vec3(model * vec4(aPos, 1.0f));
    Normal = mat3(transpose(inverse(model))) * aNormal;
}

fragment shader

#version 330 core
out vec4 FragColor;

in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoords;

struct PointLight {
    
    
    vec3 position;

    float constant;
    float linear;
    float quadratic;  

    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};  
uniform PointLight pointLights[2];

uniform vec3 viewPos;

uniform sampler2D texture_diffuse1;
uniform sampler2D texture_specular1;

void main()
{
    
        
    vec3 normal = normalize(Normal);
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 a = vec3(0.0f,0.0f,0.0f);
    vec3 d = vec3(0.0f,0.0f,0.0f);
    vec3 s = vec3(0.0f,0.0f,0.0f);
    for(int i = 0; i < 2; i++){
    
    
        PointLight light = pointLights[i];
        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.0f);
        float distance    = length(light.position - FragPos);
        float attenuation = 1.0f / (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;
        a += ambient;
        d += diffuse;
        s += specular;
    }
    FragColor =  vec4((a + d + s), 1.0);
}

Guess you like

Origin blog.csdn.net/Mhypnos/article/details/130753956