如何在qt中执行opengl
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在qt中执行opengl相关的知识,希望对你有一定的参考价值。
qt可以通过QGLWidget运行opengl。QGLWidget继承QWidget,能够直接在里面调用opengl的接口。这个在qt文档里有具体说
明,也有相关例子,所以不赘述了。但是无法在正式软件里面执行,为什么?因为正式软件是用QGraphicsScene这个场景类操作和操作一切
item,而用QGraphicsView将其显示出来,而每一个item都是QGraphicsItem的子类。QGLWidget并不是QGraphicsItem类,我曾经尝试用普通的QWidget类那样,通过proxy来加进QGraphicsItem,但是没有成功。或许有方法,但是没有找到。
于是我放弃了用QGLWidget来操作opengl的打算,寻找直接在QGraphicsItem中操作opengl的方法。通过查看文档和示例代码,找到了这个方法:
1 往qt工程文件里添加opengl以及对应的lib。
2
对QGraphicsView进行一个三维对话框的指定,代码如下:
QGLWidget *widget = new
QGLWidget(QGLFormat(QGL::SampleBuffers));
widget->makeCurrent();
QGraphicsView
view;
view.setViewport(widget);
上述代码告诉了 QGraphicsView 类当前绘制的对象是支持opengl的。于是所有的场景中的item都将绘制到widget 上。
3
写一个QGraphicsItem的继承类,特别要重写paint函数。代码如下:
void XXX::paint(QPainter
*painter, const QStyleOptionGraphicsItem *option, QWidget
*widget)
painter->beginNativePainting();
glColor3f(0.5,1.0,0.2);
glBegin(GL_TRIANGLES);
glVertex3f(100.0,100.0,-100.0);
glVertex3f(150.0, 100.0,
-100.0);
glVertex3f(100.0, 150.0,
-100.0);
glEnd();
painter->endNativePainting();
上面这个函数主要是用opengl接口绘制了一个三角形。记住,在opengl绘制之前一定要执行painter->beginNativePainting()以及painter->endNativePainting()这两个语句。
QGraphicsScene、
QGraphicsView和QGraphicsItem的关系可以查阅相关文档,也不赘述了。
不过我按照这个方式画的三角形,怎么也在窗口上显示不出来,找了半天才发现问题在这个函数上QGraphicsItem::boundingRect()。这个函数是
干什么用的呢?主要用来返回该item的初始化大小,这个大小不会轻易改变,后续的改变都可以通过矩阵来完成,但是初始大小是不变的。QGraphicsView通过这个矩形来判断当前item是不是需要重绘,如果在重绘区外,则不调用重绘函数了。同时碰撞检测之类,也可以用这个矩形来判断。原来,item本身的矩阵外包框不对,所以才导致了重回不出来,改过来就正确了。
上面说的很潦草,具体怎么改的步骤就不说了。要想正确的绘制,必须得弄清楚坐标系的关系,QGraphicsScene、QGraphicsView以及QGraphicsItem这三个坐标系到底是什么关系。我看了文档,也自己进行了测试,但是感觉文档和测试的结果有些出入。具体出入不说了。说一下自己得心的吧。
先说明:涉及到一切大小和长度,都是像素大小,至少我测试的结果是这样的。
在建立QGraphicsScene
对象的时候,有一个构造函数是矩形,这个矩形是什么含义呢?经过测试,发现这个矩形并没有指定弹出窗口的位置,比如,我把矩形的左上角点指定为
-1000,-1000,显示的位置和1000,1000是一样的,而长度则正确指定了(当然,可能会有滚动条)。所以,这个矩形的左上角点并不是显示的
窗口的位置,而是它在逻辑上的左上角点。我们显示一切item,都是以这个逻辑上的坐标系为准来绘制的。比如,左上角点是-1000,-1000,而
item的位置在-500,-500,则这个-500,-500相当于在显示窗口的左上角往下各加500个像素的坐标的位置。
那么 QGraphicsItem的boundingRect是什么意思呢?返回的是什么大小?是以什么坐标系显示的大小?首先,这个大小肯定是以像素为单位的,其次,这个矩形的坐标是以QGraphicsScene的逻辑坐标为准的。当然这个大小是没有任何矩阵叠加的大小。有了矩阵叠加后,实际的矩形可能会发生变化。假如在boundingRect中指定矩形的左上角为100,100,那么最终体现的位置则是QGraphicsScene逻辑坐标100,100的位置,如果QGraphicsScene的左上角点已经指定为-1000,-1000,那么这个位置实际上就是离窗口左上角点1100,1100的位置(由于有滚动条,所以也不一定是这个长度。)
那么在QGraphicsItem的paint函数中进行了opengl绘制用的是什么坐标呢?其实用的也是QGraphicsScene
的逻辑坐标。如上面的例子,绘制的直角三角形直角顶点是0,0,那么显示的位置就是距离显示窗口左上角点1000,1000的位置。不过opengl的所
有绘制都是没有矩阵叠加的基础上,如果用矩阵叠加,则显示的位置肯定和指定的有区别了。比如,我用setPos强制指定一个位置,这个位置将和opengl绘图坐标相叠加,最后显示到窗口上。我推测setPos其实是改变了矩阵,是一个平移矩阵。 参考技术A 那么,在新版的 Qt5 中,OpenGL 模块究竟进行了哪些重大的更改,我们又应该如何在 Qt5 中使用 OpenGL呢?
工具/原料
Qt5
一、Qt5中OpenGL模块的重大更改
1
在 Qt5 中,新增了 QOpenGL* 类,用以取代之前的 QGL* 类。
注意,虽然我们仍然能通过 Qt5 中的 OpenGL 模块使用 QGL* 类,但强烈建议大家在新的 Qt 应用程序中使用 QOpenGL* 类而不是 QGL* 类。
如何在 Qt 表单类中调整 OpenGL 小部件的大小
【中文标题】如何在 Qt 表单类中调整 OpenGL 小部件的大小【英文标题】:How to resize an OpenGL widget inside a Qt form class 【发布时间】:2013-03-21 17:30:58 【问题描述】:我在 Qt 表单类 (MyForm
) 的 QVBoxLayout
(verticalLayout_2
) 中有一个 OpenGL 小部件 (myWidget
)。
当窗体调整大小后,我想调整 OpenGL 小部件的大小。
我应该在 changeEvent 方法中写什么,以将 QVBoxLayout
和 OpenGL 小部件调整为新大小?
MyForm::MyForm(QWidget *parent) :
QDialog(parent),
ui(new Ui::MyForm)
ui->setupUi(this);
myWidget = new GL_Widget;
ui->verticalLayout_2->addWidget( myWidget );
adjustSize();
void MyForm::changeEvent(QEvent *e)
// What should I write here?
【问题讨论】:
【参考方案1】:您不必编写任何代码来自动调整子窗口小部件的大小。 (另外,changeEvent()
无论如何都不是用于此目的的正确事件处理程序。)
您的问题可能与您使用 Qt Designer 创建的布局有关。您可能将垂直布局从侧边栏拖到表单小部件中,这实际上并没有创建***布局。很容易犯这个错误。
相反,请执行以下操作之一在 Qt Designer 中创建***布局:
右键单击对象检查器中的***(表单)小部件,然后从“布局”菜单中选择一种布局。
选择您的***小部件并单击工具栏中的布局图标之一:
如果您正确设置了布局,则无需添加任何代码。如果您在 Qt Designer 中预览表单,您的布局将自动更新。
【讨论】:
谢谢@jmk,我通过在Qt Designer中右键单击表单后选择“布局->在网格中布局”解决了这个问题。现在表单会自动调整大小而不使用 changeEvent 方法。以上是关于如何在qt中执行opengl的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL:如何在 Qt 中使用 glMapBuffer?