OpenGL(Open Graphics Library)是一种用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序接口。OpenGL的实现利用了图形加速硬件,这些实现一般由显示设备厂商提供。但真正使用时,一般采用基于gl的第三方库,用于在程序的运行期判断当前硬件是否支持相关的扩展,防止程序崩溃甚至造成硬件损坏。目前我了解到的第三方库就有glad、glew、glfw、freeglut等,下图反映了它们之间的关系。

此外在安装Qt后,Qt本身也会对gl库进行一定的封装,即qopengl.h和QOpenGLFunctions。Qt是目前做UI非常好的一款工具,再结合它给的例子,比如cube、hellogl2等,可以仿照着做出很多比较好的人机交互界面。

对于三维模型,常用的软件有solid work,AutoCAD等,可以采用这些软件画出后导出stl模型文件。 STL 文件有2 种类型:文本文件(ASCII格式)和二进制文件(BINARY)。其中文本格式的可以用notepad++打开,它里面包含多个三角形面片的定义组成,每个三角形的定义包括三角形各个定点的三维坐标及三角形面片的法矢量,三角形顶点的排列顺序遵循右手法则。因此对于用opengl渲染stl文件,我们首先得加载它,https://free3d.com也可下到很多模型文件。

1. 使用Qt自带的库

使用Qt自带的库,窗口可继承public QOpenGLWidget, protected QOpenGLFunctions(提供了一套OpenGL ES2.0 API,免去开发人员手动解析这些函数符号)。不过关于OpenGL ES的写法,我还是有点迷糊,没有看到比较系统性的介绍,一般给的例子都是采用现成的模板,我这里采用的是Qt例子中的方法。关于stl文本文件的加载,网上就有太多方法。

bool QObjLoad::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<int> facesIndexs;while (!objFile.atEnd()){QByteArray lineData = objFile.readLine();QList<QByteArray> strValues = lineData.trimmed().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"){facesIndexs << strValues.at(0).toInt() << strValues.at(1).toInt() << strValues.at(2).toInt();}}objFile.close();for (auto& verFaceInfo : facesIndexs){int vIndex = verFaceInfo - 1;vPoints << vertextPoints.at(vIndex * 3);vPoints << vertextPoints.at(vIndex * 3 + 1);vPoints << vertextPoints.at(vIndex * 3 + 2);}vertextPoints.clear();texturePoints.clear();normalPoints.clear();facesIndexs.clear();return true;
}

这里主要是为了获取顶点坐标,接着就是在Qt的窗口上显示了,要重新实现三个函数void initializeGL() override、void paintGL() override和void resizeGL(int width, int height) override。

void GLWindow::initializeGL()
{initializeOpenGLFunctions();glClearColor(0, 0, 0, 0);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("projMatrix");m_mvMatrixLoc = m_program->uniformLocation("mvMatrix");m_normalMatrixLoc = m_program->uniformLocation("normalMatrix");m_lightPosLoc = m_program->uniformLocation("lightPos");// Setup our vertex buffer object.m_Vbo.create();m_Vbo.bind();m_Vbo.allocate(m_vPoints.data(), m_vPoints.size() * sizeof(float));// Store the vertex attribute bindings for the program.setupVertexAttribs();// Light position is fixed.m_program->setUniformValue(m_lightPosLoc, QVector3D(10, 10, 10));m_program->release();
}void GLWindow::paintGL()
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnable(GL_DEPTH_TEST);glEnable(GL_CULL_FACE);m_world.setToIdentity();m_world.rotate(m_xRot / 16.0f, 1, 0, 0);m_world.rotate(m_yRot / 16.0f, 0, 1, 0);m_world.rotate(m_zRot / 16.0f, 0, 0, 1);m_camera.setToIdentity();m_camera.lookAt(m_camera_pos, QVector3D(0, 0, 0), QVector3D(1, 0, 0));m_program->bind();m_program->setUniformValue(m_projMatrixLoc, m_proj);m_program->setUniformValue(m_mvMatrixLoc, m_camera * m_world);QMatrix3x3 normalMatrix = m_world.normalMatrix();m_program->setUniformValue(m_normalMatrixLoc, normalMatrix);glDrawArrays(GL_TRIANGLES, 0, m_vPoints.size()/3);m_program->release();
}void GLWindow::resizeGL(int w, int h)
{m_proj.setToIdentity();m_proj.perspective(45.0f, GLfloat(w) / h, 0.01f, 100.0f);
}

最后通过lookAt设置视角去显示。我把视角进行了可调,这样就能从不同视角来查看,效果如下。

2. 通过freeglut和Qt的结合

freeglut是GLUT的开源替代库,里面很多函数,而且大多数人比较熟悉,所以用这个可能更受青睐。freeglut可以在http://freeglut.sourceforge.net下到,下载后通过cmake生成vs工程,然后就可以使用freeglut.lib和freeglut.dll库,同时需将GL目录下的头文件也拷到相应的目录下。

还是一样的,加载stl文件并显示。不过这种方法对于鼠标或者键盘的操作等的处理就非常麻烦。而且不知道为啥,我显示的颜色和角度有点奇怪。关于灯光位置,视角,渲染,各种矩阵变换,还是有很多有待弄清楚的。

typedef struct Vertex
{//定义三维图形的//用于face结构体中float x, y, z;
} Vertex;typedef struct Face
{//多边形(三角形)面的结构体Face(void) : vert_number(0), verts(0) {};int vert_number;        //记录顶点的个数Vertex** verts;          //这是一个面的所有 顶点数组(含有坐标)float normal[3];         //记录点的法向量,分别是x,y,z三个方向//注意点的法向量通过顶点的信息计算得到!//对于obj模型如果我们已经得到了法线的信息//那么就直接拿来用就好!
} Face;typedef struct myMesh
{//自定义mesh的结构体myMesh(void) : vert_number(0), verts(0), face_number(0), faces(0) {};//自定义构造器int vert_number;        //总的顶点个数Vertex* verts;          //定点数组int face_number;        //面的数目Face* faces;vector<Vertex>point;
} myMesh;void GLWin::drawObj()
{if (m_mesh->face_number == 0)return;qDebug() << m_mesh->face_number;float bbox[2][3] = { { 1.0E30F, 1.0E30F, 1.0E30F }, { -1.0E30F, -1.0E30F, -1.0E30F } };for (int i = 0; i < m_mesh->vert_number; i++){Vertex& vert = m_mesh->verts[i];if (vert.x < bbox[0][0])bbox[0][0] = vert.x;else if (vert.x > bbox[1][0])bbox[1][0] = vert.x;if (vert.y < bbox[0][1])bbox[0][1] = vert.y;else if (vert.y > bbox[1][1])bbox[1][1] = vert.y;if (vert.z < bbox[0][2])bbox[0][2] = vert.z;else if (vert.z > bbox[1][2])bbox[1][2] = vert.z;}// Setup initial viewing scalefloat dx = bbox[1][0] - bbox[0][0];float dy = bbox[1][1] - bbox[0][1];float dz = bbox[1][2] - bbox[0][2];scale = 2.0 / sqrt(dx * dx + dy * dy + dz * dz);glPushMatrix();glColor3f(0.5, 0.5, 0.5);glScalef(scale, scale, scale);glRotatef(rotation[0], 1.0, 0.0, 0.0);glRotatef(rotation[1], 0.0, 1.0, 0.0);glRotatef(rotation[2], 0.0, 0.0, 1.0);for (int i = 0; i < m_mesh->face_number; i++){Face& face = m_mesh->faces[i];glBegin(GL_TRIANGLES);glNormal3fv(face.normal);for (int j = 0; j < face.vert_number; j++){Vertex* vert = face.verts[j];glVertex3f(vert->x, vert->y, vert->z);}glEnd();}glPopMatrix();
}void GLWin::initializeGL()
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glClearColor(0.0, 0.0, 0.0, 0.0);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);glEnable(GL_NORMALIZE);glEnable(GL_DEPTH_TEST);glutInitWindowSize(600, 600);
}void GLWin::paintGL()
{glLoadIdentity();glMatrixMode(GL_MODELVIEW);glLoadIdentity();glLightfv(GL_LIGHT0, GL_POSITION, light0_position);gluLookAt(1, 1, 1, 0, 0, 0, 0, 1, 0);//draw axisglPushMatrix();glLineWidth(5);glBegin(GL_LINES);glColor3f(1, 0, 0);glVertex3f(0.0f, 0, 0);glVertex3f(10, 0, 0);glEnd();glBegin(GL_LINES);glColor3f(0, 1, 0);glVertex3f(0.0f, 0, 0);glVertex3f(0, 10, 0);glEnd();glBegin(GL_LINES);glColor3f(0, 0, 1);glVertex3f(0, 0, 0);glVertex3f(0, 0, 10);glEnd();glPopMatrix();CLoadStlObj stlobj;m_mesh = stlobj.ReaderOBj("head.obj");drawObj();// 设置光照信息static GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);static GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };设置满散射glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);glEnable(GL_LIGHT0);static GLfloat light1_diffuse[] = { 0.5, 0.5, 0.5, 1.0 };glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);glEnable(GL_LIGHT1);glEnable(GL_LIGHTING);
}void GLWin::resizeGL(int width, int height)
{glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(45.0, (GLfloat)width / (GLfloat)height, 0.1, 100.0);glMatrixMode(GL_MODELVIEW);glLoadIdentity();
}

方法1的工程代码可以在https://github.com/WelinLee/QtOpenGLDemo中找到,enjoy!

两种方法在Qt中使用OpenGL库加载stl三维模型相关推荐

  1. Qt工作笔记-两种方法从容器中筛选出父类和子类(继承法、typeid法)

    两种方法程序运行界面效果都一样! 程序运行截图如下: 这个图随便看看就可以了,没啥用! 代码如下: widget.h #ifndef WIDGET_H #define WIDGET_H#include ...

  2. 两种方法:在 PowerPoint 中插入视频

    为追求更完美效果,在Powerpoint中通过shockwave Flash Object控件插入SWF格式动画已是家常便饭.但很多情况下,演示文档还需要视频做辅助,下面我们介绍在PowerPoint ...

  3. ROS☞通过两种方法提取.bag中的图像数据

    以下两种环境均在Ubuntu16.04环境下测试成功. 第一种方法 ROS-从rosbag中提取图像(by launch文件) 1.新建launch文件(文件在哪无所谓,可以在catkin_ws的根目 ...

  4. python程序中结束while循环的两种方法是_Python中while循环

    一.while 简介 Python 的循环有 for 和 while 两种,while 为条件控制循环,通过条件表达式控制循环结束. 流程图如下: Python 中 while 语句的格式如下: wh ...

  5. Python大作业——两种方法设计计算器(使用wx库)。

    python大作业 本次设计用Pycharm开发工具,Python语言进行主要功能是基于图形用户面的多功能.该计算器的主要功能是加.减.乘.除等常规运算以及指数,对数,三角函数等科学运算功能.该计算器 ...

  6. qt中append函数_Qt 加载cern-root库 并调用root类

    cern-root是欧洲核子研究中心CERN开发的基于C++,可与python,R,Fortran等语言进行绑定的数据处理框架.cern-root最初基于Qt开发,在root5之前可通过Qt来开发ro ...

  7. 在qt中实现图片的加载

    (走了个弯路.用opencv显示qt图片...可以但没必要) 下面是常见的Qlabel加载图片 检测图片是否可以加载 QString filename = "C:\\Users\\Admin ...

  8. Android Studio中RecycerView依赖库加载问题

    依赖包导入思考: 参考资料:recycleview导包问题 打开修改本项目中的build.gradle; 切勿着急添加包,应当提前查看其中的版本号(因为加载的v7包要和其版本保持一致性): 例如: 因 ...

  9. LVGL7.11中使用freetype库加载显示字体

    目录 1.使用环境 2.关于freetype库 3.编译freetype-2.10.4 4.下载LVGL官方封装的接口lv_lib_freetype 5.在mian.c中添加测试代码 1.使用环境 硬 ...

  10. 如何在计算机中输入分数,两种方法在word中轻松输入分数

    不知道微软设计Office的时候有没有替我们用户考虑下,毕竟分数是很多办公人员常用的单位.PConline小编甚至还打听了一下,发现有许多朋友不知道分数怎么打,所以每次都用斜杠"/" ...

最新文章

  1. python语言介绍-Python语言简介
  2. 跟angular2学一键开启项目--关于上个react-redux项目的一键调试
  3. android drawable 比例,Android中的Drawable基础与自定义Drawable
  4. linux io分析工具,io性能分析工具-iostat
  5. 仿真:自动生成战争地图
  6. 【C语言】爱心表白代码
  7. Linux 开发环境搭建与使用——SlickEdit 简单使用教程
  8. 过滤百度广告+搜索热点+adblock规则快速入门
  9. vue3安装vuex报错: Could not resolve dependency npm ERR peer vue@“^2.0.0“ from vuex@3.6.2
  10. android 自动亮屏解锁,android 点亮手机屏幕与屏幕解锁方法
  11. DNS劫持、流量劫持,HTTP/HTTPS劫持
  12. AIX上解压缩.tar.Z, .tar.gz, .zip
  13. 快速导向滤波 matlab,导向滤波小结:从导向滤波(guided filter)到快速导向滤波(fast guide filter)的原理,应用及opencv实现代码...
  14. linux getchar函数使用
  15. NOI2002银河英雄传说
  16. 多目标优化(一)简单的 NSGA-Ⅱ
  17. label标签的作用
  18. AI绘画神器Stable Diffusion的疯狂与危险
  19. HTTP 错误 404.17 - Not Found 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理。...
  20. 2018-09-03 KK日记,记一次JVM内存使用过多的诊断

热门文章

  1. android7.1修改默认休眠时间为1分钟
  2. excel 行列转换
  3. 00 | 为什么下一个开源项目可能仅是一个接口
  4. 【Unity Shaders】Using Textures for Effects——通过修改UV坐标来滚动textures
  5. 虚拟机使用cheese调用摄像头黑屏问题解决
  6. Python检测重复字——部分中华字经重复字检测
  7. java实现图片压缩
  8. Android 监听软键盘弹出/隐藏,控制软键盘弹出/隐藏
  9. 保研面试-中英文问题及回答总结
  10. PHP俄罗斯方块游戏代码,俄罗斯方块游戏,俄罗斯方块游戏编程代码