蚌埠市重点工程建设管理局网站,建设酒类产品网站的好处,抓取wordpress背景图片,wordpress凌风教程OpenGLAssimp模型加载库构建Assimp网格网格渲染Assimp
我们不太能够对像是房子、汽车或者人形角色这样的复杂形状手工定义所有的顶点、法线和纹理坐标。我们要的是将这些模型(Model)导入(Import)到程序当中。模型通常都由3D艺术家在Blender、3DS Max或者Maya这样的工具中精心制…
OpenGLAssimp模型加载库构建Assimp网格网格渲染Assimp
我们不太能够对像是房子、汽车或者人形角色这样的复杂形状手工定义所有的顶点、法线和纹理坐标。我们要的是将这些模型(Model)导入(Import)到程序当中。模型通常都由3D艺术家在Blender、3DS Max或者Maya这样的工具中精心制作。上述的建模工具可以让艺术家创建复杂的形状使用一种叫做UV映射的手段来应用贴图。将会在导出到模型文件的时候自动生成所有的顶点坐标、顶点法线以及纹理坐标。 我们需要解析这些导出的模型文件以及提取有用的信息把它们存储为OpenGL能够理解的格式。
模型的文件格式有很多种每一种都会以它们自己的方式来导出模型数据。像是Wavefront的.obj这样的模型格式只包含了模型数据以及材质信息比如模型颜色和漫反射/镜面光贴图。而以XML为基础的Collada文件格式则非常的丰富包含模型、光照、多种材质、动画数据、摄像机、完整的场景信息等等。 Wavefront的.obj格式通常被认为是一个易于解析的模型格式。建议至少去Wavefront的wiki页面上看看文件格式的信息是如何封装的。这应该能让你认识到模型文件的基本结构。不同种类的文件格式有很多它们之间通常并没有一个通用的结构。想从这些文件格式中导入模型的话我们必须要去自己对每一种需要导入的文件格式写一个导入器。很幸运的是正好有一个库专门处理这个问题。
模型加载库
模型导入库Assimp它是Open Asset Import Library开放的资产导入库的缩写。 能够导入很多种不同的模型文件格式它会将所有的模型数据加载到Assimp的通用数据结构种。当Assimp加载完模型之后我们就能够从Assimp的数据结构中提取我们所需的所有数据了。由于Assimp的数据结构保持不变不论导入的是什么种类的文件格式它都能够将我们从这些不同的文件格式中抽象出来用同一种方式访问我们需要的数据。 当使用Assimp导入一个模型的时候通常会将整个模型加载到一个场景对象。包含导入的模型、场景中的所有数据。Assimp会将场景载入为一系列的节点每个节点包含了场景对象种所存储数据的索引每个节点都可以有任意数量的子节点。简化数据模型如下
和材质和网格(Mesh)一样所有的场景/模型数据都包含在Scene对象中。Scene对象也包含了场景根节点的引用。场景的Root node根节点可能包含子节点和其它的节点一样它会有一系列指向场景对象中mMeshes数组中储存的网格数据的索引。Scene下的mMeshes数组储存了真正的Mesh对象节点中的mMeshes数组保存的只是场景中网格数组的索引。一个Mesh对象本身包含了渲染所需要的所有相关数据像是顶点位置、法向量、纹理坐标、面(Face)和物体的材质。一个网格包含了多个面。Face代表的是物体的渲染图元(Primitive)三角形、方形、点。一个面包含了组成图元的顶点的索引。由于顶点和索引是分开的使用一个索引缓冲来渲染是非常简单的之前章节中画三角形。最后一个网格也包含了一个Material对象它包含了一些函数能让我们获取物体的材质属性比如说颜色和纹理贴图比如漫反射和镜面光贴图。
所以我们需要做的第一件事是将一个物体加载到Scene对象中遍历节点获取对应的Mesh对象我们需要递归搜索每个节点的子节点并处理每个Mesh对象来获取顶点数据、索引以及它的材质属性。最终的结果是一系列的网格数据我们会将它们包含在一个Model对象中。 补充网格 当使用建模工具对物体建模的时候艺术家通常不会用单个形状创建出整个模型。通常每个模型都由几个子模型/形状组合而成。组合模型的每个单独的形状就叫做一个网格(Mesh)。比如说有一个人形的角色艺术家通常会将头部、四肢、衣服、武器建模为分开的组件并将这些网格组合而成的结果表现为最终的模型。一个网格是我们在OpenGL中绘制物体所需的最小单位顶点数据、索引和材质属性。一个模型通常会包括多个网格。
构建Assimp
需要创建自己的Model和Mesh类来加载并使用刚才的结构存储导入后的模型。 要绘制一个模型不需要将整个模型渲染成一个整体只需要渲染组成模型的每个独立的网格就可以了。先将Assimp包包含到工程当中。 下载Assimp可以参考这两个文章 https://blog.csdn.net/derbi123123/article/details/105783048/ https://blog.csdn.net/xiaopenga520/article/details/126522776
网格
网格代表的是单个可绘制实体先定义一个网格类。 一个网格最少需要一系列顶点每个顶点包含一个位置向量一个法向量一个纹理坐标向量。还要包含用于索引绘制的索引纹理形式的材质数据——漫反射/镜面光贴图 把需要的向量存储到下面的结构体中可以用来索引每个顶点属性。
struct Vertex {glm::vec3 Position;glm::vec3 Normal;glm::vec2 TexCoords;
};再将纹理数据整理到一个结构体中
struct Texture {unsigned int id;string type;
};存储了纹理ID和纹理类型比如漫反射贴图或者是镜面光贴图 再定义网格类
class Mesh {public:/* 网格数据 */vectorVertex vertices;vectorunsigned int indices;vectorTexture textures;/* 函数 */Mesh(vectorVertex vertices, vectorunsigned int indices, vectorTexture textures);void Draw(Shader shader);private:/* 渲染数据 */unsigned int VAO, VBO, EBO;/* 函数 */void setupMesh();
}; 上述类结构把所有数据在构造器中进行赋值在setupMesh函数中初始化缓冲最后使用Draw来绘制网格。构造器函数如下
//只需要使用构造器的参数设置类的公有变量
Mesh(vectorVertex vertices, vectorunsigned int indices, vectorTexture textures)
{this-vertices vertices;this-indices indices;this-textures textures;setupMesh();
}在把网格数据用于渲染之前还需要配置正确的缓冲通过顶点属性指针 定义顶点着色器。setupMesh函数如下
void 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), (void*)0);// 顶点法线glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));// 顶点纹理坐标glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));glBindVertexArray(0);
} C结构体有一个很棒的特性它们的内存布局是连续的。如果我们将结构体作为一个数据数组使用那么它将会以顺序排列结构体的变量这将会直接转换为我们在数组缓冲中所需要的float实际上是字节数组。比如
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];所以直接传入一大列的Vertex结构体的指针作为缓冲的数据它们将会完美地转换为glBufferData所能用的参数
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices[0], GL_STATIC_DRAW);sizeof运算也可以用在结构体上来计算它的字节大小。这个应该是32字节的8个float * 每个4字节
结构体的另一个很好的用途是它的预处理指令offsetof(s, m)它的第一个参数是一个结构体第二个参数是这个结构体中变量的名字。这个宏会返回那个变量距结构体头部的字节偏移量(Byte Offset)。这正好可以用在定义glVertexAttribPointer函数中的偏移参数
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal)); 偏移量现在是使用offsetof来定义了在这里它会将法向量的字节偏移量设置为结构体中法向量的偏移量也就是3个float即12字节。注意我们同样将步长参数设置为了Vertex结构体的大小。
网格渲染
在渲染网格之前在调用glDrawElements函数之前需要先绑定相应的纹理。并不知道这个网格如果有的话有多少纹理、纹理是什么类型的。所以我们该如何在着色器中设置纹理单元和采样器 设定一个命名标准每个漫反射纹理被命名为texture_diffuseN每个镜面光纹理被命名为texture_specularN。N的范围是1到纹理采样器最大允许的数字。 根据这个标准在着色器中定义任意需要数量的纹理采样器。渲染代码如下
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); // 在绑定之前激活相应的纹理单元// 获取纹理序号diffuse_textureN 中的 Nstring 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);shader.setInt((material. name number).c_str(), i);glBindTexture(GL_TEXTURE_2D, textures[i].id);}glActiveTexture(GL_TEXTURE0);// 绘制网格glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);glBindVertexArray(0);
}我们首先计算了每个纹理类型的N-分量并将其拼接到纹理类型字符串上来获取对应的uniform名称。接下来我们查找对应的采样器将它的位置值设置为当前激活的纹理单元并绑定纹理。这也是我们在Draw函数中需要着色器的原因。我们也将material.添加到了最终的uniform名称中因为我们希望将纹理储存在一个材质结构体中这在每个实现中可能都不同。
综上代码如下
#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 learnopengl/shader.h#include string
#include vector
using namespace std;#define MAX_BONE_INFLUENCE 4struct Vertex {// positionglm::vec3 Position;// normalglm::vec3 Normal;// texCoordsglm::vec2 TexCoords;// tangentglm::vec3 Tangent;// bitangentglm::vec3 Bitangent;//bone indexes which will influence this vertexint m_BoneIDs[MAX_BONE_INFLUENCE];//weights from each bonefloat m_Weights[MAX_BONE_INFLUENCE];
};struct Texture {unsigned int id;string type;string path;
};class Mesh {
public:// mesh DatavectorVertex vertices;vectorunsigned int indices;vectorTexture textures;unsigned int VAO;// constructorMesh(vectorVertex vertices, vectorunsigned int indices, vectorTexture 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 meshvoid Draw(Shader shader) {// bind appropriate texturesunsigned 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); // 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(diffuseNr);else if(name texture_specular)number std::to_string(specularNr); // transfer unsigned int to stringelse if(name texture_normal)number std::to_string(normalNr); // transfer unsigned int to stringelse if(name texture_height)number std::to_string(heightNr); // transfer unsigned int to string// now set the sampler to the correct texture unitglUniform1i(glGetUniformLocation(shader.ID, (name number).c_str()), i);// and finally bind the textureglBindTexture(GL_TEXTURE_2D, textures[i].id);}// draw meshglBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, static_castunsigned int(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;// initializes all the buffer objects/arraysvoid setupMesh(){// create buffers/arraysglGenVertexArrays(1, VAO);glGenBuffers(1, VBO);glGenBuffers(1, EBO);glBindVertexArray(VAO);// load data into vertex buffersglBindBuffer(GL_ARRAY_BUFFER, VBO);// A great thing about structs is that their memory layout is sequential for all its items.// The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which// again translates to 3/2 floats which translates to a byte array.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);// set the vertex attribute pointers// vertex PositionsglEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);// vertex normalsglEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));// vertex texture coordsglEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));// vertex tangentglEnableVertexAttribArray(3);glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));// vertex bitangentglEnableVertexAttribArray(4);glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent));// idsglEnableVertexAttribArray(5);glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), (void*)offsetof(Vertex, m_BoneIDs));// weightsglEnableVertexAttribArray(6);glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, m_Weights));glBindVertexArray(0);}
};
#endif
文章转载自: http://www.morning.pumali.com.gov.cn.pumali.com http://www.morning.qxlyf.cn.gov.cn.qxlyf.cn http://www.morning.rcbdn.cn.gov.cn.rcbdn.cn http://www.morning.cnyqj.cn.gov.cn.cnyqj.cn http://www.morning.qlry.cn.gov.cn.qlry.cn http://www.morning.ypmqy.cn.gov.cn.ypmqy.cn http://www.morning.jtdrz.cn.gov.cn.jtdrz.cn http://www.morning.mjwnc.cn.gov.cn.mjwnc.cn http://www.morning.qkqzm.cn.gov.cn.qkqzm.cn http://www.morning.nbsfb.cn.gov.cn.nbsfb.cn http://www.morning.qggcc.cn.gov.cn.qggcc.cn http://www.morning.txmlg.cn.gov.cn.txmlg.cn http://www.morning.jbpodhb.cn.gov.cn.jbpodhb.cn http://www.morning.wkhfg.cn.gov.cn.wkhfg.cn http://www.morning.zqwp.cn.gov.cn.zqwp.cn http://www.morning.yfrlk.cn.gov.cn.yfrlk.cn http://www.morning.wjplr.cn.gov.cn.wjplr.cn http://www.morning.gskzy.cn.gov.cn.gskzy.cn http://www.morning.xtrnx.cn.gov.cn.xtrnx.cn http://www.morning.tqygx.cn.gov.cn.tqygx.cn http://www.morning.bnlch.cn.gov.cn.bnlch.cn http://www.morning.tsmxh.cn.gov.cn.tsmxh.cn http://www.morning.nyqzz.cn.gov.cn.nyqzz.cn http://www.morning.hjjkz.cn.gov.cn.hjjkz.cn http://www.morning.kqzt.cn.gov.cn.kqzt.cn http://www.morning.ktblf.cn.gov.cn.ktblf.cn http://www.morning.yxlpj.cn.gov.cn.yxlpj.cn http://www.morning.nxcgp.cn.gov.cn.nxcgp.cn http://www.morning.hfxks.cn.gov.cn.hfxks.cn http://www.morning.yqqxj1.cn.gov.cn.yqqxj1.cn http://www.morning.cttgj.cn.gov.cn.cttgj.cn http://www.morning.llqky.cn.gov.cn.llqky.cn http://www.morning.flxgx.cn.gov.cn.flxgx.cn http://www.morning.ndynz.cn.gov.cn.ndynz.cn http://www.morning.wnnfh.cn.gov.cn.wnnfh.cn http://www.morning.lgkbn.cn.gov.cn.lgkbn.cn http://www.morning.mzkn.cn.gov.cn.mzkn.cn http://www.morning.jzfxk.cn.gov.cn.jzfxk.cn http://www.morning.gcftl.cn.gov.cn.gcftl.cn http://www.morning.lxhgj.cn.gov.cn.lxhgj.cn http://www.morning.cspwj.cn.gov.cn.cspwj.cn http://www.morning.tdwjj.cn.gov.cn.tdwjj.cn http://www.morning.rkrl.cn.gov.cn.rkrl.cn http://www.morning.bhrbr.cn.gov.cn.bhrbr.cn http://www.morning.kkqgf.cn.gov.cn.kkqgf.cn http://www.morning.mbrbg.cn.gov.cn.mbrbg.cn http://www.morning.nmpdm.cn.gov.cn.nmpdm.cn http://www.morning.hrpbq.cn.gov.cn.hrpbq.cn http://www.morning.wqgr.cn.gov.cn.wqgr.cn http://www.morning.qghjc.cn.gov.cn.qghjc.cn http://www.morning.wtdhm.cn.gov.cn.wtdhm.cn http://www.morning.nbnpb.cn.gov.cn.nbnpb.cn http://www.morning.rlbg.cn.gov.cn.rlbg.cn http://www.morning.rrcxs.cn.gov.cn.rrcxs.cn http://www.morning.zwppm.cn.gov.cn.zwppm.cn http://www.morning.wrkhf.cn.gov.cn.wrkhf.cn http://www.morning.fjglf.cn.gov.cn.fjglf.cn http://www.morning.mgwdp.cn.gov.cn.mgwdp.cn http://www.morning.nfbkz.cn.gov.cn.nfbkz.cn http://www.morning.zlrsy.cn.gov.cn.zlrsy.cn http://www.morning.sfswj.cn.gov.cn.sfswj.cn http://www.morning.dskmq.cn.gov.cn.dskmq.cn http://www.morning.xmnlc.cn.gov.cn.xmnlc.cn http://www.morning.pqkgb.cn.gov.cn.pqkgb.cn http://www.morning.qxljc.cn.gov.cn.qxljc.cn http://www.morning.qiyelm.com.gov.cn.qiyelm.com http://www.morning.sjjq.cn.gov.cn.sjjq.cn http://www.morning.mqlsf.cn.gov.cn.mqlsf.cn http://www.morning.thbqp.cn.gov.cn.thbqp.cn http://www.morning.mnlk.cn.gov.cn.mnlk.cn http://www.morning.rwls.cn.gov.cn.rwls.cn http://www.morning.zcxjg.cn.gov.cn.zcxjg.cn http://www.morning.zbnts.cn.gov.cn.zbnts.cn http://www.morning.lhhkp.cn.gov.cn.lhhkp.cn http://www.morning.mtmnk.cn.gov.cn.mtmnk.cn http://www.morning.glnmm.cn.gov.cn.glnmm.cn http://www.morning.qbwtb.cn.gov.cn.qbwtb.cn http://www.morning.wzjhl.cn.gov.cn.wzjhl.cn http://www.morning.dgng.cn.gov.cn.dgng.cn http://www.morning.nnttr.cn.gov.cn.nnttr.cn