将OSG嵌入QGraphicsView后QGraphicsScene元素无法显示的问题
解决OSG嵌入QGraphicsView后QGraphicsScene元素无法显示的问题
我之前也碰到过类似的坑,你的问题核心在于OSG的渲染流程和QGraphicsView的绘制机制冲突了——当你在drawBackground里调用viewer_->frame()时,OSG会完全接管OpenGL上下文,默认会清除整个帧缓冲区,还可能破坏QPainter后续绘制需要的OpenGL状态,导致QGraphicsScene里的其他元素(比如你的QWidget对应的items)无法被正确渲染。
下面给你两个可行的解决方案,推荐第一个,更贴合QGraphics框架的设计:
方案一:用自定义QGraphicsItem承载OSG渲染
把OSG的渲染限制在一个独立的QGraphicsItem中,这样它只会在自己的区域内绘制,不会干扰整个Scene的其他元素。
自定义OSG Graphics Item代码
#include <QGraphicsItem> #include <osgViewer/Viewer> #include <osg/Camera> class OsgGraphicsItem : public QGraphicsItem { public: OsgGraphicsItem(osgViewer::Viewer* viewer, QGraphicsItem* parent = nullptr) : QGraphicsItem(parent), viewer_(viewer) { // 配置OSG相机,确保和QPainter兼容 viewer_->getCamera()->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); viewer_->getCamera()->setRenderOrder(osg::Camera::PRE_RENDER); viewer_->getCamera()->setAllowEventFocus(false); // 禁用OSG的自动窗口调整,由item控制视口 viewer_->setThreadingModel(osgViewer::Viewer::SingleThreaded); } // 定义item的边界,根据你的需求调整大小 QRectF boundingRect() const override { return QRectF(0, 0, this->scene()->width(), this->scene()->height()); } void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override { if (painter->paintEngine()->type() != QPaintEngine::OpenGL2) { qWarning("OSG requires OpenGL2 paint engine!"); return; } painter->save(); painter->beginNativePainting(); // 调整OSG视口匹配当前item的显示区域(处理QGraphics和OSG的Y轴方向差异) QRectF itemRect = boundingRect(); osg::Viewport* viewport = viewer_->getCamera()->getViewport(); if (viewport) { int osgY = static_cast<int>(this->scene()->height() - itemRect.y() - itemRect.height()); viewport->setViewport(static_cast<int>(itemRect.x()), osgY, static_cast<int>(itemRect.width()), static_cast<int>(itemRect.height())); } viewer_->frame(); painter->endNativePainting(); painter->restore(); } private: osgViewer::Viewer* viewer_; };
使用方式
把这个item添加到你的QGraphicsScene中,代替修改QGraphicsView的drawBackground:
// 初始化OSG viewer和场景数据(你的原有代码) osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer(); // ... 添加你的OSG场景节点 ... // 创建item并加入scene OsgGraphicsItem* osgItem = new OsgGraphicsItem(viewer.get()); yourGraphicsScene->addItem(osgItem); // 把scene设置到QGraphicsView yourGraphicsView->setScene(yourGraphicsScene);
方案二:修复drawBackground的渲染冲突(不推荐)
如果你一定要在drawBackground里做OSG渲染,需要调整OSG的缓冲区设置,确保它不会清除QGraphicsScene的绘制结果,同时恢复OpenGL状态:
void OsgQGraphicsView::drawBackground(QPainter *painter, const QRectF &rect) { // 先绘制QGraphicsScene的原始背景 QGraphicsView::drawBackground(painter, rect); if(painter->paintEngine()->type() != QPaintEngine::OpenGL2) { qWarning("OSG requires OpenGL2 paint engine!"); return; } painter->save(); painter->beginNativePainting(); // 关键:禁止OSG清除颜色缓冲区,只清除深度缓冲区(避免遮挡) viewer_->getCamera()->setClearMask(GL_DEPTH_BUFFER_BIT); // 调整OSG视口匹配当前View的视口 QRect viewRect = this->viewport()->rect(); osg::Viewport* viewport = viewer_->getCamera()->getViewport(); if (viewport) { viewport->setViewport(viewRect.x(), viewRect.y(), viewRect.width(), viewRect.height()); } viewer_->frame(); painter->endNativePainting(); painter->restore(); }
注意点
这个方案虽然能解决问题,但OSG会覆盖整个背景区域,而且如果后续QGraphicsScene有元素需要在OSG下面绘制,会变得很难控制,所以更推荐方案一。
内容的提问来源于stack exchange,提问作者Shengwei Zhang
相关产品推荐
相关产品推荐

