QGLViewer是在原生OpenGL的基础上做了一层封装,支持显示和交互,而且与QT完美融合,可扩展性好。不足之处是这个库只封装了OpenGL1,其显示速度有待提高。本人在开发环境搭建过程中也踩了不少坑,特此记录,供日后查阅。
准备工作:下载并解压libQGLViewer.zip
下载地址:http://libqglviewer.com/installWindows.html
一、libGLViewer-2.7.2编译
(1)VS2017+Qt5平台编译
VS ——> Qt VS Tools ——> Open Qt Project File(.pro)——>打开libQGLViewer-2.7.2.pro文件
(2)编译QGLViewer
选择编译生成Debug或者Release版本的库,我选择了在Release模式下编译(注:Release版本和Debug版本的库不能混用!!!)。
右击QGLViewer——>仅用于项目(J)——>仅生成QGLViewer(B)
如下图所示,当输出目录下生成动态库QGLViewer.dll和静态库QGLViewer.lib时即为编译成功。
(3)示例代码编译
example文件夹下都是官方给出示例代码,感兴趣的HXD可以编译后跑一把看看效果,我这里就编译运行一下“simpleViewer项目”。
右击simpleViewer项目——>仅用于项目——>仅生成simpleViewer(B)
如下图所示,显示出了一个像老8蜜汁小憨包一样东西,说明QGLViewer库配置成功!
(4)qglviewerplugin插件的编译和安装
但是上面仅仅是在独立的控制台中利用OpenGL窗口显示了图形,在实际开发过程中实用性并不高。QGLViewer是支持把显示窗口嵌入到QT的QWidget中去使用的,为达到上述效果必须编译安装qglviewerplugin插件。
1)插件编译
右击qglviewerplugin项目——>仅用于项目——>仅生成qglviewerplugin(B)
发生如下错误:qglviewerplugin项目本身编译没问题但是会链接失败,提示无法解析的外部符号。
qglviewerPlugin.obj : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) public: __cdecl Viewer::Viewer(class QWidget *)" (__imp_??0Viewer@@QEAA@PEAVQWidget@@@Z),该符号在函数 "public: virtual class QWidget * __cdecl QGLViewerPlugin::createWidget(class QWidget *)" (?createWidget@QGLViewerPlugin@@UEAAPEAVQWidget@@PEAV2@@Z) 中被引用
qglviewerPlugin.obj : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) public: virtual __cdecl Viewer::~Viewer(void)" (__imp_??1Viewer@@UEAA@XZ),该符号在函数 "public: virtual void * __cdecl Viewer::`scalar deleting destructor'(unsigned int)" (??_GViewer@@UEAAPEAXI@Z) 中被引用
qglviewerPlugin.obj : error LNK2001: 无法解析的外部符号 "public: virtual void __cdecl Viewer::draw(void)" (?draw@Viewer@@UEAAXXZ)
解决方法:去源码里面找到这个Viewer类,把Viewer类的“类前宏定义修饰符QDESIGNER_WIDGET_EXPORT”删除掉,再次编译生成即可!
2)插件安装
将QGLViewer2.dll文件复制到:C:\Windows\System32或者C:\Windows\SysWOW64路径下。
将qglviewerplugin.dll复制到:Qt5安装目录\plugins\designer(在我计算机上路径:C:\OSGeo4W64\apps\Qt5\plugins\designer\)
3)效果
打开QT Designer,左侧控件栏中会出现QGLViewer控件,拖拽到窗体中即可使用。
(5)库文件提取
其实操作到这里为止,QGLViewer库和控件都已经编译完毕了!但为了今后方便使用,需要新建一个include和lib文件夹,然后把所有h文件统一放到include目录下,把dll文件、lib文件统一放到lib目录下。
如下图所示,在include目录下新建QGLViewer目录和VRender目录,分别把各自头文件扔进去。
再把QGLViewer.dll、QGLViewer.lib和qglviewerplugin.dll、qglviewerplugin.lib文件扔到lib目录下:
二、VS工程项目配置
(1)在VS2017中新建一个带窗口的QT项目,切换到Release模式。
(2)包含目录:
Qt5安装目录\include\QTOpenGL (我的路径:C:\OSGeo4W64\apps\Qt5\include\QtOpenGL)
Qt5安装目录\include\QtXml (我的路径:C:\OSGeo4W64\apps\Qt5\include\QtXml)
include文件夹目录 (我的路径:D:\libQGLViewer-2.7.2\include)
(2)库目录:
lib文件夹目录(我的路径:D:\libQGLViewer-2.7.2\lib)
OpenGL32.Lib文件目录(我的路径:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x64)
(3)连接器——>输入——>附加依赖项:
QGLViewer2.lib
OpenGL32.Lib
三、代码实现
(1)新建一个QViewer类继承自QGLViewer类,重写相关虚函数。
(2)在Qt Designer中不能直接把QGLViewer控件拖拽到界面上去使用,而是借助于QT自带的QWidget控件,利用代码将OpenGL窗口嵌入到QWidget上来显示图形。
QViewer.h
#include "QGLViewer\qglviewer.h"
class QViewer : public QGLViewer
{
Q_OBJECT
public:
QViewer();
~QViewer();
protected:
// 重写虚函数draw()和init()
virtual void draw();
virtual void init();
private:
// 自定义绘图函数(绘制一坨老8蜜汁小憨堡)
void drawShit();
};
QViewer.cpp
#include "QViewer.h"
QViewer::QViewer()
{
}
QViewer::~QViewer()
{
}
void QViewer::draw()
{
// 必须在虚函数draw()内部调用自定义的绘图函数才能成功显示图形!!!
drawShit();
}
void QViewer::init()
{
}
void QViewer::drawShit()
{
const float nbSteps = 200.0;
glBegin(GL_QUAD_STRIP);
for (int i = 0; i < nbSteps; ++i)
{
const float ratio = i / nbSteps;
const float angle = 21.0 * ratio;
const float c = cos(angle);
const float s = sin(angle);
const float r1 = 1.0 - 0.8f * ratio;
const float r2 = 0.8f - 0.8f * ratio;
const float alt = ratio - 0.5f;
const float nor = 0.5f;
const float up = sqrt(1.0 - nor * nor);
glColor3f(1.0 - ratio, 0.2f, ratio);
glNormal3f(nor * c, up, nor * s);
glVertex3f(r1 * c, alt, r1 * s);
glVertex3f(r2 * c, alt + 0.05f, r2 * s);
}
glEnd();
}
glWidget.cpp
#include "glWidget.h"
#include "QViewer.h"
#include "qgridlayout.h"
glWidget::glWidget(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
// 关键代码:将OpenGL窗口嵌入到UI上去,自动调用QViewer类的虚函数draw()。
QViewer* xjm = new QViewer();
QGridLayout *GridGLLayout = new QGridLayout(this);
GridGLLayout->addWidget(xjm);
ui.widget->setLayout(GridGLLayout);
}
最终可以实现下图中的效果: