如何在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的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Qt 表单类中调整 OpenGL 小部件的大小

OpenGL:如何在 Qt 中使用 glMapBuffer?

QT和OpenGL如何正确集成并显示纹理

如何在带有 Qt 的 OpenGL 中使用顶点缓冲区对象绘制矩形?

如何在Qt中配置OpenGL

Qt OpenGL-如何根据鼠标点击获取对象