OpenGL基础27:网格
Posted 1994july
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL基础27:网格相关的知识,希望对你有一定的参考价值。
一、网格
网格(Mesh):一个模型会由几个子模型/形状组合拼接而成,而模型中的那些子模型/形状就是一个网格,一个网格在OpenGL中是绘制物体的最小单位
从字面上的意思来看就是下面这个东西:
其实差不多,如果你是游戏开放相关的工作者,又或者了解过图形学,应该对网格(Mesh)这个词很熟悉,大概印象是下面这样的:
理解的没问题的话,网格就是上面这些东东,不过对于大多数游戏开发者更喜欢用Mesh这个词而并非网格,在Assimp里面
- 一个Mesh对象本身包含渲染所需的所有相关数据,比如顶点位置、法线向量、纹理坐标、面片及物体的材质
- 一个Mesh会包含多个面片(Face)。一个面片表示渲染中的一个最基本的形状单位,即图元(基本图元有点、线、三角面片、矩形面片),其记录了一个图元的顶点索引,通过这个索引,可以寻找到对应的顶点位置数据
- 一个Mesh还会包含一个材质(Material)对象用于指定物体的一些材质属性。如颜色、纹理贴图
二、Mesh类
和之前的Camera类和Shader类一样,实现一个Mesh类,以满足:
- 只需要将顶点数据和纹理数据传入,便可自动配置正确的缓冲,并通过顶点属性指针定义顶点着色器的布局
- 提供Draw()方法,完成纹理的绑定和绘制
#ifndef MESH_H
#define MESH_H
#include<vector>
#include<string>
#include<fstream>
#include<sstream>
#include"Shader.h"
#include<opengl/glew.h>
#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<assimp/Importer.hpp>
#include<assimp/scene.h>
#include<assimp/postprocess.h>
using namespace std;
struct Vertex
{
glm::vec3 Position; //顶点
glm::vec3 Normal; //法线
glm::vec2 TexCoords; //贴图
};
struct Texture
{
GLuint id;
string type; //贴图类型:漫反射贴图还是镜面贴图(后面还有法线贴图、错位贴图等)
aiString path; //贴图路径
};
class Mesh
{
public:
vector<Vertex> vertices;
vector<GLuint> indices; //索引
vector<Texture> textures;
Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<Texture> textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
this->setupMesh();
}
void Draw(Shader shader)
{
GLuint diffuseNr = 1;
GLuint specularNr = 1;
for (GLuint i = 0; i < this->textures.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i);
stringstream ss;
string name = this->textures[i].type;
if (name == "texture_diffuse")
ss << diffuseNr++;
else if (name == "texture_specular")
ss << specularNr++;
name = name + ss.str();
glUniform1i(glGetUniformLocation(shader.Program, name.c_str()), i);
//这样的话,着色器中的纹理名就必须有一个对应的规范,例如“texture_diffuse3”代表第三个漫反射贴图
//方法不唯一,这是最好理解/最简单的一种规范/写法
glBindTexture(GL_TEXTURE_2D, this->textures[i].id);
}
glUniform1f(glGetUniformLocation(shader.Program, "material.shininess"), 16.0f); //暂时写死反光度,也可配置
glBindVertexArray(this->VAO);
glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0); //EBO绘制
for (GLuint i = 0; i < this->textures.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, 0);
}
glBindVertexArray(0);
}
private:
GLuint VAO, VBO, EBO;
void setupMesh()
{
glGenVertexArrays(1, &this->VAO);
glGenBuffers(1, &this->VBO);
glGenBuffers(1, &this->EBO);
glBindVertexArray(this->VAO);
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(Vertex), &this->vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), &this->indices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
//别忘了struct中内存是连续的
//offsetof():获取结构体属性的偏移量
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));
glBindVertexArray(0);
}
};
#endif
都是之前已经掌握的知识,相当于就是从主程序里移一下代码
别忘了struct的内存布局:
Vertex vertex;
vertex.Position = glm::vec3(0.2f, 0.4f, 0.6f);
vertex.Normal = glm::vec3(0.0f, 1.0f, 0.0f);
vertex.TexCoords = glm::vec2(1.0f, 0.0f);
// = [0.2f, 0.4f, 0.6f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f];
以上是关于OpenGL基础27:网格的主要内容,如果未能解决你的问题,请参考以下文章