Vries的原教程里,对于模型载入,使用的是一种非常流行的模型加载库Assimp,可以方便的加载obj,fbx,3ds等常见的模型格式文件,在visual studio2015里,我照原教程进行了Assimp的配置,程序成功运行。在Qt中,把Assimp当作外库进行导入,试了很多种方法也不可以,万般无奈之下,我自写了一个基于Qt平台的简易模型导入程序,仅针对简易obj模型进行解析导入。
https://learnopengl-cn.github.io/03%20Model%20Loading/01%20Assimp/关于Assimp库的内容与常见模型只是请看Vries的原版教程)
Qt开发平台:5.8.0
编译器:Desktop Qt 5.8.0 MSVC2015_64bit
本程序源代码
百度网盘链接:https://pan.baidu.com/s/1w60NPe69ySSqzkQ6o0BeVA 密码:dmud
csdn下载连接: https://download.csdn.net/download/z136411501/10611540
一,程序截图
![基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十五)obj模型加载_第1张图片](http://img.e-com-net.com/image/info8/50667986bbc7446a9dbcffcea689a5e2.jpg)
1.1 开启光照
![基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十五)obj模型加载_第2张图片](http://img.e-com-net.com/image/info8/07ae74c26f014eed98b4c9daeca42d2a.jpg)
1.2 关闭光照
![基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十五)obj模型加载_第3张图片](http://img.e-com-net.com/image/info8/5a257a99c4ed4472adf6a4694b368f4f.jpg)
1.3 线性渲染
![基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十五)obj模型加载_第4张图片](http://img.e-com-net.com/image/info8/46160e349e974b45adce5a0aec8c3557.jpg)
1.4 比武台
![基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十五)obj模型加载_第5张图片](http://img.e-com-net.com/image/info8/9d7a0a3427684845a6decd9d2ba1987f.jpg)
1.5 坦克
![基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十五)obj模型加载_第6张图片](http://img.e-com-net.com/image/info8/bc7ea4ba89384c16a6be857056e5d33a.jpg)
1.6 基地
二,obj模型解释
这里借用一下另外一个学习可编程管线OpenGL的网站里,对obj模型的解释,网站原链接如下:
http://www.opengl-tutorial.org/cn/beginners-tutorials/tutorial-7-model-loading/
相对于原链接所介绍的简易OBJ模型,我增添了一些内容,主要是材质文件mtllib的使用,
2.1 OBJ文件示例
在原作者的示例obj文件中,增添材质属性的使用,大概是这个模样:
# Blender3D v249 OBJ File: untitled.blend
# www.blender3d.org
mtllib cube.mtl
#
# object Arch41_039
#
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.748573 0.750412
vt 0.749279 0.501284
vt 0.999110 0.501077
vt 0.999455 0.750380
vt 0.250471 0.500702
vt 0.249682 0.749677
vt 0.001085 0.750380
vt 0.001517 0.499994
vt 0.499422 0.500239
vt 0.500149 0.750166
vt 0.748355 0.998230
vt 0.500193 0.998728
vt 0.498993 0.250415
vt 0.748953 0.250920
vn 0.000000 0.000000 -1.000000
vn -1.000000 -0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
vn -0.000001 0.000000 1.000000
vn 1.000000 -0.000000 0.000000
vn 1.000000 0.000000 0.000001
vn 0.000000 1.000000 -0.000000
vn -0.000000 -1.000000 0.000000
usemtl Material_ray
s off
f 5/1/1 1/2/1 4/3/1
f 5/1/1 4/3/1 8/4/1
f 3/5/2 7/6/2 8/7/2
f 3/5/2 8/7/2 4/8/2
f 2/9/3 6/10/3 3/5/3
f 6/10/4 7/6/4 3/5/4
f 1/2/5 5/1/5 2/9/5
f 5/1/6 6/10/6 2/9/6
f 5/1/7 8/11/7 6/10/7
f 8/11/7 7/12/7 6/10/7
f 1/2/8 2/9/8 3/13/8
f 1/2/8 3/13/8 4/14/8
- #是注释标记,就像C++中的//
- object是将一个obj模型分为多个模块,进行储存管理
- mtllib描述了模型所使用的材质文件所在的路径,材质文件里一般会有多个材质
- usemtl表示接下来的面f所构成的三维几何结构的材质属性使用该种材质
- v顶点
- vt代表顶点的纹理坐标
- vn代表顶点的法线
- f代表面
v vt vn都很好理解。f比较麻烦。例如f 8/11/7 7/12/7 6/10/7:
- 8/11/7描述了三角形的第一个顶点
- 7/12/7描述了三角形的第二个顶点
- 6/10/7描述了三角形的第三个顶点
- 对于第一个顶点,8指向要用的顶点。此例中是-1.000000 1.000000 -1.000000(索引从1开始,和C++中从0开始不同)
- 11指向要用的纹理坐标。此例中是0.748355 0.998230。
- 7指向要用的法线。此例中是0.000000 1.000000 -0.000000。
我们称这些数字为索引。若几个顶点共用同一个坐标,索引就显得很方便,文件中只需保存一个”v”,可以多次引用,节省了存储空间。
以下是原教程一个简易的obj载入函数,仅一个函数即可完成模型载入的关键步骤,不过读取的模型不包含材质文件,只有最基础的顶点位置参数,且读取文件时使用的是最基础的stdio.h标准输入输出流。
百度网盘链接:https://pan.baidu.com/s/15aQ3QbHtzzkt4zQXE6oF3g 密码:22el
2.2 mtl文件示例
这是一个简单的mtl材质文件:
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# 创建的文件:01.03.2017 19:24:15
newmtl 01___Default
Ns 58.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 1.0000 1.0000 1.0000
Kd 1.0000 1.0000 1.0000
Ks 0.1167 0.1167 0.1167
Ke 0.0000 0.0000 0.0000
map_Ka white.jpg
map_Kd white.jpg
newmtl 17___Default
Ns 1.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.5882 0.5882 0.5882
Kd 0.5882 0.5882 0.5882
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000
map_Ka Arch41_039_bark.jpg
map_Kd Arch41_039_bark.jpg
- newmtl代表一种材质,以下皆为该材质的属性参数
- Ns为Phong式光照模型中镜面光的高光反射系数
- Ka为Phong式光照模型中环境光的颜色反射系数
- Kd为Phong式光照模型中漫反射光的颜色反射系数
- Ks为Phong式光照模型中镜面光的颜色反射系数
- map_Ka为环境光所采样的纹理贴图路径,在.obj模型文件的根目录下
- map_Kd为漫反射光所采样的纹理贴图路径
- 其余参数感兴趣的大家自己查呗,反正我没用上
三,源代码解析
3.1 项目目录
![基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十五)obj模型加载_第7张图片](http://img.e-com-net.com/image/info8/2c17de10ed134c0a82e291150b229763.jpg)
相对于教程(八)的简单框架,我进行了进一步的精简
- camera.cpp是摄像机文件,使用WASDEQ按键控制摄像机的前进后退上升下降,鼠标左键拖拽进行视角的移动
- light.cpp是灯光,存储一个简单的6面,36个顶点的立方体
- main.cpp主函数调用主程序接口,与使用qss样式文件
- mainwindow.cpp打开主窗口,相应按键与按钮
- model.cpp模型文件类,读取指定路径下的obj模型文件
- oglmanager.cpp继承QOpenGLWidget类,作为附属于窗口类的widget类使用
- resourcemanager.cpp作为资源管理类,管理shader与texture纹理资源
- shader.cpp本质对象为QOpenGLShader,做了一些方便管理参数的成员函数
- texture2d.cpp本质对象为QOpenGLTexture,设置成员函数方便管理
3.2 模型读取函数解析
这里仅解释model.h与model.cpp这个类,其余.h与.cpp文件,之前教程有过解析。
model.h
#ifndef MODEL_H
#define MODEL_H
#include
#include
#include
#include
#include
#include
#include
#include
class Object;
class Material;
class Model
{
public:
Model();
bool init(const QString& path); //模型文件的初始化设置,将.obj文件的路径传入参数列表
void draw(GLboolean isOpenLighting = GL_FALSE);//绘制模型,参数列表为是否打开Phong式光照计算
private:
bool loadOBJ(const QString& path);//整个程序的最关键函数!!! 参数为obj模型所在的路径
void bindBufferData();
QOpenGLFunctions_3_3_Core *core;
QVector