之前学习了window+vs的方式使用assimp库进行模型加载,但是咧,并不支持跨平台使用,所以又搞了一次linux+qt来完成
本章只包含assimp库内容以及assimp与qt交互的问题,其他内容不过多介绍,不熟悉者还是边看learnopengl官网学习边参考

不过大家有问题还是可以问我,我知道的会给大家解答,也可以提出我代码的问题,我会进行修改

1.assimp库导入qt

在此之前需要进行assimp库编译,linux编译都差不多,用3个命令

cmake CMakeLists.txt
make
make install

这里不过多介绍

然后导入我使用一种简单(直接链接)的方法(正式项目不要用哦)
在.pro文件中加入
LIBS +=
/root/assimp/assimp-3.1.1/lib/libassimp.so

这是我assimp库的绝对路径,.so就是linux的库文件,类似window下的.lib文件

2.使用qt封装好的类,而不再使用glew和glut

QOpenGLWidget
用于进行渲染的窗体,我们需要继承并重写3个函数

virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();

这3个函数不需要手动调用,qt会自动调用

QOpenGLFunctions_3_3_Core
版本化的函数包装器,类似glew,用于使用opengl函数,针对给定的opengl版本和配置文件,通常在渲染类(有shader的类中)和main函数中继承或使用
QOpenGLExtraFunctions
函数包装器,对OpenGL ES 3进行跨平台访问,类似QOpenGLFunctions_
3_3_Core,不过是通用的,一般在封装的类中继承,因为封装的类并不进行渲染,而是渲染程序调用时由调用的渲染程序进行渲染

QOpenGLShaderProgram
封装好的着色器程序,我们不用再自己编写shader了
QOpenGLTexture
封装好的纹理,我们不用再自己编写纹理载入代码了

3.渲染窗口

我就不过多介绍了,与window上不同的地方,我会用注释解释

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QTime>
#include <QTimer>
#include <QVector3D>
#include <QKeyEvent>
#include <QMouseEvent>
#include "camera.h"
#include <QDebug>
#include "model.h"
#include <QCoreApplication>
#include <QFileDialog>#define PI 3.1415926
class MyOpenGLWidget : public QOpenGLWidget,protected QOpenGLFunctions_3_3_Core
{//继承QOpenGLFunctions_3_3_Core用于使用openGL函数库
//继承QOpenGLWidget用于实现我们自己的渲染窗口Q_OBJECT
public:explicit MyOpenGLWidget(QWidget *parent = nullptr);~MyOpenGLWidget();protected:virtual void initializeGL();virtual void resizeGL(int w, int h);virtual void paintGL();//用于实现camera移动,观看不同的视角virtual void keyPressEvent(QKeyEvent *event);virtual void mouseMoveEvent(QMouseEvent *event);virtual void mousePressEvent(QMouseEvent *event);virtual void mouseReleaseEvent(QMouseEvent *event);
//camera,learnopengl教程中的入门就有,不多介绍Camera *camera;
//着色器程序QOpenGLShaderProgram *colorShader;Model ourModel;QTimer timer;QTime m_time;float deltaTime = 0.0f; // 当前帧与上一帧的时间差float lastFrame = 0.0f; // 上一帧的时间QPoint lastPos;bool leftButtonIsPressed = false;float sensitivity = 0.2f;private:signals:public slots:void on_timer_timeout();
};#endif // MYOPENGLWIDGET_H

这里先不介绍cpp文件,先实现mesh和model文件,最后再介绍

4.mesh类

头文件

#ifndef MESH_H
#define MESH_H
#include <QString>
#include <QVector3D>
#include <QOpenGLShaderProgram>
#include <QOpenGLExtraFunctions>
#include <QOpenGLTexture>
#include <QDebug>using std::vector;
struct Vertex {QVector3D Position;QVector3D Normal;QVector3D TexCoords;
};struct Texture {unsigned int num;QString type;QString filename;
};class Mesh : protected QOpenGLExtraFunctions
{//继承QOpenGLExtraFunctions用于使用opengl函数
public:vector<Vertex> vertices;vector<unsigned int> indices;vector<Texture> textures;Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures);~Mesh();void Draw(QOpenGLShaderProgram *shader,vector<QOpenGLTexture*> textureInstances);//draw时传入着色器程序和纹理
private:/*  渲染数据  */unsigned int VAO, VBO, EBO;/*  函数  */void setupMesh();//用于初始化网格数据
};#endif // MESH_H

cpp文件

#include "mesh.h"Mesh::Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures)
{this->vertices = vertices;this->indices = indices;this->textures = textures;setupMesh();
}Mesh::~Mesh()
{}void Mesh::Draw(QOpenGLShaderProgram* shader,vector<QOpenGLTexture*> textureInstances)
{shader->bind();for(unsigned int i = 0; i < textures.size(); i++){//遍历网格纹理,获取纹理类型,并读出纹理对象QString name = textures[i].type;if(name == "texture_diffuse"){//bind(),QOpenGLTexture函数,直接绑定到指定的纹理单元,而不用再先glActiveTexture了,很方便textureInstances[textures[i].num]->bind(0);//shaderProgram也直接封装了,setUnifromxxx的函数也直接封装成setUnifromValue()这一个函数,很方便shader->setUniformValue(("material." + name).toLatin1().data(), 0);//toLatin1()从QStirng 转为QByteArray//data()转为char *//设置着色器中此变量纹理也第0槽纹理,也就是刚bind 的}else if(name == "texture_specular"){//同上textureInstances[textures[i].num]->bind(1);shader->setUniformValue(("material." + name).toLatin1().data(), 1);}}// 绘制网格glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);glBindVertexArray(0);shader->release();
}void Mesh::setupMesh()
{initializeOpenGLFunctions();//类似glew的init函数,初始化opengl函数库,必须在第一步用,否则下面的函数都不能使用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);glBindBuffer(GL_ARRAY_BUFFER,0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
}

5.model类

头文件

#ifndef MODEL_H
#define MODEL_H
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QImage>
#include "mesh.h"
#include <QString>
#include <string>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <QDebug>
using std::string;class Model
{public:Model();~Model();void loadModel(string path);void Draw(QOpenGLShaderProgram *shader);
private:/*  模型数据  */vector<Mesh> meshes;QString directory;/*  函数   */void processNode(aiNode *node, const aiScene *scene);Mesh processMesh(aiMesh *mesh, const aiScene *scene);vector<Texture> loadMaterialTextures(aiMaterial *mat, aiTextureType type,QString typeName);//用于存放纹理,待传入mesh中使用,由于是指针,放在类私有成员等析构函数delete掉vector<QOpenGLTexture *> m_textureInstance;//纹理数(不是个数,而是在vector中的索引)unsigned int m_num = 0;
};#endif // MODEL_H

cpp文件

#include "model.h"Model::Model()
{}Model::~Model()
{//把指针内存释放掉for(unsigned int i = 0; i < m_textureInstance.size(); ++i){delete m_textureInstance[i];}
}void Model::Draw(QOpenGLShaderProgram *shader)
{//for循环分别绘制每个网格for(unsigned int i = 0; i < meshes.size(); i++)meshes[i].Draw(shader,m_textureInstance);
}//加载模型
//通过assimp::Importer类的ReadFile函数读取模型文件,它返回一个aiScene*是assimp库的类,只要遵循它库的规则,用正确的类接受,这里没啥问题
void Model::loadModel(string path)
{Assimp::Importer importer;const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);//判断是否读取文件成功if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){qDebug() << "ERROR::ASSIMP::" << importer.GetErrorString() << endl;return;}//获取目录,从最后一个“/"往前的所有字符串,一会用来读取其他文件directory = QString::fromStdString(path.substr(0, path.find_last_of('/')));//遍历节点(简单介绍:scene中存放着root节点,网格数据和metaril材//质,root节点指向子节点,每个子节点分别还有自己的子节点,类似树的结//构,每个节点下有它所对应的网格数据的索引,通过索引去scene中获取自己     //对应的网格数据,挨着递归就可以了,mesh类中存放了顶点数据,法线数//据,纹理坐标数据,还有面的数据,以及纹理索引,这里的面是立方体的面的//意思,每个面中有它对应顶点的索引,获取索引用于绘制面,最后是纹理索//引,通过纹理索引去scene中获取纹理,大体就是这样)processNode(scene->mRootNode, scene);
}void Model::processNode(aiNode *node, const aiScene *scene)
{// 处理节点所有的网格(如果有的话)for(unsigned int i = 0; i < node->mNumMeshes; i++){aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];meshes.push_back(processMesh(mesh, scene));}// 接下来对它的子节点重复这一过程for(unsigned int i = 0; i < node->mNumChildren; i++){processNode(node->mChildren[i], scene);}
}Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene)
{vector<Vertex> vertices;vector<unsigned int> indices;vector<Texture> textures;for(unsigned int i = 0; i < mesh->mNumVertices; i++){Vertex vertex;// 处理顶点位置、法线和纹理坐标QVector3D vector;vector.setX(mesh->mVertices[i].x);vector.setY(mesh->mVertices[i].y);vector.setZ(mesh->mVertices[i].z);vertex.Position = vector;vector.setX(mesh->mNormals[i].x);vector.setY(mesh->mNormals[i].y);vector.setZ(mesh->mNormals[i].z);vertex.Normal = vector;if(mesh->mTextureCoords[0]) // 网格是否有纹理坐标?{QVector2D vec;vec.setX(mesh->mTextureCoords[0][i].x);vec.setY(mesh->mTextureCoords[0][i].y);vertex.TexCoords = vec;}elsevertex.TexCoords = QVector2D(0.0f, 0.0f);vertices.push_back(vertex);}// 处理索引for(unsigned int i = 0; i < mesh->mNumFaces; i++){aiFace face = mesh->mFaces[i];for(unsigned int j = 0; j < face.mNumIndices; j++)indices.push_back(face.mIndices[j]);}// 处理材质if(mesh->mMaterialIndex >= 0){aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];vector<Texture> diffuseMaps = loadMaterialTextures(material,aiTextureType_DIFFUSE, "texture_diffuse");textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());vector<Texture> specularMaps = loadMaterialTextures(material,aiTextureType_SPECULAR, "texture_specular");textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());}return Mesh(vertices, indices, textures);
}vector<Texture> Model::loadMaterialTextures(aiMaterial *mat, aiTextureType type, QString typeName)
{//这个函数不多将,learnopengl网站写的很详细vector<Texture> textures_temp;vector<Texture> textures_loaded;for(unsigned int i = 0; i < mat->GetTextureCount(type); i++){aiString str;mat->GetTexture(type, i, &str);QString filename = QString::fromStdString(str.C_Str()); //类型转换aiString转为QStringbool skip = false;for(unsigned int j = 0; j < textures_loaded.size(); j++){if(textures_loaded[j].filename == filename){textures_temp.push_back(textures_loaded[j]);skip = true;break;}}if(!skip){   // 如果纹理还没有被加载,则加载它Texture texture;QString path = directory+"/"+filename;//new出纹理对象放在vector中供使用,以及纹理的一些配置,都是//qt封装好的,就是st方向的环绕方式和缩小放大筛选器,类似//glTexParametri()QOpenGLTexture *textureInstance =  new QOpenGLTexture(QImage(path).mirrored());textureInstance->setWrapMode(QOpenGLTexture::DirectionS,QOpenGLTexture::Repeat);textureInstance->setWrapMode(QOpenGLTexture::DirectionT,QOpenGLTexture::Repeat);textureInstance->setMagnificationFilter(QOpenGLTexture::Linear);textureInstance->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);m_textureInstance.push_back(textureInstance);texture.num = m_num++;texture.type = typeName;texture.filename = filename;textures_temp.push_back(texture);textures_loaded.push_back(texture); // 添加到已加载的纹理中        }}return textures_temp;
}

6.渲染

#include "myopenglwidget.h"MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{setFocusPolicy(Qt::StrongFocus);setMouseTracking(true);connect(&timer, SIGNAL(timeout()), this, SLOT(on_timer_timeout()));timer.start(100);m_time.start();
}MyOpenGLWidget::~MyOpenGLWidget()
{delete camera;delete colorShader;
}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();camera = new Camera(QVector3D(0.0f,0.0f,3.0f),0.0f,-90.0f,QVector3D(0.0f,1.0f,0.0f));glEnable(GL_DEPTH_TEST);colorShader = new QOpenGLShaderProgram();colorShader->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/color.vert");colorShader->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/color.frag");bool success = colorShader->link();if(!success){qDebug() << colorShader->log();}
//linux+qt读文件是读相对路径,记得把模型文件(文件夹)放到编译后的目录中
//由于使用的是assimp的ReadFile,使用qt的.qrc文件我这里没成功ourModel.loadModel("./model/nanosuit.obj");
}void MyOpenGLWidget::resizeGL(int w, int h)
{Q_UNUSED(w);Q_UNUSED(h);
}void MyOpenGLWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_TEST);colorShader->bind();colorShader->setUniformValue("viewPos", camera->getPostion());QMatrix4x4 projection;projection.perspective(45.0f,(float)width()/(float)height(),0.1f, 100.0f);QMatrix4x4 view;view = camera->getViewMatrix();colorShader->setUniformValue("projection", projection);colorShader->setUniformValue("view", view);QMatrix4x4 model;colorShader->setUniformValue("model", model);ourModel.Draw(colorShader);colorShader->release();
}void MyOpenGLWidget::keyPressEvent(QKeyEvent *event)
{switch (event->key()) {case Qt::Key_W:camera->speedZ = 1.0f* deltaTime;break;case Qt::Key_S:camera->speedZ = -1.0f * deltaTime;break;case Qt::Key_D:camera->speedX = 1.0f * deltaTime;break;case Qt::Key_A:camera->speedX = -1.0f * deltaTime;break;case Qt::Key_Up:camera->speedY = 1.0f * deltaTime;break;case Qt::Key_Down:camera->speedY = -1.0f * deltaTime;break;case Qt::Key_Escape:this->parentWidget()->setFocus();default:break;}camera->updataCameraPos();update();
}void MyOpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{if(leftButtonIsPressed){QPoint currentPos = event->pos();QPoint deltaPos = currentPos - lastPos;lastPos = currentPos;deltaPos *= sensitivity;camera->processMouseMove(deltaPos.x(),-deltaPos.y());update();}
}void MyOpenGLWidget::mousePressEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){lastPos = event->pos();leftButtonIsPressed = true;}
}void MyOpenGLWidget::mouseReleaseEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){leftButtonIsPressed = false;}
}void MyOpenGLWidget::on_timer_timeout()
{float currentFrame = m_time.elapsed()/1000.0f;deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;
}

vertex着色器文件和fragment着色器和learnopengl上的一模一样

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;out vec2 TexCoords;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{TexCoords = aTexCoords;gl_Position = projection * view * model * vec4(aPos, 1.0);
}
#version 330 core
in vec2 TexCoords;out vec4 FragColor;struct Material {sampler2D texture_diffuse;sampler2D texture_specular;
};uniform Material material;void main()
{vec4 diffuse = texture2D(material.texture_diffuse, TexCoords);FragColor = diffuse;
}

最后在ui界面添加一个QOpenGLWidget,然后promote为自己定义的myOpenGLWidget

并在mianWindow中设置中心组件

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);setCentralWidget(ui->openGLWidget);showFullScreen ();
}

成果展示:

最后总结一下用到的assimp库的东西
Assimp::Importer
importer.ReadFile
importer.GetErrorString

aiProcess_Triangulate
aiProcess_FlipUVs

aiScene
scene->mRootNode
scene->mMeshes
scene->mMaterials

aiNode
node->mNumMeshes
node->mNumChildren
node->mChildren

aiMesh
mesh->mVertices
mesh->mNormals
mesh->mTextureCoords
mesh->mNumFaces
mesh->mFaces
mesh->mMaterialIndex

aiFace
face.mNumIndices
face.mIndices

aiMaterial
mat->GetTextureCount
mat->GetTexture

aiTextureType_DIFFUSE
aiTextureType_SPECULAR

aiString
str.C_Str()

linux+qt使用assimp库进行模型加载相关推荐

  1. Qt Quick 3D学习:模型加载

    (注意,开源版的 Qt Quick 3D 是狗都不用的 GPL 协议) Qt Quick 3D 模块提供了 Model 类型用于 3D 模型加载,通过设置 source 的资源路径来加载对应的 3D ...

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

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

  3. OpenGL Assimp模型加载库

    OpenGL Assimp库 前言 模型加载库 构建Assimp 前言 到目前为止的所有场景中,我们一直都在滥用我们的箱子朋友,但时间久了甚至是我们最好的朋友也会感到无聊.在日常的图形程序中,通常都会 ...

  4. QT+OpenGL模型加载 - Assimp

    QT+OpenGL模型加载 - Assimp 本篇完整工程见gitee:OpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主 模型加载 先来张图: 我们不大可能手 ...

  5. 用Assimp模型加载库加载一个Crytek的游戏孤岛危机(Crysis)中的原版纳米装(Nanosuit)

    用这个例子来对GitHub上的LearnOpenGL教程前四个单元用到的所有自定义或者引入的各种头文件和资源进行一个总结,不得不说这个教程简直太美妙了. 这个模型是来自对GitHub上的LearnOp ...

  6. 模型加载库 Assimp

    大家好,接下来将为大家介绍模型加载库 Assimp . 1.Assimp介绍 Assimp 全称为 Open Asset Import Library,可以支持几十种不同格式的模型文件的解析(同样也可 ...

  7. Linux动态加载共享库,Linux共享库的动态加载(附测试案例)

    共享库的动态加载是指可以在程序运行的过程中去加载所需的共享库.常用于某些系统或者应用程序的自动升级. 在C语言的源程序动态加载共享库,需要调用一组特殊的函数,它们被声明于一个专门的头文件dlfcn.h ...

  8. Linux下的静态库、动态库和动态加载库

    from: http://www.techug.com/linux-static-lib-dynamic-lib 库的存在极大的提高了C/C++程序的复用性,但是库对于初学者来说有些难以驾驭,本文从L ...

  9. linux直接运行程序加载动态库失败,扣丁学堂Linux培训详解程序运行时加载动态库失败解决方法...

    今天扣丁学堂Linux培训老师给大家介绍一下关于Linux程序运行时加载动态库失败的解决方法,希望对同学们学习有所帮助,下面我们一起来看一下吧. Linux下不能加载动态库问题 当出现下边异常情况 . ...

  10. Linux动态库的动态加载与静态加载以及加载依赖了其他动态库的动态库

    Linux动态库加载 在Linux下,动态库格式一般为libxxx.so或者libxxx.so.3这种格式. 通常我们在网上下载下来源码包,编译之后会是libxxx.so软连接libxxx.so.1链 ...

最新文章

  1. Linux系统编程——进程基础知识
  2. How to add and configure jetty server in maven pom.xml
  3. 平面设计师必备的十个技能
  4. python跨包导入包_python引入跨模块包
  5. tarjan求LCA模板
  6. mac 显示隐藏文件_MacOS如何隐藏、加密文件或文件夹
  7. Linux学习总结(78)—— 常见开源协议讲解
  8. mooc中习题--计算天数
  9. aov建立Java模拟,JAVA
  10. mysql 5.7 sys schema_案例详细说明MySQL5.7中 performance与sys schema中的监控参数
  11. ARM启动流程及启动代码分析
  12. Win11系统电脑怎么C盘扩容教学
  13. 如何不用绿幕,从视频中移除背景?
  14. 汽车行业如何借助微信小程序引流
  15. 使用()关键字来创建python的自定义函数_17.python自定义函数
  16. 杭电数电实验(二)译码器
  17. TimesTen IX锁及用途介绍[TimesTen运维]
  18. Linux安装LUA
  19. 计算机科学创新大赛,计算机学院大学生创新项目入围挑战杯大赛
  20. 登录模块测试点提取大纲1(功能,性能,界面,兼容,安全,稳定,易用)

热门文章

  1. 基于matlab的电池管理系统开发,使用 Simulink 和基于模型的设计开发电池管理系统...
  2. opencv 4.5.5 imread 失败(报错)的处理方式
  3. 国开电大 古代诗歌散文专题 形考任务
  4. 如何让电脑的时间显示到秒
  5. 计算机wifi共享怎么设置,笔记本电脑设置wifi热点共享教程
  6. 实现三级导航demo
  7. android system image,android systemimage默認大小以及如何修改
  8. m3u8格式转换器android,m3u8转换格式mp4软件下载-m3u8转换格式 安卓版v2.7.0-PC6安卓网...
  9. 【博客分享】优秀的有趣的博客
  10. 正则表达式:多选项匹配