如何在Qt6的QOpenGLWidget/QQuickFramebufferObject中渲染OpenCascade?
Qt6下OpenCASCADE渲染集成QQuickFramebufferObject的适配问题
我之前在旧版Qt中通过QGLWidget实现了OpenCASCADE渲染,升级到Qt6后遇到瓶颈,同时希望将其集成到QQuickFramebufferObject与QtQuick2环境中。尝试了三种方案均存在问题:
- 方案1:通过QWidget句柄创建WNT_Window,设置
Qt::WA_PaintOnScreen时程序可运行但产生大量警告;移除该属性后画面严重闪烁。 - 方案2:基于QWidget句柄和当前GL上下文创建Aspect_NeutralWindow,无法显示OpenCASCADE渲染内容。
- 方案3:参考官方文档使用GL上下文构建OpenCASCADE环境,同样无法显示渲染内容。
完整示例代码
CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project(VisiTouchPSL LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) find_package(OpenCASCADE REQUIRED) set(EXEC_NAME TestOcctQt6) # Find Qt packages find_package(Qt6 COMPONENTS Widgets OpenGLWidgets REQUIRED) # Add your source and headers files here set(HEADERS occView.h ) set(SOURCES occView.cpp main.cpp ) # Create executable add_executable(${EXEC_NAME} ${HEADERS} ${SOURCES}) # Link Qt libraries target_link_libraries(${EXEC_NAME} PRIVATE Qt6::Widgets Qt6::OpenGLWidgets ${OpenCASCADE_LIBRARIES}) # Include OpenCASCADE headers target_include_directories(${EXEC_NAME} PRIVATE ${OpenCASCADE_INCLUDE_DIRS})
main.cpp
// Author ADRIAN MAIRE // MIT license #include "occView.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); OcctViewer w; w.resize(800, 600); w.show(); return a.exec(); }
occView.h
// Author ADRIAN MAIRE // MIT license #ifndef OCCTVIEWER_H #define OCCTVIEWER_H #include <memory> #include <QOpenGLWidget> #include <AIS_InteractiveContext.hxx> #include <Standard_Handle.hxx> //! Adapted a QWidget for OpenCASCADE viewer. class OcctViewer : public QOpenGLWidget { Q_OBJECT // Pimpl to not expose OCCL stuff used internally struct Internal; public: explicit OcctViewer(QWidget* parent=nullptr); ~OcctViewer() override; // Provide access to OCCT context, for building the scene const Handle(AIS_InteractiveContext)& getContext() const; protected: void initializeGL() override; void paintGL() override; void resizeGL(int w, int h) override; // Some default content for this example. void makeTorus(); std::unique_ptr<Internal> m_internal; public slots: void rotateScene(); }; #endif
occView.cpp
// Author ADRIAN MAIRE // MIT license #include "occView.h" #include <QOpenGLContext> #include <QTimer> #include <OpenGl_GraphicDriver.hxx> #include <V3d_View.hxx> #include <Aspect_Handle.hxx> #include <Aspect_NeutralWindow.hxx> #include <Aspect_DisplayConnection.hxx> #include <OpenGl_FrameBuffer.hxx> #include <OpenGl_Context.hxx> #include <WNT_Window.hxx> #include <BRepPrimAPI_MakeTorus.hxx> #include <AIS_Shape.hxx> #include <OpenGl_GraphicDriver.hxx> #include <QOpenGLFunctions> struct OcctViewer::Internal { Handle(V3d_Viewer) m_viewer; Handle(V3d_View) m_view; Handle(AIS_InteractiveContext) m_context; //For texting/example Handle(AIS_Shape) m_torusShape; double m_rotationAngle = 0.0; QTimer timer; }; OcctViewer::OcctViewer(QWidget* parent ) : QOpenGLWidget(parent) , m_internal(std::make_unique<Internal>()) { setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_NoSystemBackground); // Avoid many QPainter prints/errors setAutoFillBackground(false); setUpdateBehavior(QOpenGLWidget::NoPartialUpdate); // Setup the rotation of the scene connect(&m_internal->timer, &QTimer::timeout, this, &OcctViewer::rotateScene); m_internal->timer.setInterval(500); m_internal->timer.start(); } OcctViewer::~OcctViewer() = default; void OcctViewer::initializeGL() { QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); //ATTEMPT 3 /*// Create OpenGL graphic driver Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection(); Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(displayConnection); Handle(OpenGl_Context) oglContext = new OpenGl_Context(); oglContext->Init(QOpenGLContext::currentContext()); //Initialize from currently bound OpenGL context Handle(OpenGl_FrameBuffer) fbo = new OpenGl_FrameBuffer(); fbo->InitWrapper(oglContext); oglContext->SetDefaultFrameBuffer(fbo); // OCC Viewer m_internal->m_viewer = new V3d_Viewer(graphicDriver); // OCC View m_internal->m_view = m_internal->m_viewer->CreateView(); m_internal->m_view->SetImmediateUpdate(false); graphicDriver->ChangeOptions().buffersNoSwap = false;*/ // ATTEMPT 2 /* // Create OpenGL graphic driver Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection(); Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(displayConnection); // OCC Viewer m_internal->m_viewer = new V3d_Viewer(graphicDriver); // OCC View m_internal->m_view = m_internal->m_viewer->CreateView(); // Aspect rendering context should use the OpenGL context of QOpenGLWidget Aspect_RenderingContext renderContext = (Aspect_RenderingContext)QOpenGLContext::currentContext()->handle(); Handle(Aspect_Window) wind = new Aspect_NeutralWindow(); m_internal->m_view->SetWindow(wind, renderContext); if (!wind->IsMapped()) wind->Map();*/ //ATTEMPT 1 // Create OpenGL graphic driver /*Handle(Aspect_DisplayConnection) displayConnection = new Aspect_DisplayConnection(); Handle(OpenGl_GraphicDriver) graphicDriver = new OpenGl_GraphicDriver(displayConnection); // OCC Viewer m_internal->m_viewer = new V3d_Viewer(graphicDriver); // OCC View m_internal->m_view = m_internal->m_viewer->CreateView(); // Make this QOpenGLWindow to be the surface for the view WId windowHandle = (WId)winId(); Handle(Aspect_Window) wind; #ifdef _WIN32 wind = new WNT_Window((Aspect_Handle)windowHandle); #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX) wind = new Cocoa_Window((NSView *)windowHandle); #else wind = new Xw_Window(aDisplayConnection, (Window)windowHandle); #endif m_internal->m_view->SetWindow(wind); if (!wind->IsMapped()) wind->Map();*/ // OCC Context m_internal->m_context = new AIS_InteractiveContext(m_internal->m_viewer); // Setup the scene m_internal->m_viewer->SetDefaultLights(); m_internal->m_viewer->SetLightOn(); m_internal->m_context->SetDisplayMode(AIS_Shaded, Standard_True); // Setup the rendering m_internal->m_view->SetBackgroundColor(Quantity_NOC_WHITE); m_internal->m_view->MustBeResized(); m_internal->m_view->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_ZBUFFER); // Create initial content (for the example) makeTorus(); } const Handle(AIS_InteractiveContext)& OcctViewer::getContext() const { return m_internal->m_context; } void OcctViewer::paintGL() { if (QOpenGLContext::currentContext() != context()) // avoid QPaint errors. { makeCurrent(); } static bool color = true; color = ! color; QOpenGLFunctions *f = context()->functions(); f->glClearColor(0.0f, color?1.0f:0.5f, 0.0f, 0.1f); if (!m_internal->m_view.IsNull()) { m_internal->m_view->Redraw(); } } void OcctViewer::resizeGL( int w, int h ) { if( !m_internal->m_view.IsNull() ) { m_internal->m_view->MustBeResized(); } } void OcctViewer::makeTorus() { // Create a Torus gp_Ax2 axis; axis.SetLocation(gp_Pnt(0.0, 0.0, 0.0)); TopoDS_Shape torus = BRepPrimAPI_MakeTorus(axis, 90.0, 30.0).Shape(); m_internal->m_torusShape = new AIS_Shape(torus); m_internal->m_torusShape->SetColor(Quantity_NOC_BLUE); m_internal->m_context->Display(m_internal->m_torusShape, Standard_True); // Align the view to fit the full window with the torus m_internal->m_view->FitAll(); m_internal->m_view->ZFitAll(); } void OcctViewer::rotateScene() { if (m_internal->m_torusShape.IsNull()) { return; } m_internal->m_rotationAngle += 0.01; // Adjust this value to change rotation speed if (m_internal->m_rotationAngle >= 2 * M_PI) { m_internal->m_rotationAngle -= 2 * M_PI; } gp_Trsf rotation; rotation.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), m_internal->m_rotationAngle); m_internal->m_context->SetLocation(m_internal->m_torusShape, rotation); // Request a redraw update(); }
内容的提问来源于stack exchange,提问作者Adrian Maire
相关产品推荐
相关产品推荐

