opengl网格mesh

  • 和材质和网格(Mesh)一样,所有的场景/模型数据都包含在Scene对象中。Scene对象也包含了场景根节点的引用。
  • 场景的Root node(根节点)可能包含子节点(和其它的节点一样),它会有一系列指向场景对象中mMeshes数组中储存的网格数据的索引。Scene下的mMeshes数组储存了真正的Mesh对象,节点中的mMeshes数组保存的只是场景中网格数组的索引。
  • 一个Mesh对象本身包含了渲染所需要的所有相关数据,像是顶点位置、法向量、纹理坐标、面(Face)和物体的材质。
  • 一个网格包含了多个面。Face代表的是物体的渲染图元(Primitive)(三角形、方形、点)。一个面包含了组成图元的顶点的索引。由于顶点和索引是分开的,使用一个索引缓冲来渲染是非常简单的(见你好,三角形)。
    最后,一个网格也包含了一个Material对象,它包含了一些函数能让我们获取物体的材质属性,比如说颜色和纹理贴图(比如漫反射和镜面光贴图)。

结构:在这里插入图片描述

在这里插入图片描述

  • MESH.h代码:注意这里边的setupmesh函数已经取代了VOAset,注意这里边将纹理部分分为绑定纹理放到主文件的构造mesh中和绘制纹理放到mesh文件的Draw中
#pragma once
#ifndef MESH_H
#define MESH_H

#include <glad/glad.h> // holds all OpenGL type declarations

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "Shader.h"

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>

using namespace std;

struct Vertex {
    // position
    glm::vec3 Position;
    // normal
    glm::vec3 Normal;
    // texCoords
    glm::vec2 TexCoords;
};

struct Texture {
    unsigned int id;
    string type;
    string path;
};

class Mesh {
public:
    /*  Mesh Data  */
    vector<Vertex> vertices;
    vector<unsigned int> indices;
    vector<Texture> textures;
    unsigned int VAO;

    /*  Functions  */
    // constructor
    Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures)
    {
        this->vertices = vertices;
        this->indices = indices;
        this->textures = textures;
        // now that we have all the required data, set the vertex buffers and its attribute pointers.
        setupMesh();
    }

    // render the mesh
    void Draw(Shader shader)
    {	
    	//加载与绘制纹理
        unsigned int diffuseNr = 1;
        unsigned int specularNr = 1;
        for (unsigned int i = 0; i < textures.size(); i++)
        {
            glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
            // retrieve texture number (the N in diffuse_textureN)
            //这里要绑定着色器里边的名字
            string number;
            string name = textures[i].type;
            if (name == "texture_diffuse")
                number = std::to_string((long double)diffuseNr++);
            else if (name == "texture_specular")
                number = std::to_string((long double)specularNr++); // transfer unsigned int to stream

                                                     // now set the sampler to the correct texture unit
            glUniform1i(glGetUniformLocation(shader.ID, (name + number).c_str()), i);
            // and finally bind the texture
            glBindTexture(GL_TEXTURE_2D, textures[i].id);
        }

        // draw mesh
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        // always good practice to set everything back to defaults once configured.
        glActiveTexture(GL_TEXTURE0);
    }

private:
    /*  Render data  */
    unsigned int VBO, EBO;

    /*  Functions    */
    // initializes all the buffer objects/arrays
    void setupMesh()    //取代VAOset
    {
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glGenBuffers(1, &EBO);

        glBindVertexArray(VAO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

        //往显卡写值,分配显存空间GL_STATIC_DRAW表示,值不修改
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);

        //告诉显卡,值的结构 position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
        glEnableVertexAttribArray(0);
        //告诉显卡,值的结构 法线
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
        glEnableVertexAttribArray(1);
        //告诉显卡,值的结构 纹理坐标
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
        glEnableVertexAttribArray(2);

        glEnableVertexAttribArray(0);
    }
};
#endif

main函数修改:注:1.main函数中while循环里边在画函数之前绑定VAO这个操作因为使用的是glDrawElements函数,所以都不需要了;2.VAOset和texture函数都放到了mesh类当中,其中在创建mesh的时候就已经者加载好了,mesh类中的直接进行纹理绑定

  • main函数的修改:注意没有了vao和texture函数,使用了mesh的draw函数进行纹理绑定并且最终绘制结果
int main() {
	//初始化
	GLFWwindow* window = init(); //创建一个窗口指针,因为里边是一个空指针所有init函数必须改变类型
	//着色    
	Shader lightShader("lamp.vert", "lamp.frag");
	Shader cubeShader("cube.vert", "cube.frag");    //使用封装shader类

	glm::mat4 trans = glm::mat4(1.0f);  //单位矩阵
	glm::mat4 model = glm::mat4(1.0f);  //模型矩阵:用于物体坐标转化为世界坐标
	glm::mat4 view = glm::mat4(1.0f);

	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);   //防止窗口对鼠标进行拦截
	//渲染引擎
	glEnable(GL_DEPTH_TEST);    //打开深度缓存

	//使用mesh生成一个mesh对象
	Mesh mesh = processCubeMesh();

	while (!glfwWindowShouldClose(window)) {    //当需要退出时候退出

		//因为每一个循环的进入时间不一样,确保推进的距离一样,要用到时间差
		currentFrame = glfwGetTime();
		deltaTime = currentFrame - lastFrame;
		lastFrame = currentFrame;

		processInput(window); //每个周期都调用键位函数

		//动态变化摄像机位置
		float radius = 10.0f;   //半径
		float camX = sin(glfwGetTime()) * radius;
		float camZ = cos(glfwGetTime()) * radius;

		//设置颜色值和透明度,需要链接opengl32库才行
		glClearColor(0.2f, 0.3f, 0.3f, 0.1f);   //背景
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   //清理颜色或者深度缓存

		//绘制立方体
		trans = glm::mat4(1.0f);
		model = glm::translate(trans, cubePositions[0]);    //只变换位置用来区分不同的立方体
		model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(1.5f, 3.0f, 0.0f));  //角度(逆向),绕
		view = camera.GetViewMatrix();

		glm::mat4 projection;   //投影
		projection = glm::perspective(glm::radians(camera.fov), 800.0f / 600.0f, 0.1f, 100.0f);  //透视投影:FOV,屏幕长宽比,近,远。
		cubeShader.useShader();
		//传值给传送多个矩阵
		glUniformMatrix4fv(glGetUniformLocation(cubeShader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniformMatrix4fv(glGetUniformLocation(cubeShader.ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(cubeShader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniform4f(glGetUniformLocation(cubeShader.ID, "lightPos"), cubePositions[1].r, cubePositions[1].g, cubePositions[1].b, 1);   //注意lightposion的三个值,现在是齐次坐标
		glUniform3f(glGetUniformLocation(cubeShader.ID, "viewPos"), camera.Position.r, camera.Position.g, camera.Position.b);   //观察的方向
		glUniform3f(glGetUniformLocation(cubeShader.ID, "front"), camera.Front.r, camera.Front.g, camera.Front.b);   //相机朝向的方向
		glUniform3f(glGetUniformLocation(cubeShader.ID, "objectColor"), 1.0f, 0.5f, 0.31f);

		glUniform3f(glGetUniformLocation(cubeShader.ID, "lightColor"), 1.0f, 1.0f, 1.0f);
		//绘制mesh
		mesh.Draw(cubeShader);

		//绑定第二个立方体
		model = glm::translate(trans, cubePositions[2]);
		glUniformMatrix4fv(glGetUniformLocation(cubeShader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
		mesh.Draw(cubeShader);//画第二个立方体

		//绘制光源
		trans = glm::mat4(1.0f);
		model = glm::translate(trans, cubePositions[1]);
		model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f));
		trans = projection * view * model;
		lightShader.useShader();    //注意这是新的useShader了
		glUniform3f(glGetUniformLocation(lightShader.ID, "lightColor"), 1.0f, 1.0f, 1.0f);
		glUniformMatrix4fv(glGetUniformLocation(lightShader.ID, "transform"), 1/*个矩阵*/, GL_FALSE,
			glm::value_ptr(trans));  //设置偏移矩阵
		mesh.Draw(lightShader);

		glfwSwapBuffers(window);
		glfwPollEvents();   //立即处理已经到位的事件,如果没有这个就会一直渲染而不触发事件       
	}
	//退出
	glfwTerminate();
	return 0;
}
  • 创建初始mesh函数
//创建初始mesh
Mesh processCubeMesh()
{
    vector<Vertex> Vers;
    vector<unsigned int> Indis;
    Vers.reserve(36);
    Indis.reserve(288);
    for (int i = 0; i < 288; i++)
    {
        Indis.push_back(i);
    }
    for (int i = 0; i < 36; i++)
    {
        Vertex vertex;

        vertex.Position[0] = vertices[i * 8 + 0];
        vertex.Position[1] = vertices[i * 8 + 1];
        vertex.Position[2] = vertices[i * 8 + 2];

        vertex.Normal[0] = vertices[i * 8 + 3];
        vertex.Normal[1] = vertices[i * 8 + 4];
        vertex.Normal[2] = vertices[i * 8 + 5];

        vertex.TexCoords[0] = vertices[i * 8 + 6];
        vertex.TexCoords[1] = vertices[i * 8 + 7];
        Vers.push_back(vertex);
    }
    vector<Texture> textures;
    Texture _tex;
    _tex.id = 1;
    _tex.type = "texture_diffuse";
    _tex.path = "container2.png";
    textures.push_back(_tex);
    _tex.id = 2;
    _tex.type = "texture_specular";
    _tex.path = "container2_specular.png";
    textures.push_back(_tex);

    Mesh ourMesh(Vers, Indis, textures);
    //加载纹理
    unsigned int texture[16];
    for (unsigned int i = 0; i < textures.size(); i++)
    {
    	//textures有多少个纹理就加载多少次
        glGenTextures(1, &texture[i]);
        int width, height, nrChannels;
        unsigned char* data;
        stbi_set_flip_vertically_on_load(true);
        glBindTexture(GL_TEXTURE_2D, texture[i]);
        data = stbi_load(textures[i].path.c_str(), &width, &height, &nrChannels, 0);
        GLenum format;
        if (nrChannels == 1)
            format = GL_RED;
        else if (nrChannels == 3)
            format = GL_RGB;
        else if (nrChannels == 4)
            format = GL_RGBA;
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
        stbi_image_free(data);
    }

    return ourMesh;
}
  • 注意因为在使用mesh的Draw函数中的纹理绑定名字发生了改变所以,立方体的glsl着色器语言当中,所以着色器语言中的传值和用值都要发生改变
//引用
uniform sampler2D texture_diffuse1;
uniform sampler2D texture_specular1;
	//材质光
	material.ambient = vec3(texture(texture_diffuse1,TexCoords));	
	material.diffuse =	vec3(texture(texture_diffuse1,TexCoords));	//这里使用材质漫反射贴图而不用向量
	material.specular = vec3(texture(texture_specular1,TexCoords));	//这里使用的是第二个金属反光图片

结果没有发生改变在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenGL是一种图形绘制库,用于创建各种图形效果和动画。在绘制mesh网格)时,我们可以使用OpenGL的绘制函数和几何变换来实现。以下是使用OpenGL绘制mesh的一般步骤: 1. 初始化OpenGL环境:包括创建窗口、设置视口、初始化OpenGL相关设置等。 2. 加载mesh数据:读取网格模型的顶点、法线、纹理坐标等信息。通常可以使用支持多种文件格式的库来加载mesh数据,例如Open Asset Import Library(Assimp)。 3. 创建并绑定顶点缓冲对象(Vertex Buffer Object,VBO):将mesh的顶点数据(包括坐标、法线、纹理坐标等)存储到VBO中。 4. 创建并绑定索引缓冲对象(Index Buffer Object,IBO):将mesh的索引数据(指示顶点绘制顺序的索引值)存储到IBO中。 5. 创建着色器程序:编写顶点着色器和片段着色器,用于处理顶点和片段的着色逻辑。 6. 设置顶点属性指针:告诉OpenGL如何解析VBO中的数据,以便正确渲染mesh。 7. 启用深度测试:根据需要设置深度测试,以保证mesh的正确渲染顺序。 8. 绑定纹理(如果有):如果mesh需要贴图渲染,可以先加载纹理数据,并将其绑定到对应的纹理单元上。 9. 渲染mesh:使用顶点和索引缓冲对象绘制mesh。可以使用glDrawElements函数指定绘制方式(如三角形、线段等)和数量。 10. 释放资源:当绘制完成后,需要释放申请的缓冲对象、着色器程序、纹理等资源。 使用上述步骤,我们可以利用OpenGL绘制mesh,实现各种复杂的图形效果和动画。绘制mesh时,可以根据需求对材质、光照、纹理等进行调整,以获得想要的视觉效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值