在加载OBJ模型文件之前首先要对OBJ文件的内容有所了解,在3d模型网站https://free3d.com/3d-models/3d-printable-obj

随便找了一个模型

它的OBJ文件内容为:

# File exported by ZBrush version 4.4
# www.zbrush.com
#Vertex Count 20545
#UV Vertex Count 15953
#Face Count 20559
#Auto scale x=0.022208 y=0.022208 z=0.022208
#Auto offset x=-0.531189 y=-0.179415 z=0.083041
mtllib stickman2.mtl
usemtl defaultMat
v 14.23160078 -34.12469952 6.2026003
v 14.47159986 -34.17430379 6.32490063
v 14.4308002 -34.00520591 6.28000128
v 14.26249945 -33.91609966 6.17129972

...

vt 0.699 0.3513
vt 0.7029 0.352
vt 0.7295 0.3476

...

f 390/393 398/401 371/374 378/381
f 399/402 401/404 402/405 400/403
f 365/368 372/375 400/403 402/405

...

\n

注意:文件末尾会有一个\n字符。而3dsmax建模出的文件是\r\n..

其中最为关键的为开头为"v","vt","f"的几行数据,“v”代表了顶点数据,“vt”代表贴图坐标也及uv坐标数据,“f”代表了面数据,

其中f 1 2 3 4代表四边形顶点,f 1 2 3代表三角顶点,f 1/1 2/2 3/3 代表顶点索引/纹理索引,f 1//1 2//2 3//3 代表顶点索引//法线索引,f 1/1/1 2/2/2 3/3/3 代表顶点索引/纹理索引/法线索引.索引及代表这是第几个元素,如f 390/393 398/401 371/374 378/381

表示这个面有四个顶点分别是第390个顶点/393个uv ,第398个顶点/401个uv...。

先从最简单的读取单纯的顶点数据开始:

本文在Qt下使用OpenGL,选择使用QOpenGLExtraFunctions类采用OpenGL原生API进行编写。

读取数据部分:

bool ObjLoader::Load(QString fileName, QVector<float> &vPoints)
{if (fileName.mid(fileName.lastIndexOf('.')) != ".obj"&&fileName.mid(fileName.lastIndexOf('.')) != ".OBJ"){qDebug() << "file is not a obj file!";return false;}QFile objfile(fileName);if (!objfile.open(QIODevice::ReadOnly)){qDebug() << "open" << fileName << "failed";return false;}else{qDebug() << "open" << fileName << "success!";}QVector<float> vertextPoints, texturePoints;QVector<std::tuple< int, int>> facesIndexs;while (!objfile.atEnd()){QByteArray lineData = objfile.readLine();lineData = lineData.remove(lineData.count() - 2, 2);qDebug() << lineData;if (lineData == "")continue;QList<QByteArray> strValues = lineData.split(' ');strValues.removeAll("");QString dataType = strValues.takeFirst();if (dataType == "v"){for(int i=0;i<strValues.count();i++){if (strValues[i] != "")vertextPoints.push_back( strValues[i].toFloat() );}}else if (dataType == "f"){if (strValues.size() == 4){strValues.push_back(strValues.at(0));strValues.push_back(strValues.at(2));}std::transform(strValues.begin(), strValues.end(), std::back_inserter(facesIndexs), [](QByteArray &str) {QList<QByteArray> intStr = str.split('/');return std::make_tuple(intStr.first().toInt(), intStr.last().toInt());});}}if (vertextPoints.count() != 0){qDebug() <<"vertpoints: "<< vertextPoints.count();}else{qDebug() << "none vert points";return false;}if (facesIndexs.count() != 0){qDebug() << "facepoints: "<<facesIndexs.count();}else{qDebug() << "none faces";return false;}for (auto &verFaceInfo:facesIndexs){int vIndex = std::get<0>(verFaceInfo);int vPointSizes = vertextPoints.count() / 3;//将顶点坐标放入vPoints << vertextPoints.at(vIndex * 3 - 3);vPoints << vertextPoints.at(vIndex * 3 - 2);vPoints << vertextPoints.at(vIndex * 3 - 1);}vertextPoints.clear();facesIndexs.clear();objfile.close();return true;
}

此代码改自https://blog.csdn.net/wanghualin033/article/details/84642286

整体思路便是 读取文件的每一行,删除掉最后的一个字符'\r\n' 并判断头个字符进行操作。先不管uv坐标.

有一个细节是此OBJ文件里的面有三个点成面的也有四个点成面的,我统一存储为三个点及把四个数据变为六个数据(顶点0 1 2 3 变为顶点 0 1 2 3 0 2)便于绘制.

将数据存储于容器中。在绘制函数中进行调用。

先初始化OpenGL绘制的环境:

void MyWidget::initializeGL()
{showNormal();setGeometry(0, 0, 800, 600);_program.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, "vsrc.vert");_program.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, "fsrc.frag");if (_program.link()){qDebug() << "link success!";}else{qDebug() << "link failed";}_objLoader.Load("C:/Users/Administrator/Desktop/obj/43n0m0fl66o0-stickman/stickman.OBJ", _vertPoints);qDebug() << _vertPoints.count();f = QOpenGLContext::currentContext()->extraFunctions();f->glGenVertexArrays(1, &VAO);f->glGenBuffers(1, &VBO);f->glBindBuffer(GL_ARRAY_BUFFER, VBO);f->glBufferData(GL_ARRAY_BUFFER, _vertPoints.size()*sizeof(float), &_vertPoints[0], GL_STATIC_DRAW);f->glBindVertexArray(VAO);f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (GLvoid*)0);f->glEnableVertexAttribArray(0);f->glBindVertexArray(0);vMatrix.lookAt(_cameraLocation, QVector3D(0.0, 0.0, 0.0), QVector3D(0.0, 1.0, 0));
}

此处又遇到了一个问题,    f->glBufferData(GL_ARRAY_BUFFER, _vertPoints.size()*sizeof(float), &_vertPoints[0], GL_STATIC_DRAW);其中的第二个参数 sizeof(vector)是不能返回一个vector的总数据大小的,是一个相当小的定值,以至于在想怎么把数据传进去时出了许多问题:int* arr = new int[10];

sizeof(arr)返回的是arr[0]的大小而不是指针代表的数组的大小。

而int arr[10] 这种方式sizeof(arr)返回的就是数组的大小。

而第二种方式的数组的大小需要在编译时就确认也就是无法跟着读取数据大小的变化而改变,想了许久之后才发现,原来是sizeof(vector)这个地方出了问题,只传了一点数据进去,也就谈不上能绘制出来了。。改成_vertPoints.size()*sizeof(float)就解决了问题。

最后进行绘制:

void MyWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);_program.bind();f->glBindVertexArray(VAO);_program.setUniformValue("uPMatrix", pMatrix);_program.setUniformValue("uVMatrix", vMatrix);_program.setUniformValue("uMMatrix", mMatrix);glDrawArrays(GL_TRIANGLES, 0, _vertPoints.size()/3);第三个参数是要绘制的顶点数f->glBindVertexArray(0);update();
}

加以最简单的shader:

fragshader

#version 330out vec4 fragColor;void main(void)
{fragColor = vec4(1.0f,1.0f,1.0f,1.0f);
}

vertexshader

#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
layout (location = 0) in vec3 aPosition;void main(void)
{gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);
}

出来吧:皮卡丘

感觉有点奇怪。

换种方式绘制试试:

glDrawArrays(GL_POINTS, 0, _vertPoints.size() );

没想到就是加载个模型也是如此困难重重。。之后加上光影和uv再看看效果吧。

Qt OpenGL加载OBJ模型相关推荐

  1. qt opengl 加载3d模型(obj格式)

    和一般c++程序加载3d模型一样,解读出数据内容,再用一个常规的着色程序就可以了. 我实现的效果如下,采用的免费模型 实现思路和前面的略有不同,就是把自己生成顶点.纹理.法线的过程变成从文件读取了. ...

  2. threejs加载obj模型_Vulkan编程指南(章节31-载入模型)

    章节31 载入模型 介绍 本章节我们将会渲染一个带有纹理的三维模型. 库 我们使用tinyobjloader库来从OBJ文件加载顶点数据.tinyobjloader库是一个简单易用的单文件OBJ加载器 ...

  3. three.js加载obj模型和材质

    1.Vue中安装three.js和加载用的包 安装three.js使用npm install three --save 安装加载obj和mtl文件的包npm install three-obj-mtl ...

  4. three.js加载OBJ模型

    three.js加载OBJ模型 推荐一个免费下载3D模型的网址https://www.cgtrader.com,包含多种格式(obj, mtl等). three.js现在是es6语法,旧版本是es5的 ...

  5. OpenGL学习脚印:模型加载初步-加载obj模型(load obj model)

    写在前面 前面介绍了光照基础内容,以及材质和lighting maps,和光源类型,我们对使用光照增强场景真实感有了一定了解.但是到目前为止,我们通过在程序中指定的立方体数据,绘制立方体,看起来还是很 ...

  6. WPF加载obj模型-2

    安装微软Expression Blend: 新建一个WPF项目: 把obj文件添加到项目: 然后把obj文件拖到MainWindow:模型出来了: 运行一下如下: 右击添加模型以后的xaml文件,外部 ...

  7. Assimp库调用mtl加载obj模型

    网上查阅了很多资料,通过测试都未通过,后来在两位大神博客的帮助下最终完成了obj及mtl的加载. 参考博客链接: OpenGL学习: uniform blocks(UBO)在着色器中的使用_arag2 ...

  8. Qt OpenGL 加载3D世界,并在其中漫游

    这次教程中,我将教大家如何加载一个3D世界,并在3D世界中漫游.这相较于我们只能创造一个旋转的立方体或一群星星时有很大的进步了,当然这节课代码难度不低,但也不会很难,只要你跟着我慢慢一步一步来. 一个 ...

  9. 首次使用three.js加载obj模型未成功

    接此,https://blog.csdn.net/bcbobo21cn/article/details/110676331 基本代码如下: <!DOCTYPE html> <html ...

  10. threejs加载obj模型_倾斜摄影三维模型几种常见的格式,你能说出哪些?

    本文首发于公众号Wish3D,原文链接:倾斜摄影三维模型几种常见的格式,你能说出哪些? 无人机航拍的影像经过建模软件处理产出之时,有很多成果的数据需要我们去选择输出,对于新手而言,如何选择数据格式呢? ...

最新文章

  1. javascript var变量删除
  2. 安装和配置SQL Server 2016 With SP1
  3. jQuery Dom 操作,动态生成dom,绑定事件
  4. 万字详解Lambda、Stream和日期
  5. linux命令(一)查看进程的线程数top,ps
  6. java 可变参数列表 数组_java可变参数列表如何填充数组?
  7. mysql默认dba_DBA 基本常识 - 安装完 MySQL 后必须调整的 10 项配置 - iTeknical
  8. 2009年北京第一场雪
  9. b站视频解析php,B站视频解析套路
  10. Android创建txt文件并写入
  11. 通过cmd进行文件格式的转换
  12. python用matplotlib画雷达图_matplotlib雷达图
  13. 解决问题win10无线网卡:无法连接到此网络
  14. 成考计算机专业难不难,成人高考计算机类难度大吗(成人大学难度)
  15. 二级分销系统对企业来说意味着什么?
  16. 华为nova6开启开发者模式,连接USB
  17. 网页设计如何排成一列_HTML页面布局怎么设计(图文)
  18. 好久没来,深夜来一发
  19. 通信之道-傅立叶分析
  20. Oracle转MySQL存储函数percentile_cont(比例) WITHIN GROUP( ORDER BY to_number(分数) )用法

热门文章

  1. RHEL7安装配置FTP服务
  2. 换IP工具派克斯和PPTP的区别
  3. 用计算机软件绘制思维导图,电脑软件绘制思维导图操作教程分享
  4. 一台电脑实现Kvaser CAN总线理论实践、开发与测试!
  5. SVN、GIT图标不显示解决方案
  6. python xlsxwriter下载_python_xlsxwriter模块
  7. springboot入门-idea
  8. 超级高铁(Hyperloop)
  9. Unirech-腾讯云服务器简介及腾讯云国际版云服务器购买流程
  10. 数据库导出数据字典(MySQL)