Horde3D http://horde3d.org/forums/ |
|
Qt 5.1 (Qt Quick 2.1) & Horde3D http://horde3d.org/forums/viewtopic.php?f=1&t=1895 |
Page 1 of 1 |
Author: | Zuck [ 08.08.2013, 04:14 ] |
Post subject: | Qt 5.1 (Qt Quick 2.1) & Horde3D |
Hi guys, I'm trying to integrate Horde3D (from horde3d-x branch) inside the new Qt Quick 2(.1) system of Qt 5(.1). This is the current code: view3d.h Code: #ifndef VIEW3D_H #define VIEW3D_H #include <QQuickItem> #include <QDateTime> #include <Horde3D.h> class View3D : public QQuickItem { Q_OBJECT protected: H3DRes m_pipeline; H3DNode m_cam; public: View3D( QQuickItem* parent = 0 ); virtual ~View3D(); private slots: void onPaint(); void onRendered(); void onWindowChanged(QQuickWindow* win); signals: void rendered(); }; #endif // VIEW3D_H view3d.cpp Code: #include "view3d.h" #include <QQuickWindow> #include <Horde3DUtils.h> View3D::View3D(QQuickItem* parent) : QQuickItem(parent), m_cam(0) { this->setObjectName("View3D"); QObject::connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(onWindowChanged(QQuickWindow*))); QObject::connect(this, SIGNAL(rendered()), this, SLOT(onRendered()), Qt::DirectConnection); } View3D::~View3D() { h3dRelease(); } void View3D::onPaint() { // Initialize engine. h3dInit(); if (!m_cam) { // Add a pipeline resource. m_pipeline = h3dAddResource(H3DResTypes::Pipeline, "pipelines/forward.pipeline.xml", 0); // Add a model. H3DRes modelRes = h3dAddResource(H3DResTypes::SceneGraph, "models/knight/knight.scene.xml", 0); H3DNode model = h3dAddNodes(H3DRootNode, modelRes); // Add a light source. H3DNode light = h3dAddLightNode(H3DRootNode, "Light1", 0, "LIGHTING", "SHADOWMAP"); h3dSetNodeTransform(light, 0, 20, 0, 0, 0, 0, 1, 1, 1); h3dSetNodeParamF(light, H3DLight::RadiusF, 0, 50.0f); // Add a camera m_cam = h3dAddCameraNode(H3DRootNode, "Camera", m_pipeline); // Load added resources. h3dutLoadResourcesFromDisk(""); } int x = this->x(); int y = this->y(); int width = this->width(); int height = this->height(); // Setup viewport and render target sizes h3dSetNodeParamI(m_cam, H3DCamera::ViewportXI, x); h3dSetNodeParamI(m_cam, H3DCamera::ViewportYI, y); h3dSetNodeParamI(m_cam, H3DCamera::ViewportWidthI, width); h3dSetNodeParamI(m_cam, H3DCamera::ViewportHeightI, height); h3dSetupCameraView(m_cam, 45.0f, (float)width / height, 0.5f, 2048.0f); h3dResizePipelineBuffers(m_pipeline, width, height); // Render scene h3dRender(m_cam); // Finish rendering of frame h3dFinalizeFrame(); emit rendered(); } void View3D::onRendered() { this->window()->update(); } void View3D::onWindowChanged(QQuickWindow* win) { if (win) { QObject::connect(win, SIGNAL(beforeRendering()), this, SLOT(onPaint()), Qt::DirectConnection); win->setClearBeforeRendering(false); } } main.cpp Code: #include "view3d.h" #include <QQmlApplicationEngine> #include <QQmlContext> #include <QQuickWindow> #include <QApplication> int main(int argc, char** argv) { QApplication app(argc, argv); app.setApplicationName(QObject::tr("Qt5 + Horde3D-x")); qmlRegisterType<View3D>("View3D", 1, 0, "View3D"); QQmlApplicationEngine engine(QUrl("main.qml")); QObject* topLevel = engine.rootObjects().value(0); QQuickWindow* win = qobject_cast<QQuickWindow*>(topLevel); if (!win) { qWarning("Error: not a valid window."); return -1; } win->showMaximized(); return app.exec(); } main.qml Code: import QtQuick 2.1 import QtQuick.Controls 1.0 import View3D 1.0 ApplicationWindow { id: main menuBar: MenuBar { Menu { title: qsTr("&File") MenuItem { text: qsTr("&New Project") shortcut: "Ctrl+N" } } } View3D { id: centralArea anchors.fill: parent } Rectangle { width: 200 height: 200 color: "#ffffff" } } The problem is that after h3dInit call, something goes wrong with the OpenGL context and the ApplicationWindow is rendered all black (also the menubar becomes black) and Horde3D doesn't render anything. The front Rectangle element, instead, is rendered correctly. Any hints? Thanks, Emanuele |
Author: | attila [ 09.08.2013, 12:50 ] |
Post subject: | Re: Qt 5.1 (Qt Quick 2.1) & Horde3D |
I haven't used Qt for years, so probably I am not the best person to help. What i would try: - You should call h3dInit only once / not per frame (before any other h3d call) - In order to successfully initialize the engine the calling application must provide a valid OpenGL context. this could be done using h3dut on windows or using qt for creating the context, I found this: http://qt-project.org/forums/viewthread/4109 maybe you should subclass QGLWidget. Hope it helps |
Author: | Zuck [ 15.08.2013, 07:13 ] |
Post subject: | Re: Qt 5.1 (Qt Quick 2.1) & Horde3D |
Hi attila, thanks for your reply. BTW the approach you suggested is valid for Qt4 (is still valid for Qt5, but only if you want to use widgets), but my purpose is to integrate Horde3D inside the new QtQuick (2.1) framework which is OpenGL-based (so the OGL context is already there). |
Author: | Zuck [ 17.08.2013, 00:41 ] |
Post subject: | Re: Qt 5.1 (Qt Quick 2.1) & Horde3D |
Here it is a first working prototype It's not perfect and has many limitations, but it's a starting point to reach something more cool! Feel free to use it: view3d.h Code: #ifndef VIEW3D_H #define VIEW3D_H #include <QQuickItem> #include <QOpenGLFramebufferObject> #include <Horde3D.h> class View3D : public QQuickItem { Q_OBJECT private: int m_timerID; QOpenGLFramebufferObject* m_fbo; H3DNode m_cam; public: View3D( QQuickItem* parent = 0 ); virtual ~View3D(); protected: void timerEvent(QTimerEvent* evt); private slots: void paint(); void cleanup(); void handleWindowChanged(QQuickWindow* win); }; #endif // VIEW3D_H view3d.cpp Code: #include "view3d.h"
#include <QQuickWindow> #include <QOpenGLContext> #include <QOpenGLFunctions> #include <Horde3DUtils.h> View3D::View3D(QQuickItem* parent) : QQuickItem(parent), m_timerID(0), m_fbo(0), m_cam(0) { this->setFlag(QQuickItem::ItemHasContents); QObject::connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*))); } View3D::~View3D() { this->cleanup(); } void View3D::timerEvent(QTimerEvent* evt) { if (evt && evt->timerId() == m_timerID) this->window()->update(); } void View3D::paint() { // Save (push) Qt state. glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // Clear back surface. glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); // Render Horde3D. int x = this->x(); int y = this->y(); int width = this->width(); int height = this->height(); delete m_fbo; m_fbo = 0; if (width && height) m_fbo = new QOpenGLFramebufferObject(width, height); if (m_fbo) { QOpenGLFunctions glFunctions(QOpenGLContext::currentContext()); glFunctions.glUseProgram(0); m_fbo->bind(); if (!m_cam) { // Initialize engine. h3dInit(); h3dSetOption(H3DOptions::LoadTextures, 1); h3dSetOption(H3DOptions::TexCompression, 0); h3dSetOption(H3DOptions::FastAnimation, 0); h3dSetOption(H3DOptions::MaxAnisotropy, 4); h3dSetOption(H3DOptions::ShadowMapSize, 2048); // Add resources. H3DRes pipelineRes = h3dAddResource(H3DResTypes::Pipeline, "pipelines/forward.pipeline.xml", 0); H3DRes modelRes = h3dAddResource(H3DResTypes::SceneGraph, "models/platform/platform.scene.xml", 0); // Load added resources. h3dutLoadResourcesFromDisk("data/"); // Add an environment. H3DNode model = h3dAddNodes(H3DRootNode, modelRes); h3dSetNodeTransform(model, 0, -20, 0, 0, 0, 0, 20, 20, 20 ); // Add a light source. H3DNode light = h3dAddLightNode( H3DRootNode, "Light1", 0, "LIGHTING", "SHADOWMAP" ); h3dSetNodeTransform( light, 0, 15, 10, -60, 0, 0, 1, 1, 1 ); h3dSetNodeParamF( light, H3DLight::RadiusF, 0, 30 ); h3dSetNodeParamF( light, H3DLight::FovF, 0, 90 ); h3dSetNodeParamI( light, H3DLight::ShadowMapCountI, 1 ); h3dSetNodeParamF( light, H3DLight::ShadowMapBiasF, 0, 0.01f ); h3dSetNodeParamF( light, H3DLight::ColorF3, 0, 1.0f ); h3dSetNodeParamF( light, H3DLight::ColorF3, 1, 0.8f ); h3dSetNodeParamF( light, H3DLight::ColorF3, 2, 0.7f ); h3dSetNodeParamF( light, H3DLight::ColorMultiplierF, 0, 1.0f ); // Add a camera. m_cam = h3dAddCameraNode(H3DRootNode, "Camera", pipelineRes); QObject::connect(QOpenGLContext::currentContext(), SIGNAL(aboutToBeDestroyed()), this, SLOT(cleanup()), Qt::DirectConnection); } // Setup viewport and render target sizes. h3dSetNodeParamI(m_cam, H3DCamera::ViewportXI, 0); h3dSetNodeParamI(m_cam, H3DCamera::ViewportYI, 0); h3dSetNodeParamI(m_cam, H3DCamera::ViewportWidthI, width); h3dSetNodeParamI(m_cam, H3DCamera::ViewportHeightI, height); h3dSetupCameraView(m_cam, 45.0f, (float)width / height, 0.1f, 1000.0f); h3dResizePipelineBuffers(h3dGetNodeParamI(m_cam, H3DCamera::PipeResI), width, height); // Render scene. h3dRender(m_cam); // Finish rendering of frame. h3dFinalizeFrame(); m_fbo->release(); m_fbo->blitFramebuffer(this->window()->renderTarget(), m_fbo); // Restore (pop) Qt state. glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); glPopClientAttrib(); } } void View3D::cleanup() { this->handleWindowChanged(0); if (m_cam) { h3dRelease(); m_cam = 0; delete m_fbo; m_fbo = 0; } } void View3D::handleWindowChanged(QQuickWindow *win) { if (m_timerID) { this->killTimer(m_timerID); m_timerID = 0; } if (win) { QObject::connect(win, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection); win->setClearBeforeRendering(false); m_timerID = this->startTimer(16); } } |
Author: | Zuck [ 17.08.2013, 08:27 ] |
Post subject: | Re: Qt 5.1 (Qt Quick 2.1) & Horde3D |
Another version! This time I'm using QSGSimpleTextureNode, doing things (almost) right. In fact it solved almost all of the issues of the previous solution and it's now perfectly integrated in the QtQuick scene graph instead of simply copying the render content on the window background. view3d.h Code: #ifndef VIEW3D_H #define VIEW3D_H #include <QQuickItem> #include <QOpenGLFramebufferObject> #include <Horde3D.h> class View3D : public QQuickItem { Q_OBJECT private: int m_timerID; QOpenGLFramebufferObject* m_fbo; H3DNode m_cam; public: View3D( QQuickItem* parent = 0 ); virtual ~View3D(); protected: QSGNode* updatePaintNode(QSGNode* old, UpdatePaintNodeData* data); void timerEvent(QTimerEvent* evt); private slots: void cleanup(); }; #endif // VIEW3D_H view3d.cpp Code: #include "view3d.h" #include <QQuickWindow> #include <QOpenGLContext> #include <QSGSimpleTextureNode> #include <Horde3DUtils.h> View3D::View3D(QQuickItem* parent) : QQuickItem(parent), m_timerID(0), m_fbo(0), m_cam(0) { this->setFlag(QQuickItem::ItemHasContents); } View3D::~View3D() { this->cleanup(); } void View3D::timerEvent(QTimerEvent* evt) { if (evt && evt->timerId() == m_timerID) this->update(); } QSGNode* View3D::updatePaintNode(QSGNode* node, UpdatePaintNodeData* data) { QSGSimpleTextureNode* textureNode = static_cast<QSGSimpleTextureNode*>(node); if (!textureNode) textureNode = new QSGSimpleTextureNode(); // Push Qt state. glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // Render Horde3D. int x = this->x(); int y = this->y(); int width = this->width(); int height = this->height(); delete m_fbo; m_fbo = 0; if (width && height) { m_fbo = new QOpenGLFramebufferObject(width, height); textureNode->setTexture(this->window()->createTextureFromId(m_fbo->texture(), m_fbo->size())); } else { textureNode->setTexture(this->window()->createTextureFromId(0, QSize(0,0))); } textureNode->setRect(this->boundingRect()); // Flip Y-axis between Horde3D and GLSL. QMatrix4x4 flipY; flipY.translate(width*0.5, height*0.5); flipY.scale(1.0, -1.0); flipY.translate(-width*0.5, -height*0.5); data->transformNode->setMatrix(flipY); if (m_fbo) { m_fbo->bind(); if (!m_cam) { // Initialize engine. h3dInit(); h3dSetOption(H3DOptions::LoadTextures, 1); h3dSetOption(H3DOptions::TexCompression, 0); h3dSetOption(H3DOptions::FastAnimation, 0); h3dSetOption(H3DOptions::MaxAnisotropy, 4); h3dSetOption(H3DOptions::ShadowMapSize, 2048); // Add resources. H3DRes pipelineRes = h3dAddResource(H3DResTypes::Pipeline, "pipelines/forward.pipeline.xml", 0); H3DRes envRes = h3dAddResource(H3DResTypes::SceneGraph, "models/platform/platform.scene.xml", 0); H3DRes modelRes = h3dAddResource(H3DResTypes::SceneGraph, "models/knight/knight.scene.xml", 0); // Load added resources. h3dutLoadResourcesFromDisk("data"); // Add an environment. H3DNode env = h3dAddNodes(H3DRootNode, envRes); h3dSetNodeTransform(env, 0, 0, 0, 0, 0, 0, 20, 20, 20 ); // Add a model. H3DNode model = h3dAddNodes(H3DRootNode, modelRes); h3dSetNodeTransform(model, 0, 0, 0, 0, 180, 0, 1, 1, 1 ); // Add a light source. H3DNode light = h3dAddLightNode( H3DRootNode, "Light1", 0, "LIGHTING", "SHADOWMAP" ); h3dSetNodeTransform( light, 0, 15, 40, 0, 0, 0, 100, 100, 100 ); h3dSetNodeParamF( light, H3DLight::RadiusF, 0, 1000 ); h3dSetNodeParamF( light, H3DLight::FovF, 0, 90 ); h3dSetNodeParamI( light, H3DLight::ShadowMapCountI, 1 ); h3dSetNodeParamF( light, H3DLight::ShadowMapBiasF, 0, 0.01f ); h3dSetNodeParamF( light, H3DLight::ColorF3, 0, 1.0f ); h3dSetNodeParamF( light, H3DLight::ColorF3, 1, 0.8f ); h3dSetNodeParamF( light, H3DLight::ColorF3, 2, 0.7f ); h3dSetNodeParamF( light, H3DLight::ColorMultiplierF, 0, 1.0f ); // Add a camera. m_cam = h3dAddCameraNode(H3DRootNode, "Camera", pipelineRes); h3dSetNodeTransform(m_cam, 0, 30, 100, 0, 0, 0, 1, 1, 1 ); QObject::connect(QOpenGLContext::currentContext(), SIGNAL(aboutToBeDestroyed()), this, SLOT(cleanup()), Qt::DirectConnection); } // Setup viewport and render target sizes. h3dSetNodeParamI(m_cam, H3DCamera::ViewportXI, 0); h3dSetNodeParamI(m_cam, H3DCamera::ViewportYI, 0); h3dSetNodeParamI(m_cam, H3DCamera::ViewportWidthI, width); h3dSetNodeParamI(m_cam, H3DCamera::ViewportHeightI, height); h3dSetupCameraView(m_cam, 45.0f, (float)width / height, 0.1f, 1000.0f); h3dResizePipelineBuffers(h3dGetNodeParamI(m_cam, H3DCamera::PipeResI), width, height); // Render scene. h3dRender(m_cam); // Finish rendering of frame. h3dFinalizeFrame(); m_fbo->release(); // Restore (pop) Qt state. glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); glPopClientAttrib(); } if (!m_timerID) m_timerID = this->startTimer(16); return textureNode; } void View3D::cleanup() { this->killTimer(m_timerID); m_timerID = 0; if (m_cam) { h3dRelease(); m_cam = 0; delete m_fbo; m_fbo = 0; } } main.cpp Code: #include "view3d.h" #include <QQuickView> #include <QGuiApplication> int main(int argc, char** argv) { QGuiApplication app(argc, argv); qmlRegisterType<View3D>("View3DToolkit", 1, 0, "View3D"); QQuickView win; win.setSource(QUrl("main.qml")); win.setResizeMode(QQuickView::SizeRootObjectToView); win.show(); return app.exec(); } main.qml Code: import QtQuick 2.1
import View3DToolkit 1.0 Item { width: 320 height: 480 View3D { anchors.fill: parent Rectangle { color: Qt.rgba(0, 1, 0, 0.5); width: 100 height: 100 anchors.centerIn: parent } } Rectangle { color: Qt.rgba(1, 1, 1, 0.7) radius: 10 border.width: 1 border.color: "white" anchors.fill: label anchors.margins: -10 } Text { id: label color: "black" wrapMode: Text.WordWrap text: "The background here is a squircle rendered with raw OpenGL using the 'beforeRender()' signal in QQuickWindow. This text label and its border is rendered using QML" anchors.right: parent.right anchors.left: parent.left anchors.bottom: parent.bottom anchors.margins: 20 } } |
Page 1 of 1 | All times are UTC + 1 hour |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |