简短的回答:QOpenGLWidget 中的 Open GL 绘图应该在 QOpenGLWidget::paintGL() 中进行。
当调用 OpenGL 命令时,先决条件是相应的。之前已经激活了 OpenGL 上下文。这是QOpenGLWidget::paintGL() 确保的:
无需调用makeCurrent(),因为调用此函数时已完成。
在调用这个函数之前,上下文和帧缓冲区是绑定的,并且视口是通过调用 glViewport() 来设置的。
顺便说一句。另一个先决条件是相应的。 OpenGL 上下文已经创建完毕。
为了了解更多关于这方面的信息,我进行了更深入的挖掘——QOpenGLWidget::paintEvent()(在 woboq.org 上):
void QOpenGLWidget::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e);
Q_D(QOpenGLWidget);
if (!d->initialized)
return;
if (updatesEnabled())
d->render();
}
只要尚未完成初始化,paint 事件就不会执行任何操作。 (我没有深入挖掘,但我确信初始化涉及调用QOpenGLWidget::initializeGL()。)
绘制事件请求渲染。
用眼睛跟踪代码(严格来说:鼠标点击),d->render() 调用 QOpenGLWidgetPrivate::render() 最终调用 QOpenGLWidgetPrivate::invokeUserPaint(),我们在这里:
void QOpenGLWidgetPrivate::invokeUserPaint()
{
Q_Q(QOpenGLWidget);
QOpenGLContext *ctx = QOpenGLContext::currentContext();
Q_ASSERT(ctx && fbo);
QOpenGLFunctions *f = ctx->functions();
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbo->handle();
f->glViewport(0, 0, q->width() * q->devicePixelRatioF(), q->height() * q->devicePixelRatioF());
inPaintGL = true;
// vvvvvvvvvvvv
q->paintGL();
// ^^^^^^^^^^^^
inPaintGL = false;
flushPending = true;
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = 0;
}
(这些cmets是我的。)
所以,如果QOpenGLWidget::paintEvent() 被重载,那么它应该调用基类的paintEvent()。 (否则,OpenGL 渲染肯定会中断。)
最后,当我改变几何图形时,如何强制重新渲染图形?我应该调用什么方法?
这实际上在QOpenGLWidget的描述中得到了回答:
如果您需要从paintGL() 以外的地方触发重绘(典型示例是使用计时器为场景设置动画时),您应该调用小部件的update() 函数来安排更新。
以防万一,我误解了OP的意图,实际的问题是在QOpenGLWidget中放置QPainter绘图 - 我曾经写过一个关于混合OpenGL命令和QPainter绘图在@中的SO: Paint a rect on qglwidget at specifit times的答案987654344@.