和一般c++程序加载3d模型一样,解读出数据内容,再用一个常规的着色程序就可以了。

我实现的效果如下,采用的免费模型

实现思路和前面的略有不同,就是把自己生成顶点、纹理、法线的过程变成从文件读取了。

我的obj文件如下

mtllib C:\Users\Animation\Desktop\XNALara\data\dummy\Vanquish - Augmented Reaction Suit\vanquish.mtl
g Model001_24_Vanquish_1.0_0.0_0.0
usemtl Model001_Material001
v 0.1132252 1.45228 0.0713402
vn 0.452102 0.483883 0.749307
vt 0.946289 0.365723

....

f -800/-800/-800 -810/-810/-810 -808/-808/-808
f -808/-808/-808 -799/-799/-799 -800/-800/-800
f -801/-801/-801 -800/-800/-800 -798/-798/-798
f -798/-798/-798 -802/-802/-802 -801/-801/-801
f -802/-802/-802 -798/-798/-798 -797/-797/-797
f -797/-797/-797 -803/-803/-803 -802/-802/-802
f -803/-803/-803 -797/-797/-797 -796/-796/-796

然后这里会有一个空行,下面的内容格式和上面保持一致,如此有几个循环

mtllib C:\Users\Animation\Desktop\XNALara\data\dummy\Vanquish - Augmented Reaction Suit\vanquish.mtl
g Model001_24_Vanquish_1.0_0.0_0.0
usemtl Model001_Material001
v 0.1132252 1.45228 0.0713402
vn 0.452102 0.483883 0.749307
vt 0.946289 0.365723

....

f -800/-800/-800 -810/-810/-810 -808/-808/-808
f -808/-808/-808 -799/-799/-799 -800/-800/-800
f -801/-801/-801 -800/-800/-800 -798/-798/-798
f -798/-798/-798 -802/-802/-802 -801/-801/-801
f -802/-802/-802 -798/-798/-798 -797/-797/-797
f -797/-797/-797 -803/-803/-803 -802/-802/-802
f -803/-803/-803 -797/-797/-797 -796/-796/-796

关于obj文件的介绍我就不说了,百度吧。

解析如下

bool ObjLoader::load(QString fileName, QVector<float> &vPoints,QVector<float> &tPoints,QVector<float> &nPoints)
{if(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;}QVector<float> vertextPoints,texturePoints,normalPoints;QVector<std::tuple<int,int,int>> facesIndexs;while (!objFile.atEnd()) {QByteArray lineData = objFile.readLine();lineData = lineData.remove(lineData.count() - 2,2);if(lineData.isEmpty()){for(auto &verFaceInfo : facesIndexs){int vIndex = std::get<0>(verFaceInfo);int tIndex = std::get<1>(verFaceInfo);int nIndex = std::get<2>(verFaceInfo);int vPointSizes = vertextPoints.count() / 3;int tPointSizes = texturePoints.count() / 2;int nPointSizes = normalPoints.count() / 3;vPoints << vertextPoints.at((vPointSizes + vIndex) * 3);vPoints << vertextPoints.at((vPointSizes + vIndex) * 3 + 1);vPoints << vertextPoints.at((vPointSizes + vIndex) * 3 + 2);tPoints << texturePoints.at((tPointSizes + tIndex) * 2);tPoints << texturePoints.at((tPointSizes + tIndex) * 2 + 1);nPoints << normalPoints.at((nPointSizes + nIndex) * 3);nPoints << normalPoints.at((nPointSizes + nIndex) * 3 + 1);nPoints << normalPoints.at((nPointSizes + nIndex) * 3 + 2);}vertextPoints.clear();texturePoints.clear();normalPoints.clear();facesIndexs.clear();continue;}QList<QByteArray> strValues = lineData.split(' ');QString dataType = strValues.takeFirst();if(dataType == "v"){std::transform(strValues.begin(),strValues.end(),std::back_inserter(vertextPoints),[](QByteArray &str){return str.toFloat();});}else if(dataType == "vt"){std::transform(strValues.begin(),strValues.end(),std::back_inserter(texturePoints),[](QByteArray &str){return str.toFloat();});}else if(dataType == "vn"){std::transform(strValues.begin(),strValues.end(),std::back_inserter(normalPoints),[](QByteArray &str){return str.toFloat();});}else if(dataType == "f"){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.at(1).toInt(),intStr.last().toInt());});}}objFile.close();
}

这样解析出来的数据就按顺序放入容器了,接下的步骤和前面一样的,写个常用渲染器,用就可以了

#ifndef GENERICRENDER_H
#define GENERICRENDER_H#include <QOpenGLShaderProgram>
#include <QOpenGLExtraFunctions>
#include <QOpenGLTexture>
#include <QOpenGLBuffer>
class GenericRender
{
public:GenericRender() = default;void initsize(QString filename,QImage &textureImg);void render(QOpenGLExtraFunctions *f,QMatrix4x4 &pMatrix,QMatrix4x4 &vMatrix,QMatrix4x4 &mMatrix,QVector3D &cameraLocation,QVector3D &lightCation);private:QOpenGLTexture *texture_{nullptr};QOpenGLBuffer vbo_;QOpenGLShaderProgram program_;QVector<float> vertPoints_,texturePoints_,normalPoints_;
};#endif // GENERICRENDER_H
#include "genericrender.h"
#include "utils/objloader.h"
void GenericRender::initsize(QString filename, QImage &textureImg)
{program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vert");program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.frag");program_.link();ObjLoader objModelLoader;objModelLoader.load(filename,vertPoints_,texturePoints_,normalPoints_);QVector<float> points;points << vertPoints_ << texturePoints_ << normalPoints_;vbo_.create();vbo_.bind();vbo_.allocate(points.data(),points.count() * sizeof(float));texture_ = new QOpenGLTexture(textureImg);texture_->setWrapMode(QOpenGLTexture::ClampToEdge);texture_->setMinMagFilters(QOpenGLTexture::Nearest,QOpenGLTexture::Linear);
}void GenericRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix, QVector3D &cameraLocation, QVector3D &lightCation)
{f->glEnable(GL_DEPTH_TEST);program_.bind();vbo_.bind();f->glActiveTexture(GL_TEXTURE0 + 0);program_.setUniformValue("uPMatrix",pMatrix);program_.setUniformValue("uVMatrix",vMatrix);program_.setUniformValue("uMMatrix",mMatrix);program_.setUniformValue("uLightLocation",lightCation);program_.setUniformValue("uCamera",cameraLocation);program_.setUniformValue("sTexture",0);program_.enableAttributeArray(0);program_.enableAttributeArray(1);program_.enableAttributeArray(2);program_.setAttributeBuffer(0,GL_FLOAT,0,3,3*sizeof(GLfloat));program_.setAttributeBuffer(1,GL_FLOAT,vertPoints_.count() * sizeof(GLfloat),2,2*sizeof(GLfloat));program_.setAttributeBuffer(2,GL_FLOAT,(vertPoints_.count() + texturePoints_.count()) * sizeof(GLfloat),3,3*sizeof(GLfloat));texture_->bind(0);f->glDrawArrays(GL_TRIANGLES,0,vertPoints_.count()/3);program_.disableAttributeArray(0);program_.disableAttributeArray(1);program_.disableAttributeArray(2);texture_->release();vbo_.release();program_.release();f->glDisable(GL_DEPTH_TEST);
}

其shader如下

#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
uniform vec3 uLightLocation,uCamera;
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTextureCoord;
layout (location = 2) in vec3 aNormal;
smooth out vec2 vTextureCood;
smooth out vec4 vAmbient;
smooth out vec4 vDiffuse;
smooth out vec4 vSpecular;void pointLight(in vec3 normal,inout vec4 ambient,inout vec4 diffuse,inout vec4 specular,in vec4 lightAmbient,in vec4 lightDiffuse,in vec4 lightSpecular,in float shininess){ambient = lightAmbient;vec3 normalTarget = aPosition + normal;vec3 newNormal = normalize((uMMatrix * vec4(normalTarget,1)).xyz - (uMMatrix * vec4(aPosition,1)).xyz);vec3 eye = normalize(uCamera - (uMMatrix * vec4(aPosition,1)).xyz);vec3 vp = normalize(uLightLocation - (uMMatrix * vec4(aPosition,1)).xyz);vec3 halfVector = normalize(eye + vp);float nDotViewPotision = max(0.0,dot(newNormal,vp));diffuse = lightDiffuse * nDotViewPotision;float nDotViewHalfVector = dot(newNormal,halfVector);float powerFactor = max(0.0,pow(nDotViewHalfVector,shininess));specular = lightSpecular * powerFactor;
}void main(void)
{gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);vec4 ambient = vec4(0.0,0.0,0.0,0.0),diffuse = vec4(0.0,0.0,0.0,0.0),specular = vec4(0.0,0.0,0.0,0.0);pointLight(aNormal,ambient,diffuse,specular,vec4(0.6,0.6,0.6,1.0),vec4(0.8,0.8,0.8,1.0),vec4(0.9,0.9,0.9,1),50);vAmbient = ambient;vDiffuse = diffuse;vSpecular = specular;vTextureCood = aTextureCoord;
}
#version 330
uniform sampler2D sTexture;
in vec2 vTextureCood;
in vec4 vAmbient;
in vec4 vDiffuse;
in vec4 vSpecular;
out vec4 fragColor;void main(void)
{vec4 finalColor = texture2D(sTexture,vTextureCood);finalColor = finalColor * (vAmbient + vDiffuse + vSpecular);fragColor = finalColor;
}

在qwidget界面中调用如下

#ifndef WIDGET_H
#define WIDGET_H#include <QOpenGLWidget>
#include <QTimer>
#include "genericrender.h"class Widget : public QOpenGLWidget
{Q_OBJECTpublic:Widget(QWidget *parent = 0);~Widget();protected:void initializeGL() override;void resizeGL(int w,int h) override;void paintGL() override;private:GenericRender render_;QTimer tm_;QVector3D cameraLocation_,lightLocation_;QMatrix4x4 pMatrix_;qreal angleX_,angleY,anglZ_;private slots:void slotTimeout();
};#endif // WIDGET_H
#include "widget.h"
#include "utils/objloader.h"Widget::Widget(QWidget *parent): QOpenGLWidget(parent)
{connect(&tm_,SIGNAL(timeout()),this,SLOT(slotTimeout()));tm_.start(30);
}Widget::~Widget()
{}void Widget::initializeGL()
{render_.initsize("vanquish.obj",QImage("vanquish.jpg"));cameraLocation_.setX(0);cameraLocation_.setY(0);cameraLocation_.setZ(3);lightLocation_.setX(10);lightLocation_.setY(10);lightLocation_.setZ(1);
}void Widget::resizeGL(int w, int h)
{pMatrix_.setToIdentity();pMatrix_.perspective(45,float(w)/h,0.01f,100.0f);
}void Widget::paintGL()
{QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();f->glClearColor(0.0f,0.0f,0.0f,1.0f);f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);QMatrix4x4 vMatrix;vMatrix.lookAt(cameraLocation_,QVector3D(0,0,0),QVector3D(0,1,0));QMatrix4x4 mMatrix;mMatrix.translate(0,-0.8);
//    mMatrix.rotate(angleX_,1,0,0);mMatrix.rotate(angleY,0,1,0);
//    mMatrix.rotate(anglZ_,0,0,1);render_.render(f,pMatrix_,vMatrix,mMatrix,cameraLocation_,lightLocation_);
}void Widget::slotTimeout()
{angleX_ += 5;angleY += 5;anglZ_ += 5;update();
}

到此结束。

qt opengl 加载3d模型(obj格式)相关推荐

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

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

  2. Qt和OpenGL:使用Open Asset Import Library(ASSIMP)加载3D模型

    Qt和OpenGL:使用Open Asset Import Library(ASSIMP)加载3D模型 翻译自:https://www.ics.com/blog/qt-and-opengl-loadi ...

  3. Qt Quick 3D系列(一):加载3d模型

    如果我们想在QML中使用3D且你之前没有三维程序开发的基础,使用Qt Quick 3D是个不错的选择,下面我介绍如何使用Qt Quick 3D加载3d模型.注意:Qt Quick 3D从Qt 5.15 ...

  4. Cesium.js 加载3D模型

    一.Cesuimjs介绍 Cesiunjs是一套GIS行业中进行地图渲染的js库,该库使用的WebGL进行地图渲染.并且结合HTML5进行相应,从而实现3D中渲染地图.本篇文章则介绍如何将后缀名为ma ...

  5. threejs加载3D模型例子

    加载3D模型 首先要引入ColladaLoader加载器,Collada是一个3D模型交换方案,即不同的3D模型可以通过Collada进行相互转换,言外之意,threejs可以使用Collada将3D ...

  6. 如何加载3D模型(odj文件和mtl文件)

    模型的加载 因为,在最近的项目模块中需要加载部分"模型".在加载模型在方面我从来的没有接触过,是通过同事告诉,慢慢摸索才完成的,其中是我遇到的问题和总结的一些的方法. 使用VUE加 ...

  7. threejs加载3D模型

    加载3D模型 首先要引入ColladaLoader加载器,Collada是一个3D模型交换方案,即不同的3D模型可以通过Collada进行相互转换,言外之意,threejs可以使用Collada将3D ...

  8. PHP加载3D模型【WebGL】

    这是另一篇关于如何使用 PHP加载 3D 模型的文章. 在这里,我使用 Laravel 作为后端及其存储. 我在前端使用 Three.Js 库来渲染和显示 3D 模型. 我将向您展示如何上传 3D 模 ...

  9. Labview加载3D模型(.wrl)出现内存不足的解决方法

    Labview加载3D模型(.wrl)出现内存不足的解决方法 最近,由于项目的要求,需要做一个上位机,用于实时采集装备的状态信息.最终方案采用Labview数据流的方式构建应用程序.在加载wrl3D模 ...

最新文章

  1. Python使用Redis实现IP代理池
  2. 赠 看穿一切的var_dump
  3. 盛佳:搜索是有目的的发现,发现是无目的的搜索
  4. java list类型参数_java – List是一个原始类型.引用通用类型List应该参数化
  5. 领域驱动设计DDD实战进阶第一波(十四):开发一般业务的大健康行业直销系统(订单上下文应用服务用例与接口)...
  6. MySQL 如何复制表
  7. ecshop php升级,升级-安装与升级- ECShop帮助
  8. mysql表空间自增_Oracle 默认表空间问题及自增变量设置
  9. 20190816:(leetcode习题)有效的数独
  10. vim修改tab默认4个空格
  11. 设置tomcat内存
  12. pytorch nn.CrossEntropyLoss()中的label不需要是one_hot
  13. [SoapUI]怎样保存response到本地文件夹
  14. 数据结构与算法(三):链表
  15. 电源管理模块设计 - 线性电源和开关电源的区别
  16. 读取网络时间完整代码
  17. [HEVC] HEVC学习(五) —— 帧内预测系列之三
  18. VASP自旋(NM、AM、AFM)
  19. 接口自动化之操作mysql数据库
  20. 约瑟夫环问题(数学递推法)

热门文章

  1. SpreadJS 15.0 vs SpreadJS 14.0 Patch
  2. 数学建模方法——SPSS主成分分析法
  3. 谷粒商城11——认证服务、短信验证、Gitee-OAuth 社交登录、分布式session
  4. 以“微”知著,用友ISV生态的力量与担当
  5. 打开Excle出现配置进度解决方法【WPS罪魁祸首】
  6. Grafana 的介绍和安装
  7. 1.Understanding the Rasa NLU Pipeline
  8. 夏杰语音麦克精灵:智能语音交互升级新体验
  9. zz2021029-2021年全国职业院校技能大赛(中职组)
  10. 金融科技业务的云端服务