公有方法:
- 构造函数:
QOpenGLWidget(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()) - 析构函数:
~QOpenGLWidget() - 返回上下文:
QOpenGLContext * context() const - 返回帧缓存句柄:
GLuint defaultFramebufferObject() const - 释放上下文:
void doneCurrent() - 返回面格式:
QSurfaceFormat format() const - 返回帧缓存对象的32位位图对象:
QImage grabFramebuffer() - 窗口部件显示时返回false,初始化了未显示时返回true
bool isValid() const - 通过让相应的待渲染上下文为当前并绑定帧缓存到该上下文以预渲染
void makeCurrent() - 设置面格式为所选择的格式:
void setFormat(const QSurfaceFormat &format) - 设置部件的更新行为:
void setUpdateBehavior(UpdateBehavior updateBehavior) - 返回部件的更新行为:
UpdateBehavior updateBehavior() const
信号:
- 即将开始最上层构建信号:
void aboutToCompose() - 部件的窗口大小变化,帧缓存对象即将重新创建信号:
void aboutToResize() - 完成最顶层构建,即完成swapBuffers之后信号:
void frameSwapped() - 帧缓存因为部件大小变化重新创建之后信号:
void resized()
保护方法:
- 该虚函数会在PaintGL或者ResizeGL之前被调用一次:
(设置所需要的opengl资源和状态,不需要调用makecurrent因为在调用该函数前已经调过了,因为在这个阶段还不能访问帧缓存,所以不要在这里进行绘制操作)
virtual void initializeGL() - 该虚函数会在该部件任何需要绘制之前的时候被调用:
(不需要调用makecurrent因为在调用该函数前已经调过了,绘制上下文和帧缓存已经绑定,视口会被通过调用glViewport设定,而不会被设定为任何其他状态,该帧不执行任何清空和绘制操作.)
virtual void paintGL() - 该虚函数会在部件改变大小之后的时候被调用:
(新的宽高会通过w,h传入获取,不需要调用makecurrent因为在调用该函数前已经调过了,同样的帧缓存此时处于绑定状态)
virtual void resizeGL(int w, int h)
继承过来并属于保护的方法:
- 继承自QWidget::paintEvent()的保护方法,处理绘制事件:
(部件的update方法会发送绘制事件消息,这是个异步过程在调用update方法后的某一时间点,在进过一些准备过程之后,会调用到PaintGL方法更新帧缓存,然后部件顶层在下一个swapbuffer过程则会绘制这个更新后的帧缓存)
virtual void paintEvent(QPaintEvent *e) - 继承自QWidget::resizeEvent()的保护方法,处理大小变化事件:
(传入事件参数,避免在派生类里重写该方法,实在要重写,请保证QOpenGLWidget的实现被调用,以避免相关资源不随大小改变事件变化或者正确渲染)
virtual void resizeEvent(QResizeEvent *e)
详细说明
QOpenGLWidget类是用于渲染OpenGL图形的小部件。
QOpenGLWidget提供了将集成到Qt应用程序中的OpenGL图形显示的功能。
QOpenGLWidget提供了三个方便的虚拟函数:
paintGL() - 渲染OpenGL场景。每当需要更新窗口小部件时就会调用。
resizeGL() - 设置OpenGL视口,投影等。每当窗口小部件被调整大小时(包括第一次显示)会调用。
initializeGL() - 设置OpenGL资源和状态。在第一次调用大小调用GL()或paintGL()之前调用一次。
如果您需要触发paintGL()之外的其他地方的重绘(典型的例子是使用定时器来动画场景)时,您应该调用窗口小部件的update()函数来调度更新。
当调用paintGL(),resizeGL()或initializeGL())时,您的窗口小部件的OpenGL渲染上下文将变为最新。如果您需要从其他地方调用标准的OpenGL API函数(例如在您的窗口小部件的构造函数或自己的绘图函数中),则必须首先调用makeCurrent()。
所有渲染都发生在一个OpenGL帧缓冲区对象中。 makeCurrent()确保它在上下文中绑定。在创建和绑定paintGL()中的渲染代码中的其他帧缓冲区对象时,请记住这一点。不要重新绑定ID为0的帧缓冲区。而是调用defaultFramebufferObject()来获取应绑定的ID。
QOpenGLWidget允许在平台支持时使用不同的OpenGL版本和配置文件。只需通过setFormat()设置所请求的格式。但是请记住,在同一个窗口中有多个QOpenGLWidget实例要求它们都使用相同的格式,或至少不会使上下文不可共享的格式。为了克服这个问题,更喜欢使用QSurfaceFormat :: setDefaultFormat()而不是setFormat()。
注意:在构建QApplication实例之前,在请求OpenGL核心配置文件上下文时,在某些平台(例如OS X)上调用QSurfaceFormat :: setDefaultFormat()是必需的。这是为了确保上下文之间的资源共享保持功能,因为使用正确的版本和配置文件创建所有内部上下文。
资源初始化和清空:
- 不要尝试在创建OpenGL资源在initializeGL()被调用之前(例如在子类构造里编译shader或者初始化顶点缓存或者上传纹理数据都是不行的,因为这些操作必须至少等到initializeGL()函数中调用);
- 释放资源同样要设置上下文到当前
class MyGLWidget : public QOpenGLWidget
{
...
private:
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo;
QOpenGLShaderProgram *m_program;
QOpenGLShader *m_shader;
QOpenGLTexture *m_texture;
};
MyGLWidget::MyGLWidget()
: m_program(0), m_shader(0), m_texture(0)
{
// No OpenGL resource initialization is done here.
}
MyGLWidget::~MyGLWidget()
{
// Make sure the context is current and then explicitly
// destroy all underlying OpenGL resources.
makeCurrent();
delete m_texture;
delete m_shader;
delete m_program;
m_vbo.destroy();
m_vao.destroy();
doneCurrent();
}
void MyGLWidget::initializeGL()
{
m_vao.create();
if (m_vao.isCreated())
m_vao.bind();
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(...);
m_texture = new QOpenGLTexture(QImage(...));
m_shader = new QOpenGLShader(...);
m_program = new QOpenGLShaderProgram(...);
...
}
or
void MyGLWidget::initializeGL()
{
// context() and QOpenGLContext::currentContext() are equivalent when called from initializeGL or paintGL.
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup);
}
void MyGLWidget::cleanup()
{
makeCurrent();
delete m_texture;
m_texture = 0;
...
doneCurrent();
}
例程:
class MyGLWidget : public QOpenGLWidget
{
public:
MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { }
protected:
void initializeGL()
{
// Set up the rendering context, load shaders and other resources, etc.:
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
...
}
void resizeGL(int w, int h)
{
// Update projection matrix and other size related settings:
m_projection.setToIdentity();
m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f);
...
}
void paintGL()
{
// Draw the scene:
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClear(GL_COLOR_BUFFER_BIT);
...
}
};
可以通过继承自QOpenGLFunctions避免每次调用的f->前缀
class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
...
void initializeGL()
{
initializeOpenGLFunctions();
glClearColor(...);
...
}
...
};
为了适配opengl版本和请求深度和模版缓存:
QOpenGLWidget *widget = new QOpenGLWidget(parent);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
widget->setFormat(format); // must be called before the widget or its parent window gets shown