You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:39:43