qt+opengl 加载三维obj文件

1前面我们已经熟悉了opengl自定义顶点生成一个立方体,并且我们实现了立方体的旋转,光照等功能。下面我们来用opengl来加载一个obj文件。准备我们首先准备一个简单的obj文件(head.obj)。资源在本页下载

2 在obj文件里面,我们关注下 v 字段和f字段

 v 字段就是顶点  f字段代表了面,意思是每个面的顶点编号。 结构如下

v -0.99179999 -2.98999995 4.05410025  表示顶点值

f 12791 127 126   表示这个面的三个点在 v 里面的index值是12791 也是就是v[12791]的值的顶点是这个面的顶点值。

3 下面我们来解析obj文件

bool 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, normalPoints;QVector<Face> facesIndexs;while (!objFile.atEnd()){QByteArray lineData = objFile.readLine();QList<QByteArray> strValues = lineData.trimmed().split(' ');QString dataType = strValues.takeFirst();for(int i=0;i<strValues.size();i++){double nData = strValues.at(i).toDouble();QString strTemp = QString::number(nData,'f',4);if (dataType == "v"){vertextPoints.append(strTemp.toFloat());}else if (dataType == "vt"){texturePoints.append(strValues.at(i).toFloat());}else if (dataType == "vn"){normalPoints.append(strValues.at(i).toFloat());}else if (dataType == "f"){Face ondInfo;if(strValues.at(i).contains("/")){QList<QByteArray> strTemp = strValues.at(i).split('/');if(strTemp.size()==2){ondInfo.vertices  =  strTemp.at(0).toInt();ondInfo.texCoords =  strTemp.at(1).toInt();}else if(strTemp.size()==3){ondInfo.vertices  =  strTemp.at(0).toInt();ondInfo.texCoords =  strTemp.at(1).toInt();ondInfo.normals   =  strTemp.at(2).toInt();}}else{ondInfo.vertices = strValues.at(i).toInt();//qDebug()<<"Face ondInfo"<<ondInfo.vertices;}facesIndexs.append(ondInfo);}}}objFile.close();int count =0;for (int i=0;i<facesIndexs.size();i++){int vIndex = facesIndexs[i].vertices - 1;if(vIndex * 3 <=vertextPoints.size() ||vIndex * 3 + 1 <=vertextPoints.size()||vIndex * 3 + 2<=vertextPoints.size() ){vPoints << vertextPoints.at(vIndex * 3);vPoints << vertextPoints.at(vIndex * 3 + 1);vPoints << vertextPoints.at(vIndex * 3 + 2);// qDebug()<<"vIndex"<<i<<vertextPoints.size()<<vIndex * 3;}else{//  qDebug()<<"vIndex error"<<i<<vertextPoints.size()<<vIndex * 3;}}vertextPoints.clear();texturePoints.clear();normalPoints.clear();facesIndexs.clear();return true;
}

 接着我们来写加载代码

和以前的一样,就是写glsl语句,

#ifndef TESTOBJOPENGL_H
#define TESTOBJOPENGL_H#include <QObject>
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QTimer>
#include <QOpenGLTexture>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QTimer>
#include <QMouseEvent>QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram);
QT_FORWARD_DECLARE_CLASS(QOpenGLTexture)
class testobjOpengl : public QOpenGLWidget, protected QOpenGLFunctions
{
public:testobjOpengl( QWidget *parent=nullptr);~testobjOpengl();
protected:void initializeGL() override;void paintGL() override;void resizeGL(int width, int height) override;void rotateBy(int xAngle, int yAngle, int zAngle);bool load(QString fileName, QVector<float>& vPoints);struct Face{int vertices;int texCoords;int normals;Face(){vertices = -1;texCoords = -1;normals = -1;}};
private:QVector<float> m_vPoints;int m_xRot;int m_yRot;int m_zRot;QOpenGLShaderProgram *m_program= nullptr;QOpenGLVertexArrayObject vao;QOpenGLBuffer vbo;QVector3D cameraPos;QVector3D cameraTarget;QVector3D cameraDirection;QOpenGLTexture *texture;int m_projMatrixLoc;int m_mvMatrixLoc;int m_normalMatrixLoc;int m_lightPosLoc;QMatrix4x4 m_proj;QMatrix4x4 m_camera;QMatrix4x4 m_world;QVector3D m_camera_pos;QTimer* timer;int  m_yPos=0;int  m_zPos=0;};#endif // TESTOBJOPENGL_H
#include "testobjopengl.h"static const char *vertexShaderSourceCore ="#version 330\n""layout (location = 0) in vec4 vertex;\n""layout (location = 1) in vec3 normal;\n""out vec3 vert;\n""out vec3 vertNormal;\n""uniform  mat4 matrix;\n""uniform  mat4 view;\n""uniform  mat4 projection;\n""uniform  mat3 normalMatrix;\n""void main() {\n""   vert = vertex.xyz;\n""   vertNormal = normalMatrix * normal;\n""   gl_Position = projection*view* matrix * vertex;\n""}\n";
static const char *fragmentShaderSourceCore ="#version 150\n""in highp vec3 vert;\n""in highp vec3 vertNormal;\n""out highp vec4 fragColor;\n""uniform highp vec3 lightPos;\n""void main() {\n""   highp vec3 L = normalize(lightPos - vert);\n""   highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n""   highp vec3 color = vec3(1.0, 1.0, 0.0);\n""   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n""   fragColor = vec4(col, 1.0);\n""}\n";testobjOpengl::testobjOpengl(QWidget *parent): QOpenGLWidget(parent),m_xRot(0),m_yRot(0),m_zRot(0)
{m_vPoints.clear();cameraPos = QVector3D(0, 0, 3);QString strTemp = "F:/Tree2/head.obj";bool ret = load(strTemp,m_vPoints);if(ret){timer = new QTimer;timer->setInterval(100);connect(timer,&QTimer::timeout,this,[=]{qDebug()<<"timeout";rotateBy(10 * 16, +10 * 16, -1 * 16);});timer->start();}else{qDebug()<<"1111111111111111";}}
void testobjOpengl::rotateBy(int xAngle, int yAngle, int zAngle)
{float cameraSpeed = 0.2;m_camera_pos -= cameraSpeed * QVector3D(0, 0, -1);//由远到近if(m_yPos>=100){m_yPos = 0;}m_yPos+=10;if(m_zPos>=100){m_zPos = 0;}m_zPos+=10;// m_camera_pos = QVector3D(0, m_yPos, m_zPos);//由远到近// m_camera_pos.setY(m_yPos);m_xRot += xAngle;m_yRot += yAngle;m_zRot += zAngle;update();//timer->stop();
}
testobjOpengl::~testobjOpengl()
{}void testobjOpengl::initializeGL()
{initializeOpenGLFunctions();m_program = new QOpenGLShaderProgram;m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSourceCore);m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSourceCore);if (m_program->link()){qDebug() << "link success!";}else{qDebug() << "link failed";}m_program->bindAttributeLocation("vertex", 0);m_program->bindAttributeLocation("normal", 1);m_program->link();m_program->bind();//    m_projMatrixLoc = m_program->uniformLocation("projection");
//    m_mvMatrixLoc = m_program->uniformLocation("matrix");
//    m_normalMatrixLoc = m_program->uniformLocation("normalMatrix");
//    m_lightPosLoc = m_program->uniformLocation("lightPos");vbo.create();vbo.bind();vbo.allocate(m_vPoints.data(), m_vPoints.size() * sizeof(float));QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();f->glEnableVertexAttribArray(0);f->glEnableVertexAttribArray(1);f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));vbo.release();m_program->setUniformValue(m_lightPosLoc, QVector3D(10, 10, 10)); 
}void testobjOpengl::paintGL()
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnable(GL_DEPTH_TEST);glEnable(GL_CULL_FACE);QMatrix4x4 m;//m.ortho(-0.5f, +0.5f, +0.5f, -0.5f, 4.0f, 15.0f);m.setToIdentity();m.translate(0.0f, 0.0f, 0.0f);m.rotate(m_xRot / 16.0f, 1.0f, 0.0f, 0.0f);m.rotate(90, 0.0f, 1.0f, 0.0f);m.rotate(0, 0.0f, 0.0f, 1.0f);m.scale(0.5);QMatrix4x4 view;view.setToIdentity();view.lookAt(QVector3D(0, 20, 20), QVector3D(0,0,0), QVector3D(1,0,0));m_program->bind();m_program->setUniformValue("projection", m_proj);m_program->setUniformValue("matrix", m);m_program->setUniformValue("view", view);m_program->setUniformValue("lightPos", QVector3D(10, 10, 0));QMatrix3x3 normalMatrix = m.normalMatrix();m_program->setUniformValue("normalMatrix", normalMatrix);glDrawArrays(GL_TRIANGLES, 0, m_vPoints.size()/3);m_program->release();
}void testobjOpengl::resizeGL(int width, int height)
{m_proj.setToIdentity();m_proj.perspective(45.0f, GLfloat(width) / height, 0.01f, 100.0f);
}
bool testobjOpengl::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, normalPoints;QVector<Face> facesIndexs;while (!objFile.atEnd()){QByteArray lineData = objFile.readLine();QList<QByteArray> strValues = lineData.trimmed().split(' ');QString dataType = strValues.takeFirst();for(int i=0;i<strValues.size();i++){double nData = strValues.at(i).toDouble();QString strTemp = QString::number(nData,'f',4);if (dataType == "v"){vertextPoints.append(strTemp.toFloat());}else if (dataType == "vt"){texturePoints.append(strValues.at(i).toFloat());}else if (dataType == "vn"){normalPoints.append(strValues.at(i).toFloat());}else if (dataType == "f"){Face ondInfo;if(strValues.at(i).contains("/")){QList<QByteArray> strTemp = strValues.at(i).split('/');if(strTemp.size()==2){ondInfo.vertices  =  strTemp.at(0).toInt();ondInfo.texCoords =  strTemp.at(1).toInt();}else if(strTemp.size()==3){ondInfo.vertices  =  strTemp.at(0).toInt();ondInfo.texCoords =  strTemp.at(1).toInt();ondInfo.normals   =  strTemp.at(2).toInt();}}else{ondInfo.vertices = strValues.at(i).toInt();//qDebug()<<"Face ondInfo"<<ondInfo.vertices;}facesIndexs.append(ondInfo);}}}objFile.close();int count =0;for (int i=0;i<facesIndexs.size();i++){int vIndex = facesIndexs[i].vertices - 1;if(vIndex * 3 <=vertextPoints.size() ||vIndex * 3 + 1 <=vertextPoints.size()||vIndex * 3 + 2<=vertextPoints.size() ){vPoints << vertextPoints.at(vIndex * 3);vPoints << vertextPoints.at(vIndex * 3 + 1);vPoints << vertextPoints.at(vIndex * 3 + 2);// qDebug()<<"vIndex"<<i<<vertextPoints.size()<<vIndex * 3;}else{//  qDebug()<<"vIndex error"<<i<<vertextPoints.size()<<vIndex * 3;}}vertextPoints.clear();texturePoints.clear();normalPoints.clear();facesIndexs.clear();return true;
}

 我们开始调用

testobjOpengl w;

w.show();

运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/41658.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机组成原理的学习day01

一 计算机系统层次结构 1 计算机硬件的基本组成 好的&#xff0c;上个小节中我们了解了计算机系统的概念&#xff0c;还有计算机的一个发展历程&#xff0c;那这个小节中我们会着重的探讨计算机硬件的一个基本组成。我们需要掌握这样的两种结构&#xff0c;第一种是早期的冯诺…

ASP 应用HTTP.SYS短文件文件解析Access 注入数据库泄漏

#ASP- 默认安装 -MDB 数据库泄漏下载&#xff08;路径是知道的话可以直接下载&#xff09; 由于大部分 ASP 程序与 ACCESS 数据库搭建&#xff0c;但 ACCESS 无需连接&#xff0c;都在脚本文件中定 义配置好数据库路径即用&#xff0c;不需要额外配置安装数据库&#x…

Redis 版本演进及主要新特性

Redis 版本发布历史 稳定版本时间线 Redis 2.6 (2012年)Redis 2.8 (2013年11月)Redis 3.0 (2015年4月) - 首次支持集群Redis 3.2 (2016年5月)Redis 4.0 (2017年7月)Redis 5.0 (2018年10月)Redis 6.0 (2020年4月)Redis 6.2 (2021年2月)Redis 7.0 (2022年4月) - 最新稳定版(截至…

从 MySQL 到时序数据库 TDengine:Zendure 如何实现高效储能数据管理?

小T导读&#xff1a;TDengine 助力广州疆海科技有限公司高效完成储能业务的数据分析任务&#xff0c;轻松应对海量功率、电能及输入输出数据的实时统计与分析&#xff0c;并以接近 1 : 20 的数据文件压缩率大幅降低存储成本。此外&#xff0c;taosX 强大的 transform 功能帮助用…

NVM安装速通使用手册(Windows版)NVM管理node版本命令手册 NVM使用手册

nvm&#xff08;Node Version Manager&#xff09;是一个用于管理Node.js版本的命令行工具。通过nvm&#xff0c;你可以在同一台机器上安装和切换多个Node.js版本&#xff0c;非常适合开发和测试在不同Node.js版本上运行的应用程序 一、安装地址 1. 官方下载&#xff1a; &…

qt QQuaternion详解

1. 概述 QQuaternion 是 Qt 中用于表示三维空间中旋转的四元数类。它包含一个标量部分和一个三维向量部分&#xff0c;可以用来表示旋转操作。四元数在计算机图形学中广泛用于平滑的旋转和插值。 2. 重要方法 默认构造函数 QQuaternion::QQuaternion(); // 构造单位四元数 (1…

Axure项目实战:智慧城市APP(四)医疗信息(动态面板、选中交互应用)

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 课程主题&#xff1a;智慧城市APP医疗信息模块 主要内容&#xff1a;医疗信息模块原型设计与交互 应用场景&#xff1a;医疗信息行业 案例展示&#xff1a; 案例视频&…

DeepSeek助力文案,智能音箱如何改变你的生活?

你好&#xff0c;我是三桥君 你有没有为写智能音箱的宣传文案而抓耳挠腮过&#xff1f;三桥君在这方面可是有些感想&#xff0c;今天就来给你唠唠怎么用DeepSeek写出超赞的智能音箱宣传文案。 首先&#xff0c;你得给DeepSeek喂足“料”。这就好比做饭&#xff0c;你得准备好各…

二叉树的前,中,后序遍历

我们来了解一下二叉树的遍历&#xff0c;话不多说 二叉树的遍历的概念&#xff1a; 二叉树有四种遍历方式&#xff0c;分别为前序遍历&#xff0c;中序遍历&#xff0c;后序遍历和层序遍历&#xff0c;但我们今天谈谈前三种&#xff0c;并实现它 前序遍历&#xff1a; 按照根…

Linux网站搭建(新手必看)

1.宝塔Linux面板的功能 宝塔面板是一款服务器管理软件&#xff0c;可以帮助用户建立网站&#xff0c;一键配置服务器环境&#xff0c;使得用户通过web界面就可以轻松的管理安装所用的服务器软件。 2. 宝塔Linux面板的安装 宝塔官网地址&#xff1a;宝塔面板 - 简单好用的Linu…

secp256k1的模数P是如何选择的?

在区块链和现代密码学中&#xff0c;secp256k1 椭圆曲线以其高安全性和高效运算性能而著称。你可能注意到&#xff0c;secp256k1 的曲线方程为 而其中的模数 p 被定义为 那么&#xff0c;为何会选择这样一个看似复杂的数呢&#xff1f;本文将从多个角度为你详细解析这一选择背后…

本地文生图使用插件(Stable Diffusion)

1. 插件下载&#xff08;github&#xff09; 1.1 直接Avaliable中点击安装&#xff08;方案一&#xff09; 1.2 Install from URL中输入URL&#xff08;方案二&#xff09; 1.3 直接下载复制到extensions目录&#xff08;方案三&#xff09; 2. 模型下载&#xff08;Huggingf…

鸿蒙-全屏播放页面(使用相对布局)---持续更新中

最终实现效果图&#xff1a; 实现步骤 创建FullScreenPlay.ets全品播放页面 并将其修改为启动页面。 全屏播放&#xff0c;屏幕必然横过来&#xff0c;所以要将窗口横过来。 编辑 src/main/ets/entryability/EntryAbility.ets 若写在/EntryAbility.ets中&#xff0c;则所有…

C++ 多线程简要讲解

std::thread是 C11 标准库中用于多线程编程的核心类&#xff0c;提供线程的创建、管理和同步功能。下面我们一一讲解。 一.构造函数 官网的构造函数如下&#xff1a; 1.默认构造函数和线程创建 thread() noexcept; 作用&#xff1a;创建一个 std::thread 对象&#xff0c;但…

每天认识一个设计模式-建造者模式:复杂对象的“装配式革命“

一、前言 在软件开发的广袤领域中&#xff0c;随着项目规模日益庞大、业务逻辑愈发复杂&#xff0c;对象的创建过程也变得千头万绪。 早期简单的对象创建方式&#xff0c;在面对复杂对象时&#xff0c;逐渐显露出代码臃肿、耦合度高、可维护性差等弊端&#xff0c;设计模式的…

动态IP与静态IP该如何选?

一、当IP地址成为"网络身份" 2023年亚马逊封号潮中&#xff0c;某杭州卖家因登录IP频繁切换&#xff08;早8点在纽约&#xff0c;午间瞬移到东京&#xff09;&#xff0c;触发平台风控导致账号冻结。这类"时空错乱症"揭示了跨境电商的生存法则&#xff1a…

蓝桥与力扣刷题(蓝桥 蓝桥骑士)

题目&#xff1a;小明是蓝桥王国的骑士&#xff0c;他喜欢不断突破自我。 这天蓝桥国王给他安排了 N 个对手&#xff0c;他们的战力值分别为 a1,a2,...,an&#xff0c;且按顺序阻挡在小明的前方。对于这些对手小明可以选择挑战&#xff0c;也可以选择避战。 身为高傲的骑士&a…

Linux--文件

ok&#xff0c;我们今天了解一下Linux中的文件 理解“文件” 狭义理解 ⽂件在磁盘⾥磁盘是永久性存储介质&#xff0c;因此⽂件在磁盘上的存储是永久性的磁盘是外设&#xff08;即是输出设备也是输⼊设备&#xff09;磁盘上的⽂件本质是对⽂件的所有操作&#xff0c;都是对外…

Linux-数据结构-哈夫曼树-哈希表-内核链表

一.哈夫曼树 哈夫曼树&#xff08;Huffman Tree&#xff09;是一种特殊的二叉树&#xff0c;其定义和原理如下&#xff1a; 【1】定义 哈夫曼树是一种带权路径长度最短的二叉树。给定一组权值&#xff0c;将这些权值作为叶子节点的权值构造一棵二叉树&#xff0c;若该树的带…

前端抽象化,打破框架枷锁:统一路由的设计

个人博客原文地址 此文章并不适合初级前端来看&#xff0c;它是抽象的架构设计&#xff0c;需要一定的TS基础和抽象思维&#xff0c;若带着思考的读完本文章相信会让你感到充实 当然你也可以复制&#xff0c;然后在自己项目中去实现它&#xff0c;然后用起来 只要你是在写前端…