首页 > 编程语言 >阅读《计算机图形学编程(使用OpenGL和C++)》11 - 加载外部obj模型

阅读《计算机图形学编程(使用OpenGL和C++)》11 - 加载外部obj模型

时间:2022-08-30 11:24:15浏览次数:82  
标签:11 std obj ImportedModel 图形学 back vector vt push

复杂的3D模型可以借助建模工具生成,这种工具能够在3D空间中构建任意形状并自动生成顶点、纹理坐标、顶点法向量等。模型生成后可导出成obj文件格式,这种格式有很多,OBJ文件很简单,我们可以相对容易地开发一个基本的导入器。在OBJ文件中,通过文本行的形式指定顶点几何数据、纹理坐标、法向量和其他信息。它有一些限制——例如,OBJ文件无法指定模型动画。

OBJ文件中的行,以字符标记开头,表示该行上的数据类型。一些常见的标签包括:

●v-几何(顶点位置)数据;

●vt-纹理坐标;

●vn-顶点法向量;

●f-面(通常是三角形中的顶点,每个元素的值分别是顶点列表、纹理坐标和法向量的索引。)。

obj格式文件导入器代码:

注意这个导入器非常有局限性,仅支持由单个三角形网格组成的OBJ模型(OBJ格式支持复合模型,但我们的简单导入器不支持),仅支持包含所有3个面属性字段的模型,它假设每行上的元素只用一个空格分隔。

ImportedModel.h,ImportedModel.cpp

  1 #pragma once
  2 #include <vector>
  3 #include <glm\glm.hpp>
  4 
  5 class ModelImporter
  6 {
  7 public:
  8     ModelImporter();
  9     ~ModelImporter();
 10     void parseOBJ(const char *filePath);
 11     int getNumVertices();
 12     std::vector<float> getVertices();
 13     std::vector<float> getTextureCoordinates();
 14     std::vector<float> getNormals();
 15 private:
 16     // 从OBJ文件读取的数值
 17     std::vector<float> vertVals;
 18     std::vector<float> stVals;
 19     std::vector<float> normVals;
 20     // 保存为顶点属性以供后续使用的数值
 21     std::vector<float> triangleVerts;
 22     std::vector<float> textureCoords;
 23     std::vector<float> normals;
 24 };
 25 
 26 class ImportedModel
 27 {
 28 public:
 29     ImportedModel(const char *filePath);
 30     ~ImportedModel();
 31     int getNumVertices();
 32     std::vector<glm::vec3> getVertices();
 33     std::vector<glm::vec2> getTextureCoords();
 34     std::vector<glm::vec3> getNormals();
 35 
 36 private:
 37     int numVertices;
 38     std::vector<glm::vec3> vertices;
 39     std::vector<glm::vec2> texCoords;
 40     std::vector<glm::vec3> normalVecs;
 41     ModelImporter a;
 42 };
 43 
 44 #include "ImportedModel.h"
 45 #include <fstream>
 46 #include <sstream>
 47 using namespace std;
 48 
 49 ModelImporter::ModelImporter() {}
 50 
 51 ModelImporter::~ModelImporter(){}
 52 
 53 void ModelImporter::parseOBJ(const char *filePath)
 54 {
 55     float x, y, z;
 56     string content;
 57     ifstream fileStream(filePath, ios::in);
 58     string line = "";
 59     while (!fileStream.eof())
 60     {
 61         getline(fileStream, line);
 62         if (line.compare(0, 2, "v ") == 0) // 顶点位置("v"的情况)
 63         {
 64             stringstream ss(line.erase(0, 1));
 65             ss >> x; // 提取顶点位置数值
 66             ss >> y;
 67             ss >> z;
 68             vertVals.push_back(x);
 69             vertVals.push_back(y);
 70             vertVals.push_back(z);
 71         }
 72 
 73         if (line.compare(0, 2, "vt") == 0) // 纹理坐标("vt"的情况)
 74         {
 75             stringstream ss(line.erase(0, 2));
 76             ss >> x; // 提取纹理坐标数值
 77             ss >> y;
 78             stVals.push_back(x);
 79             stVals.push_back(y);
 80         }
 81 
 82         if (line.compare(0, 2, "vn") == 0) // 顶点法向量("vn"的情况)
 83         {
 84             stringstream ss(line.erase(0, 2));
 85             ss >> x; // 提取法向量数值
 86             ss >> y;
 87             ss >> z;
 88             normVals.push_back(x);
 89             normVals.push_back(y);
 90             normVals.push_back(z);
 91         }
 92 
 93         if (line.compare(0, 2, "f ") == 0) // 三角形面("f"的情况)
 94         {
 95             string oneCorner, v, t, n;
 96             stringstream ss(line.erase(0, 2));
 97             for (int i = 0; i < 3; i++)
 98             {
 99                 getline(ss, oneCorner, ' '); // 提取三角形面引用
100                 stringstream oneCornerSS(oneCorner);
101                 getline(oneCornerSS, v, '/');
102                 getline(oneCornerSS, t, '/');
103                 getline(oneCornerSS, n, '/');
104                 int vertRef = (stoi(v) - 1) * 3; // "stoi"将字符串转化为整型
105                 int tcRef = (stoi(t) - 1) * 2;
106                 int normRef = (stoi(n) - 1) * 3;
107                 triangleVerts.push_back(vertVals[vertRef]); // 构建顶点向量
108                 triangleVerts.push_back(vertVals[vertRef + 1]);
109                 triangleVerts.push_back(vertVals[vertRef + 2]);
110                 textureCoords.push_back(stVals[tcRef]); // 构建纹理坐标向量
111                 textureCoords.push_back(stVals[tcRef + 1]);
112                 normals.push_back(normVals[normRef]); // 法向量的向量
113                 normals.push_back(normVals[normRef + 1]);
114                 normals.push_back(normVals[normRef + 2]);
115             }
116         }
117     }
118 }
119 
120 int ModelImporter::getNumVertices()
121 {
122     return (triangleVerts.size() / 3);
123 }
124 
125 vector<float> ModelImporter::getVertices()
126 {
127     return triangleVerts;
128 }
129 
130 vector<float> ModelImporter::getTextureCoordinates()
131 {
132     return textureCoords;
133 }
134 
135 vector<float> ModelImporter::getNormals()
136 {
137     return normals;
138 }
139 
140 ImportedModel::ImportedModel(const char *filePath)
141 {
142     ModelImporter modelImporter = ModelImporter();
143     modelImporter.parseOBJ(filePath); // 使用modelImporter获取顶点信息
144     numVertices = modelImporter.getNumVertices();
145     vector<float> verts = modelImporter.getVertices();
146     vector<float> tcs = modelImporter.getTextureCoordinates();
147     vector<float> normals = modelImporter.getNormals();
148 
149     for (int i = 0; i < numVertices; i++)
150     {
151         vertices.push_back(glm::vec3(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]));
152         texCoords.push_back(glm::vec2(tcs[i * 2], tcs[i * 2 + 1]));
153         normalVecs.push_back(glm::vec3(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]));
154     }
155 }
156 
157 ImportedModel::~ImportedModel()
158 {
159 }
160 
161 int ImportedModel::getNumVertices()
162 {
163     return numVertices;
164 }
165 
166 vector<glm::vec3> ImportedModel::getVertices()
167 {
168     return vertices;
169 }
170 
171 vector<glm::vec2> ImportedModel::getTextureCoords()
172 {
173     return texCoords;
174 }
175 
176 vector<glm::vec3> ImportedModel::getNormals()
177 {
178     return normalVecs;
179 }

我用Blender生成一个立方体模型的OBJ文件,生成的OBJ文件中 "f" 面是四个点构成正方形,不是三角形,我们简单的导入器只读取了四个点中前三个点,形成的每个面都是三角形不是正方形。

为此我加了一个面,是第一个“f” 的另一个三角形,可以看到有一个面是完整的正方形。其他面不想加了,都同理。

 1 # Blender v3.2.1 OBJ File: ''
 2 # www.blender.org
 3 mtllib untitled.mtl
 4 o Cube
 5 v 2.982061 2.981781 -3.035211
 6 v 2.910542 0.983304 -3.066416
 7 v 3.085501 2.946897 -1.038193
 8 v 3.013981 0.948420 -1.069397
 9 v 0.986019 3.051580 -2.930603
10 v 0.914499 1.053103 -2.961807
11 v 1.089458 3.016696 -0.933584
12 v 1.017939 1.018219 -0.964789
13 vt 0.625000 0.500000
14 vt 0.875000 0.500000
15 vt 0.875000 0.750000
16 vt 0.625000 0.750000
17 vt 0.375000 0.750000
18 vt 0.625000 1.000000
19 vt 0.375000 1.000000
20 vt 0.375000 0.000000
21 vt 0.625000 0.000000
22 vt 0.625000 0.250000
23 vt 0.375000 0.250000
24 vt 0.125000 0.500000
25 vt 0.375000 0.500000
26 vt 0.125000 0.750000
27 vn 0.0358 0.9992 0.0156
28 vn 0.0517 -0.0174 0.9985
29 vn -0.9980 0.0349 0.0523
30 vn -0.0358 -0.9992 -0.0156
31 vn 0.9980 -0.0349 -0.0523
32 vn -0.0517 0.0174 -0.9985
33 usemtl Material
34 s off
35 f 1/1/1 5/2/1 7/3/1 3/4/1
36 f 4/5/2 3/4/2 7/6/2 8/7/2
37 f 8/8/3 7/9/3 5/10/3 6/11/3
38 f 6/12/4 2/13/4 4/5/4 8/14/4
39 f 2/13/5 1/1/5 3/4/5 4/5/5
40 f 6/11/6 5/10/6 1/1/6 2/13/6
41 f 1/1/1 7/3/1 3/4/1

main.cpp

 1 ...
 2 #include "ImportedModel.h"
 3 ...
 4 ImportedModel myModel("untitled.obj");
 5 ...
 6 void setupVertices(void)
 7 {    
 8     //std::vector<int> ind = myTorus.getIndices(); //索引
 9     std::vector<glm::vec3> vert = myModel.getVertices(); //顶点
10     std::vector<glm::vec2> tex = myModel.getTextureCoords(); //纹理
11     std::vector<glm::vec3> norm = myModel.getNormals(); //法向量
12     int numObjVertices = myModel.getNumVertices();
13 
14     std::vector<float> pvalues; //顶点位置
15     vector<float> tvalues;        //纹理坐标
16     vector<float> nvalues;        //法向量
17 
18     for (int i = 0; i < numObjVertices; i++)
19     {
20         pvalues.push_back((vert[i]).x);
21         pvalues.push_back((vert[i]).y);
22         pvalues.push_back((vert[i]).z);
23         tvalues.push_back((tex[i]).s);
24         tvalues.push_back((tex[i]).t);
25         nvalues.push_back((norm[i]).x);
26         nvalues.push_back((norm[i]).y);
27         nvalues.push_back((norm[i]).z);
28     }
29 
30     glGenVertexArrays(1, vao); // 创建一个vao,并返回它的整数型ID存进数组vao中
31     glBindVertexArray(vao[0]); // 激活vao
32     glGenBuffers(numVBOs, vbo);// 创建3个vbo,并返回它们的整数型ID存进数组vbo中
33 
34     // 把顶点放入缓冲区 #0
35     glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); 
36     glBufferData(GL_ARRAY_BUFFER, pvalues.size()*4, &pvalues[0], GL_STATIC_DRAW); 
37     // 把纹理坐标放入缓冲区 #1
38     glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); 
39     glBufferData(GL_ARRAY_BUFFER, tvalues.size() * 4, &tvalues[0], GL_STATIC_DRAW); 
40     // 把法向量放入缓冲区 #2
41     glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
42     glBufferData(GL_ARRAY_BUFFER, nvalues.size() * 4, &nvalues[0], GL_STATIC_DRAW);
43     // 把索引放入缓冲区 #3
44     //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
45     //glBufferData(GL_ELEMENT_ARRAY_BUFFER, ind.size() * 4, &ind[0], GL_STATIC_DRAW);
46 }
47 ...
48 void display(GLFWwindow* window, double currentTime)
49 {
50     ...
51     glDrawArrays(GL_TRIANGLES, 0, myModel.getNumVertices());
52 }

效果如下:

标签:11,std,obj,ImportedModel,图形学,back,vector,vt,push
From: https://www.cnblogs.com/lely/p/16638633.html

相关文章

  • 解决:AttributeError: 'GovernmentApiClient' object has no attribute 're_fund'
    代码如下:1classGovernmentApiClient:23defrefund(self):4print('123456')5'''退款返销'''6body={7"t......
  • 11-12-13-14-15-16-17-18-19-20-21-22-23-24-25不知道在干啥,忘了
    时间过的好快啊,已经过去了2个星期了!!!! 而我不知道都干了什么,距离玩游戏已经过去了俩星期了,不可思议,我觉得才完了三五天而已人脑子会欺骗自己的啊我想换个键盘,换个按键轻......
  • 文件上传靶场11-16(修改)
    11-16文件上传靶场第11关   提示只允许上传jpg、png、gif类型   第十二关解题思路: Pass-11的防护方法是将出现在黑名单中的后缀名替换成空白字符串,但无......
  • Debain 11 安装并配置 wireguard
    1、安装aptinstallwireguard2、开启ipv4流量转发并使其生效echo"net.ipv4.ip_forward=1">>/etc/sysctl.confsysctl-p3、配置wireguard服务端3.1、生成服......
  • 前端Day11
    Flex布局:当为父元素设置flex布局后,子元素的float、clear、vertical-align属性将失效! flex常见父项属性:flex-direction设置主轴方向:justify-content设置子元素排......
  • Discuz论坛网站favicon图标更改方法 (2014-03-08 11:05:59)
    先制作一个网站的favicon.ico,百度搜索favicon在线制作可以找到很多的网站提供在线制作[推荐:http://www.ico.la/],favicon是ico格式的,你可以把你的图标在线制作什么ico,官方的......
  • Discuz!X3.2/3.3/3.4程序搬家/数据库修改教程 (2019-06-11 17:07:29)
    路径:/wwwroot/config/config_global.php这个根据你网站安装的路径而定。 打开config_global.php文件修改:$_config['db']['1']['dbpw']='原来密码'; 原来密码......
  • Java11-Object类,常用API
    day11【Object类、常用API】主要内容Object类Date类DateFormat类Calendar类System类StringBuilder类包装类第一章Object类1.1概述java.lang.Object类是Java......
  • 【Virt.Contest】CF1155(div.2)
    CF传送门T1:ReverseaSubstring只有本身单调不减的字符串不能转换为字典序更小的字符串。否则肯定会出现\(s_i>s_{i+1}\)的情况。所以只要从头到尾扫一遍,找到\(s_i>......
  • HC32L110(三) HC32L110的GCC工具链和VSCode开发环境
    目录HC32L110(一)HC32L110芯片介绍和Win10下的烧录HC32L110(二)HC32L110在Ubuntu下的烧录HC32L110(三)HC32L110的GCC工具链和VSCode开发环境以下介绍Ubuntu下搭建......