├── vr-window ├── vr.qrc ├── materials.qrc ├── vr-window.pro ├── main.cpp ├── StereoFrameGraph.qml └── main.qml ├── qt3d-vr-example.pro ├── .gitignore ├── virtualreality ├── frontend │ ├── qtrackedtransform.h │ ├── qtrackedtransform.cpp │ ├── querytrackedobjectsjob_p.h │ ├── querytrackedobjectsjob.cpp │ ├── qvirtualrealityaspect_p.h │ ├── qvirtualrealityaspect.h │ ├── qvirtualrealitymesh.h │ ├── qvirtualrealitymesh.cpp │ ├── qvirtualrealityaspect.cpp │ ├── qvirtualrealitycamera.h │ └── qvirtualrealitycamera.cpp ├── trackedtransform.cpp ├── qt3dvr_global.h ├── trackedtransform_p.h ├── qvirtualrealitygeometry_p.h ├── vrbackends │ ├── ovr │ │ ├── framebufferovr.h │ │ ├── virtualrealityapiovr.h │ │ ├── framebufferovr.cpp │ │ └── virtualrealityapiovr.cpp │ └── openvr │ │ ├── virtualrealityapiopenvr.h │ │ └── virtualrealityapiopenvr.cpp ├── qvirtualrealityapi.cpp ├── qvirtualrealitygeometry.h ├── qvirtualrealityapi.h ├── virtualreality.pro ├── qvirtualrealityapi_p.h ├── handler.cpp ├── qheadmounteddisplay.h ├── handler_p.h ├── qvirtualrealityapibackend.h ├── qvirtualrealitygeometry.cpp └── qheadmounteddisplay.cpp ├── vr-sdks.pri ├── README.md └── LICENSE /vr-window/vr.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | StereoFrameGraph.qml 5 | 6 | 7 | -------------------------------------------------------------------------------- /qt3d-vr-example.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | # Needed to ensure that things are built right, which you have to do yourself :( 3 | CONFIG += ordered 4 | 5 | # All the projects in your application are sub-projects of your solution 6 | SUBDIRS = virtualreality \ 7 | vr-window 8 | 9 | vr-window.depends = virtualreality 10 | -------------------------------------------------------------------------------- /vr-window/materials.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | BasicCamera.qml 5 | TrefoilKnot.qml 6 | PlaneEntity.qml 7 | RenderableEntity.qml 8 | HousePlant.qml 9 | Barrel.qml 10 | Chest.qml 11 | SortedForwardRenderer.qml 12 | Lights.qml 13 | 14 | 15 | -------------------------------------------------------------------------------- /vr-window/vr-window.pro: -------------------------------------------------------------------------------- 1 | !include( ../vr-sdks.pri ) { 2 | error( "Couldn't find the vr-sdks.pri file!" ) 3 | } 4 | 5 | QT += 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras 6 | 7 | CONFIG += link_prl 8 | 9 | HEADERS += \ 10 | 11 | SOURCES += \ 12 | main.cpp 13 | 14 | OTHER_FILES += \ 15 | main.qml \ 16 | *.qml 17 | 18 | RESOURCES += \ 19 | vr.qrc 20 | 21 | win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../virtualreality/release/ -lvirtualreality 22 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../virtualreality/debug/ -lvirtualreality 23 | else:unix: LIBS += -L$$OUT_PWD/../virtualreality/ -lvirtualreality 24 | 25 | INCLUDEPATH += $$PWD/../virtualreality 26 | DEPENDPATH += $$PWD/../virtualreality 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # https://dev.to/nishina555/how-to-ignore-files-already-managed-with-git-locally-19oo 2 | # skip file as it is user specific 3 | # $ git update-index --skip-worktree vr-sdks.pri ( adjust paths to openvr headers and libs ) 4 | # $ git update-index --skip-worktree virtualreality/virtualreality.pro ( adjust openvr lib name ) 5 | 6 | # user file 7 | # *.user 8 | qt3d-vr-example.pro.user 9 | 10 | # autosave 11 | *.autosave 12 | 13 | 14 | 15 | # Prerequisites 16 | *.d 17 | 18 | # Compiled Object files 19 | *.slo 20 | *.lo 21 | *.o 22 | *.obj 23 | 24 | # Precompiled Headers 25 | *.gch 26 | *.pch 27 | 28 | # Compiled Dynamic libraries 29 | *.so 30 | *.dylib 31 | *.dll 32 | 33 | # Fortran module files 34 | *.mod 35 | *.smod 36 | 37 | # Compiled Static libraries 38 | *.lai 39 | *.la 40 | *.a 41 | *.lib 42 | 43 | # Executables 44 | *.exe 45 | *.out 46 | *.app 47 | -------------------------------------------------------------------------------- /virtualreality/frontend/qtrackedtransform.h: -------------------------------------------------------------------------------- 1 | #ifndef QTRACKEDTRANSFORM_H 2 | #define QTRACKEDTRANSFORM_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | QT_BEGIN_NAMESPACE 11 | 12 | namespace Qt3DVirtualReality { 13 | 14 | class QTrackedTransformPrivate; 15 | 16 | //class QTrackedTransform : public Qt3DCore::QComponent 17 | //{ 18 | //public: 19 | // QTrackedTransform(); 20 | 21 | // // QNode interface 22 | //protected: 23 | // void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) 24 | // { 25 | // } 26 | 27 | //private: 28 | // Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const 29 | // { 30 | // } 31 | //}; 32 | 33 | } // namespace Qt3DVirtualReality 34 | 35 | QT_END_NAMESPACE 36 | 37 | #endif // QTRACKEDTRANSFORM_H 38 | -------------------------------------------------------------------------------- /virtualreality/trackedtransform.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #include "trackedtransform_p.h" 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | Qt3DVirtualReality::TrackedTransform::TrackedTransform() 20 | { 21 | 22 | } 23 | 24 | QT_END_NAMESPACE 25 | -------------------------------------------------------------------------------- /virtualreality/frontend/qtrackedtransform.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #include "qtrackedtransform.h" 16 | 17 | QT_BEGIN_NAMESPACE 18 | 19 | //Qt3DVirtualReality::QTrackedTransform::QTrackedTransform() 20 | //{ 21 | 22 | //} 23 | 24 | QT_END_NAMESPACE 25 | -------------------------------------------------------------------------------- /vr-sdks.pri: -------------------------------------------------------------------------------- 1 | # Custom Configuration 2 | 3 | ###### OpenVR ###### 4 | # Put openvr_api.dll in executable folder 5 | # Incompatible configuration of the dll can be visualized using the tool "dependency walker" 6 | 7 | WITH_VR_SDK_OPENVR = true 8 | VR_SDK_OPENVR_INCLUDE = "D:/devel/openvr/headers" 9 | VR_SDK_OPENVR_LIB_PATH = "D:/devel/openvr/lib/win64" 10 | 11 | 12 | ###### OculusVR ###### 13 | # LibOVR.lib compiles with static runtime by default (/MT, /MTd). 14 | # This can be changed by recompiling the lib using visual studio (simple task) 15 | # For 32bit you might add "_ITERATOR_DEBUG_LEVEL=0" under C/C++ -> Preprocessor -> Preprocessordefinitions 16 | 17 | WITH_VR_SDK_OCULUSVR = true 18 | VR_SDK_OCULUSVR_INCLUDE = "D:/devel/OculusSDK/LibOVR/Include" 19 | #VR_SDK_OCULUSVR_LIB_PATH = "D:/devel/OculusSDK/LibOVR/Lib/Windows/x64/Release/VS2015" 20 | VR_SDK_OCULUSVR_LIB_PATH = "D:/devel/OculusSDK/LibOVR/Lib/Windows/x64/Debug/VS2015" 21 | 22 | 23 | ###### OSVR ###### 24 | # Not yet implemented 25 | 26 | WITH_VR_SDK_OSVR = false 27 | 28 | ###### OpenXR ###### 29 | 30 | WITH_VR_OPENXR = false 31 | -------------------------------------------------------------------------------- /virtualreality/qt3dvr_global.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QT3DVR_GLOBAL_H 16 | #define QT3DVR_GLOBAL_H 17 | 18 | #include 19 | 20 | QT_BEGIN_NAMESPACE 21 | 22 | #if defined(QT_SHARED) || !defined(QT_STATIC) 23 | # if defined(QT3DVR_LIBRARY) 24 | # define QT3DVR_EXPORT Q_DECL_EXPORT 25 | # else 26 | # define QT3DVR_EXPORT Q_DECL_IMPORT 27 | # endif 28 | #else 29 | # define QT3DVR_EXPORT 30 | #endif 31 | 32 | QT_END_NAMESPACE 33 | 34 | #endif // QT3DVR_GLOBAL_H 35 | -------------------------------------------------------------------------------- /virtualreality/trackedtransform_p.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef TRACKEDTRANSFORM_P_H 16 | #define TRACKEDTRANSFORM_P_H 17 | 18 | #include 19 | 20 | QT_BEGIN_NAMESPACE 21 | 22 | namespace Qt3DVirtualReality { 23 | 24 | class TrackedTransform : public Qt3DCore::QBackendNode 25 | { 26 | public: 27 | TrackedTransform(); 28 | 29 | // QBackendNode interface 30 | protected: 31 | void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) 32 | { 33 | } 34 | 35 | private: 36 | void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) 37 | { 38 | } 39 | }; 40 | 41 | } //namespace Qt3DVirtualReality 42 | 43 | QT_END_NAMESPACE 44 | 45 | #endif // TRACKEDTRANSFORM_P_H 46 | -------------------------------------------------------------------------------- /virtualreality/frontend/querytrackedobjectsjob_p.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QT3DVIRTUALREALITY_QUERYTRACKEDPOBJECTS_P_H 16 | #define QT3DVIRTUALREALITY_QUERYTRACKEDPOBJECTS_P_H 17 | 18 | #include 19 | 20 | QT_BEGIN_NAMESPACE 21 | 22 | namespace Qt3DVirtualReality { 23 | 24 | class QVirtualRealityApiBackend; 25 | 26 | class QueryTrackedObjectsJob : public Qt3DCore::QAspectJob 27 | { 28 | public: 29 | QueryTrackedObjectsJob(); 30 | void setVirtualRealityApiBackend(QVirtualRealityApiBackend *apibackend); 31 | 32 | void run() Q_DECL_OVERRIDE; 33 | 34 | private: 35 | QVirtualRealityApiBackend *m_apibackend; 36 | }; 37 | 38 | } // namespace Qt3DVirtualReality 39 | 40 | QT_END_NAMESPACE 41 | 42 | #endif // QT3DLOGIC_LOGIC_CALLBACKJOB_P_H 43 | -------------------------------------------------------------------------------- /virtualreality/frontend/querytrackedobjectsjob.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #include "querytrackedobjectsjob_p.h" 16 | 17 | #include 18 | 19 | #include //TODO: remove DBG 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | namespace Qt3DVirtualReality { 24 | 25 | namespace JobTypes { 26 | 27 | enum JobType { 28 | QueryTrackedObjects = 16384 29 | }; 30 | 31 | } // JobTypes 32 | 33 | QueryTrackedObjectsJob::QueryTrackedObjectsJob() 34 | : QAspectJob() 35 | , m_apibackend(nullptr) 36 | { 37 | SET_JOB_RUN_STAT_TYPE(this, JobTypes::QueryTrackedObjects, 0); 38 | } 39 | 40 | void QueryTrackedObjectsJob::setVirtualRealityApiBackend(QVirtualRealityApiBackend *apibackend) 41 | { 42 | m_apibackend = apibackend; 43 | } 44 | 45 | void QueryTrackedObjectsJob::run() 46 | { 47 | qDebug() << "TODO:DBG:Running query object tracked vr!"; 48 | } 49 | 50 | } // namespace Qt3DVirtualReality 51 | 52 | QT_END_NAMESPACE 53 | -------------------------------------------------------------------------------- /virtualreality/frontend/qvirtualrealityaspect_p.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QT3DVIRTUALREALITY_QVIRTUALREALITYASPECT_P_H 16 | #define QT3DVIRTUALREALITY_QVIRTUALREALITYASPECT_P_H 17 | 18 | #include "qvirtualrealityaspect.h" 19 | #include 20 | #include 21 | #include "querytrackedobjectsjob_p.h" 22 | 23 | QT_BEGIN_NAMESPACE 24 | 25 | namespace Qt3DVirtualReality { 26 | 27 | class QHeadMountedDisplay; 28 | class QVirtualRealityApi; 29 | class QVirtualRealityApiBackend; 30 | 31 | class QVirtualRealityAspectPrivate : public Qt3DCore::QAbstractAspectPrivate 32 | { 33 | QVirtualRealityAspectPrivate(); 34 | 35 | Q_DECLARE_PUBLIC(QVirtualRealityAspect) 36 | 37 | void onEngineAboutToShutdown() Q_DECL_OVERRIDE; 38 | void registerBackendTypes(); 39 | 40 | qint64 m_time; 41 | bool m_initialized; 42 | QSharedPointer m_queryTrackedObjectsJob; 43 | 44 | 45 | QHeadMountedDisplay *m_hmd; 46 | //QVirtualRealityApi *m_api; 47 | QVirtualRealityApiBackend *m_apibackend; 48 | }; 49 | 50 | } // namespace Qt3DLogic 51 | 52 | QT_END_NAMESPACE 53 | 54 | #endif // QT3DVIRTUALREALITY_QVIRTUALREALITYASPECT_P_H 55 | -------------------------------------------------------------------------------- /virtualreality/qvirtualrealitygeometry_p.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | 16 | #ifndef QT3DEXTRAS_QVIRTUALREALITYGEOMETRY_P_H 17 | #define QT3DEXTRAS_QVIRTUALREALITYGEOMETRY_P_H 18 | 19 | #include 20 | #include 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | namespace Qt3DRender { 25 | 26 | class QAttribute; 27 | class QBuffer; 28 | 29 | } // namespace Qt3DRender 30 | 31 | namespace Qt3DVirtualReality { 32 | 33 | class QVirtualRealityGeometryPrivate : public Qt3DRender::QGeometryPrivate 34 | { 35 | public: 36 | QVirtualRealityGeometryPrivate(); 37 | 38 | void init(); 39 | 40 | Q_DECLARE_PUBLIC(QVirtualRealityGeometry) 41 | 42 | int m_trackedObjectIndex; 43 | Qt3DRender::QAttribute *m_positionAttribute; 44 | Qt3DRender::QAttribute *m_normalAttribute; 45 | Qt3DRender::QAttribute *m_texCoordAttribute; 46 | Qt3DRender::QAttribute *m_indexAttribute; 47 | Qt3DRender::QBuffer *m_positionBuffer; 48 | Qt3DRender::QBuffer *m_vertexBuffer; 49 | Qt3DRender::QBuffer *m_indexBuffer; 50 | QVirtualRealityApiBackend *m_apibackend; 51 | }; 52 | 53 | } // Qt3DVirtualReality 54 | 55 | QT_END_NAMESPACE 56 | 57 | #endif // QT3DEXTRAS_QVIRTUALREALITYGEOMETRY_P_H 58 | 59 | -------------------------------------------------------------------------------- /virtualreality/vrbackends/ovr/framebufferovr.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #if(QT3DVR_COMPILE_WITH_OCULUSVR) 16 | #ifndef QVRRENDERTARGET 17 | #define QVRRENDERTARGET 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | //#include "GL/CAPI_GLE.h" 25 | #include "Extras/OVR_Math.h" 26 | #include "OVR_CAPI_GL.h" 27 | #include 28 | 29 | #if defined(_WIN32) 30 | #include // for GetDefaultAdapterLuid 31 | //#pragma comment(lib, "dxgi.lib") 32 | #endif 33 | 34 | using namespace OVR; 35 | 36 | class FramebufferOvr; 37 | 38 | class OvrSwapChain 39 | { 40 | QSize m_texSize; 41 | ovrSession m_session; 42 | //GLuint m_texIdDepthBuffer; 43 | QOpenGLFunctions_3_2_Core *m_funcs; 44 | QVector m_framebuffers; 45 | ovrTextureSwapChain m_textureChain; 46 | public: 47 | OvrSwapChain(ovrSession session, QSize size); 48 | ~OvrSwapChain(); 49 | 50 | QSize size() const; 51 | void bindCurrentChainIndexFramebuffer(); 52 | void bindFramebuffer(int index); 53 | int chainLength() const; 54 | void commit(); 55 | const ovrTextureSwapChain &ovrTextureChain() const; 56 | }; 57 | 58 | #endif 59 | #endif 60 | -------------------------------------------------------------------------------- /vr-window/main.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "qvirtualrealityapi.h" 22 | #include "qheadmounteddisplay.h" 23 | 24 | int main(int argc, char* argv[]) 25 | { 26 | qDebug() << "VR Window demo"; 27 | QGuiApplication app(argc, argv); 28 | Qt3DVirtualReality::QVirtualRealityApi::Type requestedVrApi(Qt3DVirtualReality::QVirtualRealityApi::OpenVR); 29 | bool apiAvialable = Qt3DVirtualReality::QVirtualRealityApi::isRuntimeInstalled(requestedVrApi); 30 | if(!apiAvialable) 31 | { 32 | qDebug() << "Vr API not available. Try to choose another VR SDK or recompile with support for other VR SDK."; 33 | return 1; 34 | } 35 | qDebug() << "Starting..."; 36 | Qt3DVirtualReality::QVirtualRealityApi vrapi(requestedVrApi); 37 | Qt3DVirtualReality::QHeadMountedDisplayFormat fmt; 38 | Qt3DVirtualReality::QHeadMountedDisplay *hmd(vrapi.getHmd(0, fmt)); 39 | if( hmd == nullptr ) { 40 | qDebug() << "Head Mounted disply could not be initialized"; 41 | return 1; 42 | } 43 | // Expose the head mounted display as a context property so we can set the aspect ratio 44 | hmd->engine()->qmlEngine()->rootContext()->setContextProperty("_hmd", hmd); 45 | hmd->setSource(QUrl("qrc:/main.qml")); 46 | 47 | hmd->run(); 48 | return app.exec(); 49 | } 50 | -------------------------------------------------------------------------------- /virtualreality/frontend/qvirtualrealityaspect.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QT3DVIRTUALREALITY_QVIRTUALREALITYASPECT_H 16 | #define QT3DVIRTUALREALITY_QVIRTUALREALITYASPECT_H 17 | 18 | #include 19 | #include 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | namespace Qt3DRender { 24 | class QRenderAspect; 25 | } 26 | 27 | namespace Qt3DVirtualReality { 28 | 29 | class QVirtualRealityAspectPrivate; 30 | class QHeadMountedDisplay; 31 | //class QVirtualRealityApi; 32 | class QVirtualRealityApiBackend; 33 | 34 | //TO DO: might needs access to RenderAspect. UpdateWorldTransformJob must depend on QueryTrackedObjectsJob 35 | 36 | class QT3DVR_EXPORT QVirtualRealityAspect : public Qt3DCore::QAbstractAspect 37 | { 38 | Q_OBJECT 39 | public: 40 | explicit QVirtualRealityAspect(QObject *parent = nullptr); 41 | ~QVirtualRealityAspect(); 42 | 43 | void setHeadmountedDisplay(QHeadMountedDisplay *hmd); 44 | //void setVirtualRealityApi(QVirtualRealityApi *api); 45 | void setVirtualRealityApiBackend(QVirtualRealityApiBackend *apiBackend); 46 | private: 47 | QVariant executeCommand(const QStringList &args) Q_DECL_OVERRIDE; 48 | QVector jobsToExecute(qint64 time) Q_DECL_OVERRIDE; 49 | void onRegistered() Q_DECL_OVERRIDE; 50 | void onUnregistered() Q_DECL_OVERRIDE; 51 | 52 | protected: 53 | explicit QVirtualRealityAspect(QVirtualRealityAspectPrivate &dd, QObject *parent); 54 | Q_DECLARE_PRIVATE(QVirtualRealityAspect) 55 | }; 56 | 57 | } // namespace Qt3DVirtualReality 58 | 59 | QT_END_NAMESPACE 60 | 61 | #endif // QT3DVIRTUALREALITY_QVIRTUALREALITYASPECT_H 62 | -------------------------------------------------------------------------------- /virtualreality/qvirtualrealityapi.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #include "qvirtualrealityapi.h" 16 | #include "qheadmounteddisplay.h" 17 | #include "qvirtualrealityapi_p.h" 18 | 19 | #include 20 | namespace Qt3DVirtualReality { 21 | 22 | QVirtualRealityApi::QVirtualRealityApi(Qt3DVirtualReality::QVirtualRealityApi::Type type) 23 | : QVirtualRealityApi() 24 | { 25 | Q_D(QVirtualRealityApi); 26 | d->setType(type); 27 | } 28 | 29 | QVirtualRealityApi::QVirtualRealityApi() 30 | : Qt3DVirtualReality::QVirtualRealityApi(*new Qt3DVirtualReality::QVirtualRealityApiPrivate) 31 | {} 32 | 33 | 34 | QVirtualRealityApi::QVirtualRealityApi(Qt3DVirtualReality::QVirtualRealityApiPrivate &dd, QObject *parent) 35 | : QObject(dd, parent) 36 | {} 37 | 38 | QVirtualRealityApi::~QVirtualRealityApi() 39 | { 40 | Q_D(QVirtualRealityApi); 41 | d->m_apibackend->shutdown(); 42 | } 43 | 44 | bool QVirtualRealityApi::isHmdPresent() 45 | { 46 | Q_D(QVirtualRealityApi); 47 | return d->m_apibackend->isHmdPresent(); 48 | } 49 | 50 | bool QVirtualRealityApi::isRuntimeInstalled(Qt3DVirtualReality::QVirtualRealityApi::Type type) 51 | { 52 | return QVirtualRealityApiPrivate::isRuntimeInstalled(type); 53 | } 54 | 55 | QHeadMountedDisplay* QVirtualRealityApi::getHmd(int hmdId, const QHeadMountedDisplayFormat &format) 56 | { 57 | Q_D(QVirtualRealityApi); 58 | Qt3DVirtualReality::QHeadMountedDisplay *hmd(new Qt3DVirtualReality::QHeadMountedDisplay(hmdId, format, this, d->m_apibackend)); 59 | hmd->context()->makeCurrent(static_cast(hmd->surface())); 60 | d->initialize(); 61 | return hmd; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /virtualreality/frontend/qvirtualrealitymesh.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QVIRTUALREALITYMESH_H 16 | #define QVIRTUALREALITYMESH_H 17 | 18 | #include 19 | #include 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | namespace Qt3DVirtualReality { 24 | 25 | class QVirtualRealityApiBackend; //TO DO: temp 26 | 27 | class QT3DVR_EXPORT QVirtualRealityMesh : public Qt3DRender::QGeometryRenderer 28 | { 29 | Q_OBJECT 30 | Q_PROPERTY(int trackedObjectId READ trackedObjectId WRITE setTrackedObjectId NOTIFY trackedObjectIdChanged) 31 | public: 32 | explicit QVirtualRealityMesh(Qt3DCore::QNode *parent = nullptr); 33 | ~QVirtualRealityMesh(); 34 | 35 | int trackedObjectId() const; 36 | 37 | void setVrApiBackendTmp(QVirtualRealityApiBackend *apibackend); //TO DO: temp 38 | 39 | public Q_SLOTS: 40 | 41 | void setTrackedObjectId(int trackedObjectId); 42 | 43 | Q_SIGNALS: 44 | 45 | void trackedObjectIdChanged(int trackedObjectId); 46 | 47 | private: 48 | // As this is a default provided geometry renderer, no one should be able 49 | // to modify the QGeometryRenderer's properties 50 | 51 | void setInstanceCount(int instanceCount); 52 | void setVertexCount(int vertexCount); 53 | void setIndexOffset(int indexOffset); 54 | void setFirstInstance(int firstInstance); 55 | void setRestartIndexValue(int index); 56 | void setPrimitiveRestartEnabled(bool enabled); 57 | void setGeometry(Qt3DRender::QGeometry *geometry); 58 | void setPrimitiveType(PrimitiveType primitiveType); 59 | int m_trackedObjectId; 60 | }; 61 | 62 | } // namespace Qt3DVirtualReality 63 | 64 | QT_END_NAMESPACE 65 | 66 | #endif // QVIRTUALREALITYMESH_H 67 | -------------------------------------------------------------------------------- /virtualreality/vrbackends/ovr/virtualrealityapiovr.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #if(QT3DVR_COMPILE_WITH_OCULUSVR) 16 | #ifndef VIRTUALREALITYAPIOVR_H 17 | #define VIRTUALREALITYAPIOVR_H 18 | #include "../../qvirtualrealityapibackend.h" 19 | #include "OVR_CAPI_GL.h" 20 | 21 | class OvrSwapChain; 22 | 23 | class VirtualRealityApiOvr : public Qt3DVirtualReality::QVirtualRealityApiBackend 24 | { 25 | public: 26 | static bool isRuntimeInstalled(); 27 | VirtualRealityApiOvr(); 28 | ~VirtualRealityApiOvr(); 29 | bool isHmdPresent(); 30 | 31 | void initialize(); 32 | void shutdown(); 33 | bool bindFrambufferObject(int hmdId); 34 | 35 | qreal refreshRate(int hmdId) const; 36 | QMatrix4x4 headPose(int hmdId); 37 | QSize getRenderTargetSize(); 38 | 39 | int timeUntilNextFrame(); 40 | 41 | void swapToHeadset(); 42 | 43 | void getEyeMatrices(QMatrix4x4 &leftEye, QMatrix4x4 &rightEye); 44 | 45 | void getProjectionMatrices(QMatrix4x4 &leftProjection, QMatrix4x4 &rightProjection); 46 | 47 | QList currentlyTrackedObjects(); 48 | void getTrackedObject(int id, QMatrix4x4 &transform); 49 | TrackedObjectType getTrackedObjectType(int id); 50 | void getTrackedObjectModel(int id, QVector &vertices, QVector &indices, QOpenGLTexture *texture); 51 | 52 | void getMirrorTexture(QOpenGLTexture *outMirrorTexture); 53 | 54 | bool isTriggerTmp(); 55 | private: 56 | bool m_sessionStarted; 57 | ovrSession m_session; 58 | ovrGraphicsLuid m_luid; 59 | //TO DO: decouple using hmdId 60 | ovrHmdDesc m_hmdDesc; 61 | ovrPosef m_eyeRenderPose[2]; 62 | double m_sensorSampleTime; 63 | long long m_frameIndex; 64 | OvrSwapChain *m_swapChain; 65 | 66 | bool initializeIfHmdIsPresent(); 67 | }; 68 | 69 | #endif 70 | #endif 71 | -------------------------------------------------------------------------------- /virtualreality/qvirtualrealitygeometry.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QT3DEXTRAS_QVIRTUALREALITYGEOMETRY_H 16 | #define QT3DEXTRAS_QVIRTUALREALITYGEOMETRY_H 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | namespace Qt3DRender { 25 | class QAttribute; 26 | } // Render 27 | 28 | namespace Qt3DVirtualReality { 29 | 30 | class QVirtualRealityGeometryPrivate; 31 | 32 | class QT3DVR_EXPORT QVirtualRealityGeometry : public Qt3DRender::QGeometry 33 | { 34 | Q_OBJECT 35 | Q_PROPERTY(int trackedObjectIndex READ trackedObjectIndex WRITE setTrackedObjectIndex NOTIFY trackedObjectIndexChanged) 36 | Q_PROPERTY(Qt3DRender::QAttribute *positionAttribute READ positionAttribute CONSTANT) 37 | Q_PROPERTY(Qt3DRender::QAttribute *normalAttribute READ normalAttribute CONSTANT) 38 | Q_PROPERTY(Qt3DRender::QAttribute *texCoordAttribute READ texCoordAttribute CONSTANT) 39 | Q_PROPERTY(Qt3DRender::QAttribute *indexAttribute READ indexAttribute CONSTANT) 40 | 41 | public: 42 | explicit QVirtualRealityGeometry(QNode *parent = nullptr); 43 | ~QVirtualRealityGeometry(); 44 | 45 | void updateVertices(); 46 | void updateIndices(); 47 | 48 | //TO DO: this should be there e.g. through backend/aspects 49 | void setVrApiBackendTmp(QVirtualRealityApiBackend *apibackend); 50 | 51 | int trackedObjectIndex() const; 52 | Qt3DRender::QAttribute *positionAttribute() const; 53 | Qt3DRender::QAttribute *normalAttribute() const; 54 | Qt3DRender::QAttribute *texCoordAttribute() const; 55 | Qt3DRender::QAttribute *indexAttribute() const; 56 | 57 | public Q_SLOTS: 58 | void setTrackedObjectIndex(int trackedObjectIndex); 59 | 60 | Q_SIGNALS: 61 | void trackedObjectIndexChanged(int trackedObjectIndex); 62 | 63 | protected: 64 | QVirtualRealityGeometry(QVirtualRealityGeometryPrivate &dd, QNode *parent = nullptr); 65 | 66 | private: 67 | Q_DECLARE_PRIVATE(QVirtualRealityGeometry) 68 | }; 69 | 70 | } // namespace Qt3DVirtualReality 71 | 72 | QT_END_NAMESPACE 73 | 74 | #endif // QT3DEXTRAS_QVIRTUALREALITYGEOMETRY_H 75 | -------------------------------------------------------------------------------- /virtualreality/frontend/qvirtualrealitymesh.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #include "qvirtualrealitymesh.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "qvirtualrealitygeometry.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | namespace Qt3DVirtualReality { 27 | 28 | #ifndef _USE_MATH_DEFINES 29 | # define _USE_MATH_DEFINES // For MSVC 30 | #endif 31 | 32 | 33 | /*! 34 | * \qmltype VirtualrealityMesh 35 | * \instantiates Qt3DVirtualReality::QVirtualRealityMesh 36 | * \inqmlmodule Qt3D.VirtualReality 37 | * \brief A conical mesh. 38 | */ 39 | 40 | /*! 41 | * \qmlproperty real VirtualrealityMesh::length 42 | * 43 | * Holds the length. 44 | */ 45 | 46 | /*! 47 | * \class Qt3DVirtualReality::QVirtualrealityMesh 48 | * \inheaderfile Qt3DVirtualReality/QVirtualrealityMesh 49 | * \inmodule Qt3DVirtualReality 50 | * 51 | * \inherits Qt3DRender::QGeometryRenderer 52 | * 53 | * \brief A mesh queried from VR SDK. 54 | */ 55 | 56 | QVirtualRealityMesh::QVirtualRealityMesh(QNode *parent) 57 | : QGeometryRenderer(parent) 58 | { 59 | QVirtualRealityGeometry *geometry = new QVirtualRealityGeometry(this); 60 | QObject::connect(geometry, &QVirtualRealityGeometry::trackedObjectIndexChanged, this, &QVirtualRealityMesh::trackedObjectIdChanged); 61 | 62 | QGeometryRenderer::setGeometry(geometry); 63 | } 64 | 65 | /*! \internal */ 66 | QVirtualRealityMesh::~QVirtualRealityMesh() 67 | { 68 | } 69 | 70 | int QVirtualRealityMesh::trackedObjectId() const 71 | { 72 | return static_cast(geometry())->trackedObjectIndex(); 73 | } 74 | 75 | void QVirtualRealityMesh::setVrApiBackendTmp(QVirtualRealityApiBackend *apibackend) 76 | { 77 | static_cast(geometry())->setVrApiBackendTmp(apibackend); 78 | } 79 | 80 | void QVirtualRealityMesh::setTrackedObjectId(int trackedObjectId) 81 | { 82 | static_cast(geometry())->setTrackedObjectIndex(trackedObjectId); 83 | } 84 | 85 | } 86 | 87 | // namespace Qt3DVirtualReality 88 | QT_END_NAMESPACE 89 | -------------------------------------------------------------------------------- /virtualreality/qvirtualrealityapi.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QT3DVIRTUALREALITYAPI_H 16 | #define QT3DVIRTUALREALITYAPI_H 17 | 18 | #include "qt3dvr_global.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | namespace Qt3DVirtualReality { 27 | 28 | class QHeadMountedDisplay; 29 | class QVirtualRealityApiPrivate; 30 | 31 | class QHeadMountedDisplayFormat { 32 | // void setSize(const QSize& size); 33 | // const QSize& size(); 34 | // void setRenderingSurface(GLuint textureId); 35 | // GLuint renderingSurface(); 36 | }; 37 | /** 38 | * @brief The QVrApi class 39 | * TODO: Uses virtual methods internally to decide which concrete implementation was chosen. Alternatively the public interface could use template parameters. 40 | */ 41 | class QT3DVR_EXPORT QVirtualRealityApi : public QObject 42 | { 43 | Q_OBJECT 44 | public: 45 | enum Type 46 | { 47 | OculusVR, // OculusVR 48 | OSVR, // OpenSourceVR (e.g. Razer) 49 | OpenVR // HTC Vive / SteamVR 50 | }; 51 | 52 | /// 53 | /// \brief QVirtualRealityApi() Tries to choose the most specific API for the connected HMD. 54 | /// 1) Ovr, 2) OpenVR, 3) OSVR 55 | /// 56 | QVirtualRealityApi(); 57 | /// 58 | /// \brief QVirtualRealityApi Initialize with known API of given type 59 | /// \param type 60 | /// 61 | explicit QVirtualRealityApi(QVirtualRealityApi::Type type); 62 | ~QVirtualRealityApi(); 63 | 64 | QVirtualRealityApi &operator=(const QVirtualRealityApi &other); 65 | 66 | /// 67 | /// \brief type 68 | /// \return type of API used to connect to the headmounted display 69 | /// 70 | QVirtualRealityApi::Type type() const; 71 | 72 | bool isHmdPresent(); 73 | static bool isRuntimeInstalled(QVirtualRealityApi::Type type); 74 | bool supportsSetSurface() const; 75 | 76 | QHeadMountedDisplay *getHmd(int hmdId, const QHeadMountedDisplayFormat &format); 77 | 78 | private: 79 | QVirtualRealityApi(QVirtualRealityApiPrivate &dd, QObject *parent = nullptr); 80 | Q_DECLARE_PRIVATE(QVirtualRealityApi) 81 | }; 82 | 83 | } 84 | 85 | QT_END_NAMESPACE 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /virtualreality/virtualreality.pro: -------------------------------------------------------------------------------- 1 | !include( ../vr-sdks.pri ) { 2 | error( "Couldn't find the vr-sdks.pri file!" ) 3 | } 4 | 5 | TARGET = virtualreality 6 | 7 | TEMPLATE = lib 8 | 9 | DEFINES += QT3DVR_LIBRARY 10 | 11 | #MODULE = virtualreality 12 | QT += qml quick \ 13 | core core-private 3dcore 3dcore-private 3drender 3drender-private 3dinput 3dlogic 3dquick \ 14 | qml qml-private 3dquick 3drender 3drender-private 3dlogic 15 | 16 | # Qt3D is free of Q_FOREACH - make sure it stays that way: 17 | DEFINES += QT_NO_FOREACH 18 | 19 | #load(qt_module) 20 | 21 | CONFIG += c++11 22 | 23 | # track dependecies 24 | CONFIG += create_prl 25 | 26 | SOURCES += \ 27 | vrbackends/ovr/virtualrealityapiovr.cpp \ 28 | vrbackends/ovr/framebufferovr.cpp \ 29 | vrbackends/openvr/virtualrealityapiopenvr.cpp \ 30 | qvirtualrealityapi.cpp \ 31 | qheadmounteddisplay.cpp \ 32 | frontend/qvirtualrealityaspect.cpp \ 33 | frontend/qvirtualrealitycamera.cpp \ 34 | frontend/qvirtualrealitymesh.cpp \ 35 | frontend/querytrackedobjectsjob.cpp \ 36 | qvirtualrealitygeometry.cpp \ 37 | handler.cpp \ 38 | frontend/qtrackedtransform.cpp \ 39 | trackedtransform.cpp 40 | 41 | HEADERS += \ 42 | vrbackends/ovr/virtualrealityapiovr.h \ 43 | vrbackends/ovr/framebufferovr.h \ 44 | vrbackends/openvr/virtualrealityapiopenvr.h \ 45 | qvirtualrealityapi.h \ 46 | qvirtualrealityapi_p.h \ 47 | qvirtualrealityapibackend.h \ 48 | qheadmounteddisplay.h \ 49 | qt3dvr_global.h \ 50 | frontend/qvirtualrealityaspect.h \ 51 | frontend/qvirtualrealityaspect_p.h \ 52 | frontend/qvirtualrealitycamera.h \ 53 | frontend/qvirtualrealitymesh.h \ 54 | frontend/querytrackedobjectsjob_p.h \ 55 | qvirtualrealitygeometry.h \ 56 | qvirtualrealitygeometry_p.h \ 57 | handler_p.h \ 58 | frontend/qtrackedtransform.h \ 59 | trackedtransform_p.h 60 | 61 | ###### OpenVR ###### 62 | if($$WITH_VR_SDK_OPENVR) { 63 | message("Building with OpenVR support") 64 | INCLUDEPATH += $$VR_SDK_OPENVR_INCLUDE 65 | LIBS += -L$$VR_SDK_OPENVR_LIB_PATH 66 | LIBS += "$$VR_SDK_OPENVR_LIB_PATH/libopenvr_api.so" 67 | #LIBS += -L$$VR_SDK_OPENVR_LIB_PATH -lopenvr_api 68 | DEFINES+="QT3DVR_COMPILE_WITH_OPENVR=1" 69 | } else { 70 | DEFINES+="QT3DVR_COMPILE_WITH_OPENVR=0" 71 | } 72 | 73 | ###### OculusVR ###### 74 | if($$WITH_VR_SDK_OCULUSVR) { 75 | message("Building with Oculus support") 76 | INCLUDEPATH += $$VR_SDK_OCULUSVR_INCLUDE 77 | LIBS += -L$$VR_SDK_OCULUSVR_LIB_PATH -lLibOVR 78 | DEFINES+="QT3DVR_COMPILE_WITH_OCULUSVR=1" 79 | } else { 80 | DEFINES+="QT3DVR_COMPILE_WITH_OCULUSVR=0" 81 | } 82 | 83 | ###### OSVR ###### 84 | if($$WITH_VR_SDK_OSVR) { 85 | message("Building with OSVR support") 86 | INCLUDEPATH += $$VR_SDK_OSVR_INCLUDE 87 | LIBS += -L$$VR_SDK_OSVR_LIB_PATH -l 88 | DEFINES+="QT3DVR_COMPILE_WITH_OSVR=1" 89 | } else { 90 | DEFINES+="QT3DVR_COMPILE_WITH_OSVR=0" 91 | } 92 | 93 | win32 { 94 | LIBS += -ldxgi 95 | } 96 | -------------------------------------------------------------------------------- /virtualreality/qvirtualrealityapi_p.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QT3DVIRTUALREALITYAPI_P_H 16 | #define QT3DVIRTUALREALITYAPI_P_H 17 | 18 | #include "qvirtualrealityapi.h" 19 | 20 | #include 21 | #include 22 | #include "qvirtualrealityapibackend.h" 23 | 24 | #if(QT3DVR_COMPILE_WITH_OCULUSVR) 25 | # include "vrbackends/ovr/virtualrealityapiovr.h" 26 | #endif 27 | #if(QT3DVR_COMPILE_WITH_OPENVR) 28 | # include "vrbackends/openvr/virtualrealityapiopenvr.h" 29 | #endif 30 | #if(QT3DVR_COMPILE_WITH_OSVR) 31 | # include "vrbackends/osvr/vrapiosvr.h" 32 | #endif 33 | 34 | QT_BEGIN_NAMESPACE 35 | 36 | namespace Qt3DVirtualReality { 37 | 38 | class QVirtualRealityApiPrivate : public QObjectPrivate 39 | { 40 | public: 41 | 42 | Q_DECLARE_PUBLIC(QVirtualRealityApi) 43 | 44 | //VrApiBackend 45 | QVirtualRealityApiBackend *m_apibackend; 46 | 47 | void setType(QVirtualRealityApi::Type vendor) { 48 | #if(QT3DVR_COMPILE_WITH_OCULUSVR) 49 | if(QVirtualRealityApi::OculusVR == vendor) { 50 | m_apibackend = new VirtualRealityApiOvr(); 51 | return; 52 | } 53 | #endif 54 | #if(QT3DVR_COMPILE_WITH_OPENVR) 55 | if(QVirtualRealityApi::OpenVR == vendor) { 56 | m_apibackend = new VirtualRealityApiOpenVR(); 57 | return; 58 | } 59 | #endif 60 | } 61 | static bool isRuntimeInstalled(QVirtualRealityApi::Type vendor) { 62 | #if(QT3DVR_COMPILE_WITH_OCULUSVR) 63 | if(QVirtualRealityApi::OculusVR == vendor) { 64 | return VirtualRealityApiOvr::isRuntimeInstalled(); 65 | } 66 | #endif 67 | #if(QT3DVR_COMPILE_WITH_OPENVR) 68 | if(QVirtualRealityApi::OpenVR == vendor) { 69 | return VirtualRealityApiOpenVR::isRuntimeInstalled(); 70 | } 71 | #endif 72 | } 73 | void initialize() { 74 | if(!m_initialized) { 75 | Q_ASSERT(m_apibackend != nullptr); 76 | m_apibackend->initialize(); 77 | m_initialized = true; 78 | } 79 | } 80 | QVirtualRealityApiPrivate() 81 | : m_apibackend(nullptr) 82 | , m_initialized(false) 83 | { 84 | 85 | } 86 | 87 | ~QVirtualRealityApiPrivate() { 88 | if(m_apibackend) 89 | delete m_apibackend; 90 | } 91 | private: 92 | bool m_initialized; 93 | }; 94 | 95 | } 96 | 97 | QT_END_NAMESPACE 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qt3d-vr-example 2 | Qt3d example with support for OpenVR and OculusVR natively 3 | 4 | ## Setup 5 | Change _vr-sdks.pri_ to fit your directory structure and installation path for vr sdks. 6 | The current implementation uses private headers of Qt3d 5.9. 7 | If the application crashes at startup, it could be that the vr library is incompatible to your build. 8 | 9 | ### OpenVR 10 | You might have to put _openvr_api.dll_ into the executable directory. 11 | Incompatible configurations of the dll with your build can be visualized using the tool "dependency walker". 12 | 13 | ### OculusVR (LibOVR.lib) 14 | Note that the Oculus SDK (LibOVR.lib) is built with incompatible ABI to QtCreator/Visual Studio standard settings. 15 | * LibOVR.lib compiles with static runtime by default (/MT, /MTd). 16 | * Recompiling the lib using is the recommended way to solve this (simple task). 17 | * Visual Studio projects for LibOVR.lib are part of the OculusSDK 18 | * In the Visual Studio Property Pages go to "C/C++ -> Codegeneration -> Runtime Library" and select Multithreaded-Debug (/MTd) for the Debug configuration. (...and /MT for the release config) 19 | * For 32bit you might add "\_ITERATOR_DEBUG_LEVEL=0" under C/C++ -> Preprocessor -> Preprocessordefinitions 20 | 21 | # API 22 | 23 | The project vr-window is an example usage. 24 | The project virtualreality is a library. 25 | 26 | In order to render to the headset, QHeadMountedDisplay must be used in favor of QQuickWindow. 27 | VR Will render only to the Headset. It is not possible to mirror something to the desktop yet (e.g. as a Qml element). This is because VR takes control of the rendering thread. In the future mirroring might be possible, but will very likely use a different Qml scene. 28 | 29 | ```cpp 30 | int main(int argc, char* argv[]) 31 | QGuiApplication app(argc, argv); 32 | auto requestedVrApi = QVirtualRealityApi::OculusVR; 33 | bool apiAvialable = QVirtualRealityApi::isRuntimeInstalled(requestedVrApi); 34 | if(!apiAvialable) { 35 | ... 36 | } 37 | QVirtualRealityApi vrapi(requestedVrApi); 38 | QHeadMountedDisplayFormat fmt; 39 | QHeadMountedDisplay *hmd(vrapi.getHmd(0, fmt)); 40 | hmd->setSource(QUrl("qrc:/main.qml")); 41 | hmd->run(); 42 | return app.exec(); 43 | ``` 44 | 45 | In the qt3d scene, VrCamera must be used to enable head tracking. Moreover the rendertarget must have two viewports for stereoscopic rendering. 46 | 47 | ```qml 48 | VrCamera { 49 | id: vrCam 50 | offset: Qt.vector3d(80.0,-90.0,0.0) 51 | } 52 | ``` 53 | 54 | And in the framegraph the setup looks like this: 55 | ```qml 56 | StereoFrameGraph { 57 | id: stereoFrameGraph 58 | leftCamera: vrCam.leftCamera 59 | rightCamera: vrCam.rightCamera 60 | } 61 | RenderSurfaceSelector { 62 | id: surfaceSelector 63 | externalRenderTargetSize: _hmd.renderTargetSize 64 | 65 | // Draw with left eye 66 | CameraSelector { 67 | camera: vrCam.leftCamera 68 | Viewport { 69 | ... 70 | normalizedRect: Qt.rect(0,0,0.5,1) 71 | } 72 | } 73 | 74 | // Draw with right eye 75 | CameraSelector { 76 | camera: vrCam.rightCamera 77 | Viewport { 78 | ... 79 | normalizedRect: Qt.rect(0.5,0,0.5,1) 80 | } 81 | } 82 | } 83 | ``` 84 | -------------------------------------------------------------------------------- /virtualreality/handler.cpp: -------------------------------------------------------------------------------- 1 | ///**************************************************************************** 2 | //** 3 | //** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). 4 | //** Contact: https://www.qt.io/licensing/ 5 | //** 6 | //** This file is part of the Qt3D module of the Qt Toolkit. 7 | //** 8 | //** $QT_BEGIN_LICENSE:LGPL$ 9 | //** Commercial License Usage 10 | //** Licensees holding valid commercial Qt licenses may use this file in 11 | //** accordance with the commercial license agreement provided with the 12 | //** Software or, alternatively, in accordance with the terms contained in 13 | //** a written agreement between you and The Qt Company. For licensing terms 14 | //** and conditions see https://www.qt.io/terms-conditions. For further 15 | //** information use the contact form at https://www.qt.io/contact-us. 16 | //** 17 | //** GNU Lesser General Public License Usage 18 | //** Alternatively, this file may be used under the terms of the GNU Lesser 19 | //** General Public License version 3 as published by the Free Software 20 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 | //** packaging of this file. Please review the following information to 22 | //** ensure the GNU Lesser General Public License version 3 requirements 23 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 | //** 25 | //** GNU General Public License Usage 26 | //** Alternatively, this file may be used under the terms of the GNU 27 | //** General Public License version 2.0 or (at your option) the GNU General 28 | //** Public license version 3 or any later version approved by the KDE Free 29 | //** Qt Foundation. The licenses are as published by the Free Software 30 | //** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 | //** included in the packaging of this file. Please review the following 32 | //** information to ensure the GNU General Public License requirements will 33 | //** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 | //** https://www.gnu.org/licenses/gpl-3.0.html. 35 | //** 36 | //** $QT_END_LICENSE$ 37 | //** 38 | //****************************************************************************/ 39 | 40 | //#include "handler_p.h" 41 | //#include "manager_p.h" 42 | //#include "managers_p.h" 43 | //#include 44 | 45 | //QT_BEGIN_NAMESPACE 46 | 47 | //namespace Qt3DVirtualReality { 48 | 49 | //Handler::Handler() 50 | // //: m_logicManager(nullptr) 51 | //{ 52 | //} 53 | 54 | //void Handler::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) 55 | //{ 56 | // Q_UNUSED(change); 57 | // //m_logicManager->appendHandler(this); 58 | //} 59 | 60 | //void Handler::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) 61 | //{ 62 | // QBackendNode::sceneChangeEvent(e); 63 | //} 64 | 65 | //HandlerFunctor::HandlerFunctor(Manager *manager) 66 | // //: m_manager(manager) 67 | //{ 68 | //} 69 | 70 | //Qt3DCore::QBackendNode *HandlerFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const 71 | //{ 72 | // Handler *handler = m_manager->logicHandlerManager()->getOrCreateResource(change->subjectId()); 73 | // handler->setManager(m_manager); 74 | // return handler; 75 | //} 76 | 77 | //Qt3DCore::QBackendNode *HandlerFunctor::get(Qt3DCore::QNodeId id) const 78 | //{ 79 | // return m_manager->logicHandlerManager()->lookupResource(id); 80 | //} 81 | 82 | //void HandlerFunctor::destroy(Qt3DCore::QNodeId id) const 83 | //{ 84 | // m_manager->removeHandler(id); 85 | //} 86 | 87 | //} // namespace Qt3DVirtualReality 88 | 89 | //QT_END_NAMESPACE 90 | -------------------------------------------------------------------------------- /virtualreality/frontend/qvirtualrealityaspect.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #include "qvirtualrealityaspect.h" 16 | #include "qvirtualrealityaspect_p.h" 17 | #include "querytrackedobjectsjob_p.h" 18 | 19 | using namespace Qt3DCore; 20 | 21 | namespace Qt3DVirtualReality { 22 | 23 | QVirtualRealityAspectPrivate::QVirtualRealityAspectPrivate() 24 | : QAbstractAspectPrivate() 25 | , m_time(0) 26 | , m_initialized(false) 27 | , m_queryTrackedObjectsJob(new Qt3DVirtualReality::QueryTrackedObjectsJob) 28 | , m_hmd(nullptr) 29 | , m_apibackend(nullptr) 30 | { 31 | } 32 | 33 | void QVirtualRealityAspectPrivate::onEngineAboutToShutdown() 34 | { 35 | 36 | } 37 | 38 | void QVirtualRealityAspectPrivate::registerBackendTypes() 39 | { 40 | Q_Q(QVirtualRealityAspect); 41 | //q->registerBackendType(); 42 | //q->registerBackendType(); 43 | } 44 | 45 | /*! 46 | Constructs a new QVirtualRealityAspect instance with \a parent. 47 | */ 48 | QVirtualRealityAspect::QVirtualRealityAspect(QObject *parent) 49 | : QVirtualRealityAspect(*new QVirtualRealityAspectPrivate(), parent) {} 50 | 51 | QVirtualRealityAspect::QVirtualRealityAspect(QVirtualRealityAspectPrivate &dd, QObject *parent) 52 | : QAbstractAspect(dd, parent) 53 | { 54 | Q_D(QVirtualRealityAspect); 55 | setObjectName(QStringLiteral("Virtual Reality Aspect")); 56 | d->registerBackendTypes(); 57 | } 58 | 59 | QVirtualRealityAspect::~QVirtualRealityAspect() 60 | { 61 | } 62 | 63 | void QVirtualRealityAspect::setHeadmountedDisplay(QHeadMountedDisplay *hmd) 64 | { 65 | Q_D(QVirtualRealityAspect); 66 | d->m_hmd = hmd; 67 | } 68 | 69 | void QVirtualRealityAspect::setVirtualRealityApiBackend(QVirtualRealityApiBackend *apiBackend) 70 | { 71 | Q_D(QVirtualRealityAspect); 72 | d->m_apibackend = apiBackend; 73 | d->m_queryTrackedObjectsJob->setVirtualRealityApiBackend(d->m_apibackend); 74 | } 75 | 76 | QVector QVirtualRealityAspect::jobsToExecute(qint64 time) 77 | { 78 | Q_D(QVirtualRealityAspect); 79 | QVector jobs; 80 | jobs.append(d->m_queryTrackedObjectsJob); 81 | return jobs; 82 | } 83 | 84 | void QVirtualRealityAspect::onRegistered() 85 | { 86 | } 87 | 88 | void QVirtualRealityAspect::onUnregistered() 89 | { 90 | } 91 | 92 | ///*! \internal */ 93 | //void QVirtualRealityAspect::onEngineStartup() 94 | //{ 95 | // Q_D(QLogicAspect); 96 | // d->m_executor->setScene(d->m_arbiter->scene()); 97 | //} 98 | 99 | QVariant QVirtualRealityAspect::executeCommand(const QStringList &args) 100 | { 101 | return QVariant(); 102 | } 103 | 104 | } // namespace Qt3DVirtualReality 105 | 106 | QT_END_NAMESPACE 107 | 108 | QT3D_REGISTER_NAMESPACED_ASPECT("virtualreality", QT_PREPEND_NAMESPACE(Qt3DVirtualReality), QVirtualRealityAspect) 109 | 110 | -------------------------------------------------------------------------------- /virtualreality/qheadmounteddisplay.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QT3DHEADMOUNTEDDISPLAY_H 16 | #define QT3DHEADMOUNTEDDISPLAY_H 17 | 18 | #include "qvirtualrealityapi.h" 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | QT_BEGIN_NAMESPACE 31 | 32 | class QQmlIncubationController; 33 | 34 | namespace Qt3DCore { 35 | class QAbstractAspect; 36 | namespace Quick { 37 | class QQmlAspectEngine; 38 | } 39 | } 40 | 41 | namespace Qt3DRender { 42 | class QRenderAspect; 43 | class QCamera; 44 | } 45 | 46 | namespace Qt3DInput { 47 | class QInputAspect; 48 | } 49 | 50 | namespace Qt3DLogic { 51 | class QLogicAspect; 52 | } 53 | 54 | namespace Qt3DVirtualReality { 55 | 56 | class QVirtualRealityApiBackend; 57 | 58 | class QT3DVR_EXPORT QHeadMountedDisplay : public QObject /*: public QQuickItem*/ { 59 | Q_OBJECT 60 | Q_PROPERTY(QObject* surface READ surface NOTIFY surfaceChanged) 61 | Q_PROPERTY(QSize renderTargetSize READ renderTargetSize NOTIFY renderTargetSizeChanged) 62 | 63 | public: 64 | QHeadMountedDisplay(int hmdId, const QHeadMountedDisplayFormat &formathmd, QVirtualRealityApi *api, QVirtualRealityApiBackend *apibackend); 65 | ~QHeadMountedDisplay(); 66 | 67 | void registerAspect(Qt3DCore::QAbstractAspect *aspect); 68 | void registerAspect(const QString &name); 69 | 70 | void setSource(const QUrl &source); 71 | Qt3DCore::Quick::QQmlAspectEngine *engine() const; 72 | 73 | // Hmd specific 74 | qreal refreshRate(); 75 | qreal superSamplingFactor(); 76 | 77 | QObject* surface() const; 78 | QSize renderTargetSize() const; 79 | 80 | int timeUntilNextFrame(); 81 | QOpenGLContext *context(); 82 | signals: 83 | void requestRun(); 84 | void surfaceChanged(QSurface* surface); 85 | void renderTargetSizeChanged(QSize renderTargetSize); 86 | void sceneCreated(QObject *rootObject); 87 | 88 | public slots: 89 | void run(); 90 | 91 | private: 92 | void onSceneCreated(QObject *rootObject); 93 | void setWindowSurface(QObject *rootObject); 94 | 95 | QScopedPointer m_engine; 96 | 97 | // Aspects 98 | Qt3DRender::QRenderAspect *m_renderAspect; 99 | Qt3DInput::QInputAspect *m_inputAspect; 100 | Qt3DLogic::QLogicAspect *m_logicAspect; 101 | Qt3DVirtualReality::QVirtualRealityAspect *m_virtualRealityAspect; 102 | 103 | QUrl m_source; 104 | bool m_initialized; 105 | QPointer m_camera; 106 | QQmlIncubationController *m_incubationController; 107 | QVirtualRealityApi *m_api; 108 | QVirtualRealityApiBackend *m_apibackend; 109 | int m_hmdId; 110 | QOpenGLFramebufferObject *m_fbo; 111 | QOpenGLContext *m_context; 112 | QOffscreenSurface *m_surface; 113 | QObject *m_rootItem; 114 | }; 115 | 116 | } // Qt3DVirtualReality 117 | 118 | QT_END_NAMESPACE 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /virtualreality/handler_p.h: -------------------------------------------------------------------------------- 1 | ///**************************************************************************** 2 | //** 3 | //** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). 4 | //** Contact: https://www.qt.io/licensing/ 5 | //** 6 | //** This file is part of the Qt3D module of the Qt Toolkit. 7 | //** 8 | //** $QT_BEGIN_LICENSE:LGPL$ 9 | //** Commercial License Usage 10 | //** Licensees holding valid commercial Qt licenses may use this file in 11 | //** accordance with the commercial license agreement provided with the 12 | //** Software or, alternatively, in accordance with the terms contained in 13 | //** a written agreement between you and The Qt Company. For licensing terms 14 | //** and conditions see https://www.qt.io/terms-conditions. For further 15 | //** information use the contact form at https://www.qt.io/contact-us. 16 | //** 17 | //** GNU Lesser General Public License Usage 18 | //** Alternatively, this file may be used under the terms of the GNU Lesser 19 | //** General Public License version 3 as published by the Free Software 20 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 | //** packaging of this file. Please review the following information to 22 | //** ensure the GNU Lesser General Public License version 3 requirements 23 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 | //** 25 | //** GNU General Public License Usage 26 | //** Alternatively, this file may be used under the terms of the GNU 27 | //** General Public License version 2.0 or (at your option) the GNU General 28 | //** Public license version 3 or any later version approved by the KDE Free 29 | //** Qt Foundation. The licenses are as published by the Free Software 30 | //** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 | //** included in the packaging of this file. Please review the following 32 | //** information to ensure the GNU General Public License requirements will 33 | //** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 | //** https://www.gnu.org/licenses/gpl-3.0.html. 35 | //** 36 | //** $QT_END_LICENSE$ 37 | //** 38 | //****************************************************************************/ 39 | 40 | //#ifndef QT3DVIRTUALREALITY_HANDLER_H 41 | //#define QT3DVIRTUALREALITY_HANDLER_H 42 | 43 | //// 44 | //// W A R N I N G 45 | //// ------------- 46 | //// 47 | //// This file is not part of the Qt API. It exists for the convenience 48 | //// of other Qt classes. This header file may change from version to 49 | //// version without notice, or even be removed. 50 | //// 51 | //// We mean it. 52 | //// 53 | 54 | //#include 55 | //#include 56 | //#include 57 | 58 | //QT_BEGIN_NAMESPACE 59 | 60 | //namespace Qt3DVirtualReality { 61 | 62 | //class Handler : public Qt3DCore::QBackendNode 63 | //{ 64 | //public: 65 | // Handler(); 66 | 67 | // //void setManager(Manager *manager) { m_logicManager = manager; } 68 | // //Manager *logicManager() const { return m_logicManager; } 69 | 70 | //protected: 71 | // void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; 72 | 73 | //private: 74 | // void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; 75 | 76 | // //Manager *m_logicManager; 77 | //}; 78 | 79 | 80 | //class HandlerFunctor : public Qt3DCore::QBackendNodeMapper 81 | //{ 82 | //public: 83 | // //explicit HandlerFunctor(Manager *handler); 84 | 85 | // Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_OVERRIDE; 86 | // Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE; 87 | // void destroy(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE; 88 | 89 | //private: 90 | // //Manager *m_manager; 91 | //}; 92 | 93 | //} // namespace Qt3DVirtualReality 94 | 95 | //QT_END_NAMESPACE 96 | 97 | //#endif // QT3DVIRTUALREALITY_HANDLER_H 98 | -------------------------------------------------------------------------------- /virtualreality/vrbackends/openvr/virtualrealityapiopenvr.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #if(QT3DVR_COMPILE_WITH_OPENVR) 16 | #ifndef VIRTUALREALITYAPIOPENVR_H 17 | #define VIRTUALREALITYAPIOPENVR_H 18 | 19 | #include "../../qvirtualrealityapibackend.h" 20 | #include "openvr.h" 21 | class QSurfaceFormat; 22 | 23 | struct TrackedObjectModel { 24 | TrackedObjectModel(QVector t_vertices, QVector t_indices, QOpenGLTexture* t_texture) : 25 | vertices(t_vertices), indices(t_indices), texture(t_texture) {} 26 | 27 | QVector vertices; 28 | QVector indices; 29 | QOpenGLTexture* texture; 30 | }; 31 | 32 | class VirtualRealityApiOpenVR : public Qt3DVirtualReality::QVirtualRealityApiBackend 33 | { 34 | public: 35 | static bool isRuntimeInstalled(); 36 | VirtualRealityApiOpenVR(); 37 | bool isHmdPresent(); 38 | 39 | void initialize(); 40 | void shutdown(); 41 | bool bindFrambufferObject(int hmdId); 42 | 43 | qreal refreshRate(int hmdId) const; 44 | QMatrix4x4 headPose(int hmdId); 45 | QSize getRenderTargetSize(); 46 | 47 | int timeUntilNextFrame(); 48 | 49 | void swapToHeadset(); 50 | 51 | void getEyeMatrices(QMatrix4x4 &leftEye, QMatrix4x4 &rightEye); 52 | 53 | void getProjectionMatrices(QMatrix4x4 &leftProjection, QMatrix4x4 &rightProjection); 54 | 55 | QList currentlyTrackedObjects(); 56 | void getTrackedObject(int id, QMatrix4x4 &transform); 57 | TrackedObjectType getTrackedObjectType(int id); 58 | void getTrackedObjectModel(int id, QVector &vertices, QVector &indices, QOpenGLTexture *texture); 59 | 60 | void getMirrorTexture(QOpenGLTexture *outMirrorTexture); 61 | 62 | bool isTriggerTmp(); 63 | private: 64 | QOpenGLFramebufferObject *m_fbo; 65 | double m_sensorSampleTime; 66 | long long m_frameIndex; 67 | vr::IVRSystem *m_hmd; 68 | std::string m_driver; 69 | std::string m_display; 70 | vr::TrackedDevicePose_t m_trackedDevicePose[ vr::k_unMaxTrackedDeviceCount ]; 71 | QMatrix4x4 m_devicePose[ vr::k_unMaxTrackedDeviceCount ]; 72 | bool m_showTrackedDevice[ vr::k_unMaxTrackedDeviceCount ]; 73 | 74 | int m_trackedControllerCount; 75 | int m_trackedControllerCountLast; 76 | int m_validPoseCount; 77 | int m_validPoseCountLast; 78 | std::string m_poseClasses; // what classes we saw poses for this frame 79 | char m_devClassChar[ vr::k_unMaxTrackedDeviceCount ]; // for each device, a character representing its class 80 | 81 | QMatrix4x4 m_hmdPose; 82 | QMatrix4x4 m_eyePosLeft; 83 | QMatrix4x4 m_eyePosRight; 84 | 85 | bool m_isTrigger; 86 | 87 | QMatrix4x4 getHmdMatrixProjectionEye(vr::Hmd_Eye nEye); 88 | QMatrix4x4 getHmdMatrixPoseEye(vr::Hmd_Eye nEye); 89 | QMatrix4x4 getCurrentViewMatrix(vr::Hmd_Eye nEye); 90 | void updateHmdMatrixPose(); 91 | QMatrix4x4 convertSteamVrMatrixToQMatrix4x4(const vr::HmdMatrix34_t matPose); 92 | QMatrix4x4 convertSteamVrMatrixToQMatrix4x4(const vr::HmdMatrix44_t matPose); 93 | void processVrEvent(const vr::VREvent_t &event); 94 | void setupCameras(); 95 | bool m_poseNewEnough; //TO DO: openvr in example only updates poses once a frame 96 | 97 | QMap m_models; 98 | }; 99 | 100 | #endif 101 | #endif 102 | -------------------------------------------------------------------------------- /vr-window/StereoFrameGraph.qml: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the Qt3D module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:BSD$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** BSD License Usage 18 | ** Alternatively, you may use this file under the terms of the BSD license 19 | ** as follows: 20 | ** 21 | ** "Redistribution and use in source and binary forms, with or without 22 | ** modification, are permitted provided that the following conditions are 23 | ** met: 24 | ** * Redistributions of source code must retain the above copyright 25 | ** notice, this list of conditions and the following disclaimer. 26 | ** * Redistributions in binary form must reproduce the above copyright 27 | ** notice, this list of conditions and the following disclaimer in 28 | ** the documentation and/or other materials provided with the 29 | ** distribution. 30 | ** * Neither the name of The Qt Company Ltd nor the names of its 31 | ** contributors may be used to endorse or promote products derived 32 | ** from this software without specific prior written permission. 33 | ** 34 | ** 35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 46 | ** 47 | ** $QT_END_LICENSE$ 48 | ** 49 | ****************************************************************************/ 50 | 51 | import Qt3D.Core 2.0 52 | import Qt3D.Render 2.0 53 | 54 | Viewport { 55 | 56 | property alias leftCamera: leftCameraSelector.camera 57 | property alias rightCamera: rightCameraSelector.camera 58 | // property alias window: surfaceSelector.surface 59 | 60 | RenderSurfaceSelector { 61 | id: surfaceSelector 62 | //surface: _hmd.surface 63 | externalRenderTargetSize: _hmd.renderTargetSize 64 | 65 | // ColorMask is reset by default 66 | // By default reset to the default if not specified 67 | ClearBuffers { 68 | buffers: ClearBuffers.ColorDepthBuffer 69 | clearColor: "white" //Qt.rgba(0.2,0.9,0.9,0.5) 70 | NoDraw {} // We just want to clear the buffers 71 | } 72 | 73 | // Draw with left eye 74 | CameraSelector { 75 | id: leftCameraSelector 76 | Viewport { 77 | RenderStateSet { 78 | renderStates: [ 79 | DepthTest { depthFunction: DepthTest.Less } 80 | ] 81 | } 82 | normalizedRect: Qt.rect(0,0,0.5,1) 83 | } 84 | } 85 | 86 | // Draw with right eye 87 | CameraSelector { 88 | id: rightCameraSelector 89 | Viewport { 90 | RenderStateSet { 91 | renderStates: [ 92 | DepthTest { depthFunction: DepthTest.Less } 93 | ] 94 | } 95 | normalizedRect: Qt.rect(0.5,0,0.5,1) 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /vr-window/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1 2 | import Qt3D.Core 2.0 3 | import Qt3D.Render 2.0 4 | import Qt3D.Input 2.0 5 | import Qt3D.Extras 2.0 6 | 7 | import QtQuick 2.0 as QQ2 8 | 9 | import vr 2.0 10 | 11 | Entity { 12 | id: root 13 | 14 | components: RenderSettings { 15 | StereoFrameGraph { 16 | id: stereoFrameGraph 17 | leftCamera: vrCam.leftCamera 18 | rightCamera: vrCam.rightCamera 19 | } 20 | } 21 | Item { 22 | id: cameraProps 23 | readonly property real cameraRadius: obstaclesRepeater.radius - 50 24 | readonly property vector3d circlePosition: Qt.vector3d(cameraRadius * Math.cos(circleRotation), 0.0, cameraRadius * Math.sin(circleRotation)) 25 | readonly property vector3d tan: circlePosition.crossProduct(Qt.vector3d(0, 1, 0).normalized()) 26 | property real circleRotation: 0 27 | 28 | QQ2.NumberAnimation { 29 | target: cameraProps 30 | property: "circleRotation" 31 | from: 0; to: Math.PI * 2 32 | duration: 10000 33 | loops: QQ2.Animation.Infinite 34 | running: false 35 | } 36 | } 37 | // Camera 38 | VrCamera { 39 | id: vrCam 40 | //offset: Qt.vector3d(80.0,-90.0,0.0) 41 | //offsetOrientation: 42 | //offset: cameraProps.circlePosition.plus(Qt.vector3d(0, 45 * Math.sin(cameraProps.circleRotation * 2), 0)).plus(cameraProps.tan.times(-2)) 43 | } 44 | 45 | // Torus obsctacles 46 | NodeInstantiator { 47 | id: obstaclesRepeater 48 | model: 40 49 | readonly property real radius: 3.0 50 | readonly property real det: 1.0 / model 51 | delegate: Entity { 52 | components: [ 53 | TorusMesh { 54 | radius: 0.5 55 | minorRadius: 0.05 56 | rings: 100 57 | slices: 20 58 | }, 59 | Transform { 60 | id: transform 61 | readonly property real angle: Math.PI * 2.0 * index * obstaclesRepeater.det 62 | translation: Qt.vector3d(obstaclesRepeater.radius * Math.cos(transform.angle), 63 | 0.0, 64 | obstaclesRepeater.radius * Math.sin(transform.angle)) 65 | rotation: fromAxisAndAngle(Qt.vector3d(0.0, 1.0, 0.0), -transform.angle * 180 / Math.PI) 66 | }, 67 | PhongMaterial { 68 | diffuse: Qt.rgba(Math.abs(Math.cos(transform.angle)), 204 / 255, 75 / 255, 1) 69 | specular: "white" 70 | shininess: 20.0 71 | } 72 | ] 73 | } 74 | } 75 | NodeInstantiator { 76 | id: trackedObjectsRepeater 77 | // TO DO: a model does not yet work here (array with indices). temporarily using a number 78 | model: 4 // default: 1 -> head, 2&3 -> base station, 4&5 -> controller/hands 79 | // different setup? : 1&2 -> base stations, 3&4 -> controllers, 5 -> ? 80 | delegate: Entity { 81 | Timer { 82 | running: true 83 | repeat: true 84 | interval: 1 85 | onTriggered: { 86 | // this is a temporary workaround and there are no property change events here 87 | trackedTransform.matrix = vrCam.trackedObjectMatrixTmp(index+1) 88 | } 89 | } 90 | components: [ 91 | TrackedObjectMesh { 92 | trackedObjectId: index+1 93 | }, 94 | // TorusMesh { 95 | // radius: 0.1 96 | // minorRadius: 0.05 97 | // rings: 100 98 | // slices: 20 99 | // }, 100 | Transform { 101 | id: trackedTransform 102 | }, 103 | PhongMaterial { 104 | specular: "white" 105 | ambient: Qt.rgba(1.0*index,1.0*(index-1.0),0.0,1.0) 106 | shininess: 20.0 107 | } 108 | ] 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /virtualreality/qvirtualrealityapibackend.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QT3DVIRTUALREALITYAPIBACKEND_H 16 | #define QT3DVIRTUALREALITYAPIBACKEND_H 17 | 18 | #include "qt3dvr_global.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | QT_BEGIN_NAMESPACE 27 | 28 | namespace Qt3DVirtualReality { 29 | 30 | /*! 31 | * \brief The QVirtualRealityApiBackend class hides the concrete implementation for a vr headset. 32 | * It should make it easy to add more Virtual reality devices. However, becaus we can't look into the future 33 | * this interface might be extended with new features. 34 | */ 35 | class QVirtualRealityApiBackend 36 | { 37 | public: 38 | enum TrackedObjectType { 39 | Head, 40 | LeftHand, 41 | RightHand, 42 | LighthouseOrSensor, 43 | Other 44 | }; 45 | virtual bool isHmdPresent() = 0; 46 | 47 | /*! 48 | * \brief initialize is to initialize the concrete vr framework. 49 | * This is called while correct opengl context is current and already initialized 50 | * It is also known, that the runtime is installed at this point 51 | */ 52 | virtual void initialize() = 0; 53 | virtual void shutdown() = 0; 54 | /*! 55 | * \brief bindFrambufferObject for rendering. Has to bind the framebuffer of the current 56 | * headset for rendering. 57 | * \return success 58 | */ 59 | virtual bool bindFrambufferObject(int hmdId) = 0; 60 | 61 | /*! 62 | * \brief refreshRate of the selected headset. E.g. 90 Hz 63 | * \param hmdId 64 | * \return 65 | */ 66 | virtual qreal refreshRate(int hmdId) const = 0; 67 | 68 | /*! 69 | * \brief headPose estimated for the next frame 70 | * //TO DO: add estimation parameters. 71 | * It is likely that this function never returns the same headpose twice. 72 | * \param hmdId 73 | * \return 74 | */ 75 | virtual QMatrix4x4 headPose(int hmdId) = 0; 76 | 77 | //TO DO: introduce getRecomendedSize() 78 | virtual QSize getRenderTargetSize() = 0; 79 | 80 | virtual int timeUntilNextFrame() = 0; 81 | virtual void swapToHeadset() = 0; 82 | 83 | /*! 84 | * \brief getEyeMatrices without projection applied. Relative to transform-origin. 85 | * //TO DO: Add transform origin concept. Introduce a way to get interpupilar distance and offset to headPose.? 86 | * \param leftEye 87 | * \param rightEye 88 | */ 89 | virtual void getEyeMatrices(QMatrix4x4 &leftEye, QMatrix4x4 &rightEye) = 0; 90 | 91 | /*! 92 | * \brief getProjectionMatrices get correct projection matrix for each eye. These can be asymetrical. 93 | * \param leftProjection 94 | * \param rightProjection 95 | */ 96 | virtual void getProjectionMatrices(QMatrix4x4 &leftProjection, QMatrix4x4 &rightProjection) = 0; 97 | 98 | virtual QList currentlyTrackedObjects() = 0; 99 | virtual void getTrackedObject(int id, QMatrix4x4 &transform) = 0; 100 | virtual TrackedObjectType getTrackedObjectType(int id) = 0; 101 | virtual void getTrackedObjectModel(int id, QVector &vertices, QVector &indices, QOpenGLTexture *texture) = 0; 102 | 103 | virtual bool isTriggerTmp() = 0; 104 | /*! 105 | * \brief getMirrorTexture 106 | * Used to get a texture witch can be rendered in another window/thread. 107 | * Some SDKs will not automaticly fill the QOpenGLTextue itself but return an OpenGL texture name. 108 | * This method has to be called every time the mirror should update to allow copying in this case. 109 | * It might work for some SDKs, but not for others. 110 | * \param outMirrorTexture 111 | */ 112 | virtual void getMirrorTexture(QOpenGLTexture *outMirrorTexture) = 0; 113 | 114 | }; 115 | 116 | } 117 | 118 | QT_END_NAMESPACE 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /virtualreality/vrbackends/ovr/framebufferovr.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #if(QT3DVR_COMPILE_WITH_OCULUSVR) 16 | #include "framebufferovr.h" 17 | #include 18 | #include 19 | #include 20 | 21 | class FramebufferOvr 22 | { 23 | GLuint m_colorAttachment; 24 | GLuint m_depthBuffer; 25 | GLuint m_framebuffer; 26 | QOpenGLFunctions_3_2_Core *m_funcs; 27 | public: 28 | FramebufferOvr(GLuint colorAttachment0TextureId, GLuint depthBufferRenderbufferId, QOpenGLFunctions_3_2_Core *funcs) 29 | : m_colorAttachment(colorAttachment0TextureId) 30 | , m_depthBuffer(depthBufferRenderbufferId) 31 | , m_funcs(funcs) 32 | { 33 | m_funcs->glGenFramebuffers(1, &m_framebuffer); 34 | m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); 35 | 36 | m_funcs->glBindTexture(GL_TEXTURE_2D, m_colorAttachment); 37 | m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 38 | m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 39 | m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 40 | m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 41 | 42 | if(depthBufferRenderbufferId > 0) { 43 | Q_ASSERT(funcs->glIsRenderbuffer(m_depthBuffer)); 44 | funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 45 | GL_RENDERBUFFER, m_depthBuffer); 46 | } 47 | int sampleCount = 1; 48 | GLenum texTarget = (sampleCount > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; 49 | m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texTarget, m_colorAttachment, 0); 50 | 51 | m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0); 52 | } 53 | ~FramebufferOvr() { 54 | 55 | } 56 | 57 | GLuint getTextureId() { 58 | return m_colorAttachment; 59 | } 60 | void bind() { 61 | m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); 62 | } 63 | }; 64 | 65 | OvrSwapChain::OvrSwapChain( ovrSession session, QSize size) 66 | :m_session(session), 67 | m_texSize(size), 68 | m_textureChain(0) 69 | { 70 | m_funcs = QOpenGLContext::currentContext()->versionFunctions(); 71 | if(!m_funcs) 72 | { 73 | qDebug() << "Could not get OpenGLFunctions 3.2"; 74 | return; 75 | } 76 | ovrTextureSwapChainDesc desc = {}; 77 | desc.Type = ovrTexture_2D; 78 | desc.ArraySize = 1; 79 | desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; 80 | desc.Width = m_texSize.width(); 81 | desc.Height = m_texSize.height(); 82 | desc.MipLevels = 1; 83 | desc.SampleCount = 1; 84 | desc.StaticImage = ovrFalse; 85 | 86 | // We have to use the internally created texture from this method. 87 | // No way to use a native QOpenGLTexture for rendering, without copying it. 88 | ovrResult result = ovr_CreateTextureSwapChainGL(m_session, &desc, &m_textureChain); 89 | 90 | if(!OVR_SUCCESS(result)) 91 | { 92 | ovrErrorInfo inf; 93 | ovr_GetLastErrorInfo(&inf); 94 | qDebug() << inf.ErrorString; 95 | } 96 | int length = 0; 97 | ovr_GetTextureSwapChainLength(m_session, m_textureChain, &length); 98 | 99 | if(OVR_SUCCESS(result)) 100 | { 101 | GLuint depthBufferId; 102 | m_funcs->glGenRenderbuffers(1, &depthBufferId); 103 | m_funcs->glBindRenderbuffer(GL_RENDERBUFFER, depthBufferId); 104 | Q_ASSERT(m_funcs->glIsRenderbuffer(depthBufferId)); 105 | m_funcs->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, m_texSize.width(), m_texSize.height()); 106 | 107 | for (int i = 0; i < length; ++i) 108 | { 109 | GLuint chainTextureId; 110 | ovr_GetTextureSwapChainBufferGL(m_session, m_textureChain, i, &chainTextureId); 111 | m_framebuffers.push_back(new FramebufferOvr(chainTextureId, depthBufferId, m_funcs)); 112 | } 113 | } 114 | 115 | if (!m_textureChain) 116 | { 117 | ovrErrorInfo inf; 118 | ovr_GetLastErrorInfo(&inf); 119 | qDebug() << inf.ErrorString; 120 | } 121 | } 122 | 123 | OvrSwapChain::~OvrSwapChain() 124 | { 125 | if (m_textureChain) 126 | { 127 | ovr_DestroyTextureSwapChain(m_session, m_textureChain); 128 | m_textureChain = nullptr; 129 | } 130 | for(QVector::iterator iter(m_framebuffers.begin()) ; iter != m_framebuffers.end() ; ++iter) { 131 | delete *iter; 132 | } 133 | } 134 | 135 | QSize OvrSwapChain::size() const 136 | { 137 | return m_texSize; 138 | } 139 | 140 | void OvrSwapChain::commit() 141 | { 142 | Q_ASSERT(m_textureChain != nullptr); 143 | ovr_CommitTextureSwapChain(m_session, m_textureChain); 144 | } 145 | 146 | const ovrTextureSwapChain& OvrSwapChain::ovrTextureChain() const 147 | { 148 | return m_textureChain; 149 | } 150 | 151 | void OvrSwapChain::bindCurrentChainIndexFramebuffer() 152 | { 153 | Q_ASSERT(m_textureChain != nullptr); 154 | int curIndex; 155 | ovr_GetTextureSwapChainCurrentIndex(m_session, m_textureChain, &curIndex); 156 | m_framebuffers[curIndex]->bind(); 157 | } 158 | 159 | void OvrSwapChain::bindFramebuffer(int index) 160 | { 161 | //nyi 162 | } 163 | 164 | int OvrSwapChain::chainLength() const 165 | { 166 | //nyi 167 | return 0; 168 | } 169 | #endif 170 | -------------------------------------------------------------------------------- /virtualreality/frontend/qvirtualrealitycamera.h: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #ifndef QVRCAMERA 16 | #define QVRCAMERA 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include //TO DO: THis include is only for transforms over camera 22 | 23 | QT_BEGIN_NAMESPACE 24 | 25 | namespace Qt3DVirtualReality { 26 | 27 | class QVirtualrealityCamera : public Qt3DCore::QEntity 28 | { 29 | Q_OBJECT 30 | Q_PROPERTY(Qt3DRender::QCameraLens * leftCameraLens READ leftCameraLens NOTIFY leftCameraLensChanged) 31 | Q_PROPERTY(Qt3DRender::QCameraLens * rightCameraLens READ rightCameraLens NOTIFY rightCameraLensChanged) 32 | Q_PROPERTY(Qt3DCore::QEntity * leftCamera READ leftCamera NOTIFY leftCameraChanged) 33 | Q_PROPERTY(Qt3DCore::QEntity * rightCamera READ rightCamera NOTIFY rightCameraChanged) 34 | Q_PROPERTY(float disparity READ disparity NOTIFY disparityChanged) 35 | // Q_PROPERTY(QVector3D headPosPredicted READ headPosPredicted NOTIFY headPosPredictedChanged) 36 | // Q_PROPERTY(QQuaternion headOrientationPredicted READ headOrientationPredicted NOTIFY headOrientationPredictedChanged) 37 | Q_PROPERTY(QVector3D offset READ offset WRITE setOffset NOTIFY offsetChanged) 38 | Q_PROPERTY(QQuaternion offsetOrientation READ offsetOrientation WRITE setOffsetOrientation NOTIFY offsetOrientationChanged) 39 | // Q_PROPERTY(QMatrix4x4 viewMatrixPredicted READ viewMatrixPredicted NOTIFY viewMatrixPredictedChanged) 40 | Q_PROPERTY(float playerHeight READ playerHeight NOTIFY playerHeightChanged) 41 | Q_PROPERTY(QRectF leftNormalizedViewportRect READ leftNormalizedViewportRect WRITE setLeftNormalizedViewportRect NOTIFY leftNormalizedViewportRectChanged) 42 | Q_PROPERTY(QRectF rightNormalizedViewportRect READ rightNormalizedViewportRect WRITE setRightNormalizedViewportRect NOTIFY rightNormalizedViewportRectChanged) 43 | public: 44 | QVirtualrealityCamera(QNode *parent = nullptr); 45 | 46 | Qt3DCore::QEntity * leftCamera(); 47 | Qt3DCore::QEntity * rightCamera(); 48 | 49 | void setProjections(const QMatrix4x4& leftProjection, const QMatrix4x4& rightProjection); 50 | void update(const QMatrix4x4 &viewLeft, const QMatrix4x4 &viewRight); 51 | float disparity() const; 52 | 53 | // QMatrix4x4 headPosPredicted() const; 54 | // QMatrix4x4 headOrientationPredicted() const; 55 | QVector3D offset() const; 56 | // QMatrix4x4 viewMatrixPredicted() const; 57 | float playerHeight() const; 58 | QRectF leftNormalizedViewportRect() const; 59 | QRectF rightNormalizedViewportRect() const; 60 | QQuaternion offsetOrientation() const; 61 | 62 | // Transforms should be handled by special "VrTransform" Class, which has two backend nodes (one in renderaspect and one in vr aspect). 63 | // Then it should always uptade before rendering. For the moment, this will create a minimium viable product. 64 | Q_INVOKABLE QMatrix4x4 trackedObjectMatrixTmp(int trackedObjectId); 65 | Q_INVOKABLE QList trackedObjectsTmp(); 66 | void setVrBackendTmp(QVirtualRealityApiBackend* backend); //only for trackedObjectMatrixTmp 67 | Q_INVOKABLE bool isTriggerTmp(); 68 | Qt3DRender::QCameraLens * leftCameraLens() const 69 | { 70 | return m_leftCameraLens; 71 | } 72 | 73 | Qt3DRender::QCameraLens * rightCameraLens() const 74 | { 75 | return m_rightCameraLens; 76 | } 77 | 78 | public Q_SLOTS: 79 | 80 | void setOffset(QVector3D offset); 81 | void setLeftNormalizedViewportRect(QRectF leftNormalizedViewportRect); 82 | void setRightNormalizedViewportRect(QRectF rightNormalizedViewportRect); 83 | void setOffsetOrientation(QQuaternion offsetOrientation); 84 | 85 | Q_SIGNALS: 86 | 87 | void disparityChanged(float disparity); 88 | // void headPosPredictedChanged(QVector3D headPosPredicted); 89 | // void headOrientationPredictedChanged(QMatrix4x4 headOrientationPredicted); 90 | void offsetChanged(QVector3D offset); 91 | // void viewMatrixPredictedChanged(QMatrix4x4 viewMatrixPredicted); 92 | void playerHeightChanged(float playerHeight); 93 | void leftNormalizedViewportRectChanged(QRectF leftNormalizedViewportRect); 94 | void rightNormalizedViewportRectChanged(QRectF rightNormalizedViewportRect); 95 | void leftCameraChanged(Qt3DCore::QEntity * leftCamera); 96 | void rightCameraChanged(Qt3DCore::QEntity * rightCamera); 97 | void offsetOrientationChanged(QQuaternion offsetOrientation); 98 | void leftCameraLensChanged(Qt3DRender::QCameraLens * leftCameraLens); 99 | void rightCameraLensChanged(Qt3DRender::QCameraLens * rightCameraLens); 100 | 101 | private: 102 | Qt3DRender::QCameraLens *m_leftCameraLens; 103 | Qt3DRender::QCameraLens *m_rightCameraLens; 104 | Qt3DCore::QTransform *m_leftTransform; 105 | Qt3DCore::QTransform *m_rightTransform; 106 | Qt3DCore::QEntity *m_leftCamera; 107 | Qt3DCore::QEntity *m_rightCamera; 108 | float m_disparity; 109 | // QVector3D m_headPosPredicted; 110 | // QQuaternion m_headOrientationPredicted; 111 | QVector3D m_offset; 112 | // QMatrix4x4 m_viewMatrixPredicted; 113 | float m_playerHeight; 114 | QRectF m_leftNormalizedViewportRect; 115 | QRectF m_rightNormalizedViewportRect; 116 | QQuaternion m_offsetOrientation; 117 | QVirtualRealityApiBackend *m_apibackend; //TO DO: tmp 118 | 119 | }; 120 | 121 | } // namespace Qt3DVirtualReality 122 | 123 | QT_END_NAMESPACE 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /virtualreality/frontend/qvirtualrealitycamera.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #include "qvirtualrealitycamera.h" 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | namespace Qt3DVirtualReality { 25 | 26 | QVirtualrealityCamera::QVirtualrealityCamera(QNode *parent) 27 | :m_leftCamera(new Qt3DCore::QEntity(parent)), 28 | m_rightCamera(new Qt3DCore::QEntity(parent)), // TODO: Delete? 29 | m_leftCameraLens(new Qt3DRender::QCameraLens(parent)),//m_leftCamera)), 30 | m_rightCameraLens(new Qt3DRender::QCameraLens(parent)),//m_rightCamera)), 31 | m_leftTransform(new Qt3DCore::QTransform(parent)),//m_leftCamera)), 32 | m_rightTransform(new Qt3DCore::QTransform(parent)),//m_rightCamera)), 33 | m_apibackend(nullptr) 34 | { 35 | m_leftCamera->addComponent(m_leftCameraLens); 36 | m_rightCamera->addComponent(m_rightCameraLens); 37 | m_leftCamera->addComponent(m_leftTransform); 38 | m_rightCamera->addComponent(m_rightTransform); 39 | 40 | // m_leftCamera->setAspectRatio(9.0/16.0); 41 | // m_rightCamera->setAspectRatio(9.0/16.0); 42 | // m_leftCamera->setNearPlane(0.1); 43 | // m_rightCamera->setNearPlane(0.1); 44 | // m_leftCamera->setFarPlane(1000.0f); 45 | // m_rightCamera->setFarPlane(1000.0f); 46 | // m_leftCamera->setUpVector(QVector3D(0.0f,1.0f,0.0f)); 47 | // m_rightCamera->setUpVector(QVector3D(0.0f,1.0f,0.0f)); 48 | // m_leftCamera->setFieldOfView(100.0); 49 | // m_rightCamera->setFieldOfView(100.0); 50 | // //m_leftCamera->set 51 | Q_EMIT leftCameraChanged(m_leftCamera); 52 | Q_EMIT rightCameraChanged(m_rightCamera); 53 | } 54 | 55 | Qt3DCore::QEntity *QVirtualrealityCamera::leftCamera() 56 | { 57 | return m_leftCamera; 58 | } 59 | 60 | Qt3DCore::QEntity *QVirtualrealityCamera::rightCamera() 61 | { 62 | return m_rightCamera; 63 | } 64 | 65 | void QVirtualrealityCamera::setProjections(const QMatrix4x4 &leftProjection, const QMatrix4x4 &rightProjection) 66 | { 67 | m_leftCameraLens->setProjectionMatrix(leftProjection); 68 | m_rightCameraLens->setProjectionMatrix(rightProjection); 69 | Q_EMIT leftCameraLensChanged(m_leftCameraLens); 70 | Q_EMIT rightCameraLensChanged(m_rightCameraLens); 71 | } 72 | 73 | void QVirtualrealityCamera::update(const QMatrix4x4 &viewLeft, const QMatrix4x4 &viewRight) 74 | { 75 | // Vector3f finalUp = rot.Transform(Vector3f(0, 1, 0)); 76 | // Vector3f finalForward = rot.Transform(Vector3f(0, 0, -1)); 77 | // Matrix4f view = Matrix4f::LookAtRH(pos, pos + finalForward, finalUp); 78 | //QMatrix4x4 viewLeft; 79 | //viewLeft.lookAt(leftPos, leftPos + leftOrient.rotatedVector(QVector3D(0.0,0.0,1.0)), leftOrient.rotatedVector(QVector3D(0.0,1.0,0.0))); 80 | QMatrix4x4 l(viewLeft); 81 | QMatrix4x4 r(viewRight); 82 | l.translate(-m_offset); 83 | r.translate(-m_offset); 84 | m_leftTransform->setMatrix(l); 85 | //QMatrix4x4 viewRight; 86 | //viewRight.lookAt(rightPos, rightPos + rightOrient.rotatedVector(QVector3D(0.0,0.0,1.0)), rightOrient.rotatedVector(QVector3D(0.0,1.0,0.0))); 87 | m_rightTransform->setMatrix(r); 88 | 89 | 90 | // Matrix4f view = Matrix4f(orientation.Inverted()) * Matrix4f::Translation(-WorldEyePos); 91 | // QMatrix4x4 matL1, matL2; 92 | // matL1.rotate(leftOrient.inverted()); 93 | // matL2.translate(-leftPos); 94 | // QMatrix4x4 matR1, matR2; 95 | // matR1.rotate(rightOrient.inverted()); 96 | // matR2.translate(-rightPos); 97 | // m_leftTransform->setMatrix(matL1*matL2); 98 | // m_rightTransform->setMatrix(matR1*matR2); 99 | 100 | // m_leftTransform->setMatrix(leftOrient.inverted()*-leftPos); 101 | // m_leftTransform->setMatrix(leftOrient.inverted()*-leftPos); 102 | // m_leftTransform->setRotation(leftOrient.inverted()); 103 | // m_leftTransform->setTranslation(-leftPos); 104 | // m_rightTransform->setRotation(rightOrient.inverted()); 105 | // m_rightTransform->setTranslation(-rightPos); 106 | } 107 | 108 | float QVirtualrealityCamera::disparity() const 109 | { 110 | return m_disparity; 111 | } 112 | 113 | //QMatrix4x4 QVirtualrealityCamera::headPosPredicted() const 114 | //{ 115 | // return m_headPosPredicted; 116 | //} 117 | 118 | //QMatrix4x4 QVirtualrealityCamera::headOrientationPredicted() const 119 | //{ 120 | // return m_headOrientationPredicted; 121 | //} 122 | 123 | QVector3D QVirtualrealityCamera::offset() const 124 | { 125 | return m_offset; 126 | } 127 | 128 | //QMatrix4x4 QVirtualrealityCamera::viewMatrixPredicted() const 129 | //{ 130 | // return m_viewMatrixPredicted; 131 | //} 132 | 133 | float QVirtualrealityCamera::playerHeight() const 134 | { 135 | return m_playerHeight; 136 | } 137 | 138 | QRectF QVirtualrealityCamera::leftNormalizedViewportRect() const 139 | { 140 | return m_leftNormalizedViewportRect; 141 | } 142 | 143 | QRectF QVirtualrealityCamera::rightNormalizedViewportRect() const 144 | { 145 | return m_rightNormalizedViewportRect; 146 | } 147 | 148 | QQuaternion QVirtualrealityCamera::offsetOrientation() const 149 | { 150 | return m_offsetOrientation; 151 | } 152 | 153 | QMatrix4x4 QVirtualrealityCamera::trackedObjectMatrixTmp(int trackedObjectId) 154 | { 155 | if(!m_apibackend) return QMatrix4x4(); 156 | QMatrix4x4 mat; 157 | m_apibackend->getTrackedObject(trackedObjectId, mat); 158 | QMatrix4x4 off; 159 | off.translate(m_offset); 160 | return off*mat; 161 | } 162 | 163 | QList QVirtualrealityCamera::trackedObjectsTmp() 164 | { 165 | if(!m_apibackend) return QList(); 166 | return m_apibackend->currentlyTrackedObjects(); 167 | } 168 | 169 | bool Qt3DVirtualReality::QVirtualrealityCamera::isTriggerTmp() 170 | { 171 | 172 | if(!m_apibackend) return false; 173 | QMatrix4x4 mat; 174 | return m_apibackend->isTriggerTmp(); 175 | } 176 | 177 | void QVirtualrealityCamera::setVrBackendTmp(QVirtualRealityApiBackend *backend) 178 | { 179 | m_apibackend = backend; 180 | } 181 | 182 | void QVirtualrealityCamera::setOffset(QVector3D offset) 183 | { 184 | if (m_offset == offset) 185 | return; 186 | 187 | m_offset = offset; 188 | Q_EMIT offsetChanged(offset); 189 | } 190 | 191 | void QVirtualrealityCamera::setLeftNormalizedViewportRect(QRectF leftNormalizedViewportRect) 192 | { 193 | if (m_leftNormalizedViewportRect == leftNormalizedViewportRect) 194 | return; 195 | 196 | m_leftNormalizedViewportRect = leftNormalizedViewportRect; 197 | Q_EMIT leftNormalizedViewportRectChanged(leftNormalizedViewportRect); 198 | } 199 | 200 | void QVirtualrealityCamera::setRightNormalizedViewportRect(QRectF rightNormalizedViewportRect) 201 | { 202 | if (m_rightNormalizedViewportRect == rightNormalizedViewportRect) 203 | return; 204 | 205 | m_rightNormalizedViewportRect = rightNormalizedViewportRect; 206 | Q_EMIT rightNormalizedViewportRectChanged(rightNormalizedViewportRect); 207 | } 208 | 209 | void QVirtualrealityCamera::setOffsetOrientation(QQuaternion offsetOrientation) 210 | { 211 | if (m_offsetOrientation == offsetOrientation) 212 | return; 213 | 214 | m_offsetOrientation = offsetOrientation; 215 | Q_EMIT offsetOrientationChanged(offsetOrientation); 216 | } 217 | 218 | } // namespace Qt3DVirtualReality 219 | 220 | QT_END_NAMESPACE 221 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /virtualreality/vrbackends/ovr/virtualrealityapiovr.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #if(QT3DVR_COMPILE_WITH_OCULUSVR) 16 | #include "virtualrealityapiovr.h" 17 | #include "framebufferovr.h" 18 | 19 | #include "Extras/OVR_Math.h" 20 | #include "OVR_CAPI_GL.h" 21 | 22 | using namespace OVR; 23 | 24 | #if defined(_WIN32) 25 | #include // for GetDefaultAdapterLuid 26 | //#pragma comment(lib, "dxgi.lib") 27 | #endif 28 | 29 | 30 | static ovrGraphicsLuid GetDefaultAdapterLuid() 31 | { 32 | ovrGraphicsLuid luid = ovrGraphicsLuid(); 33 | 34 | #if defined(_WIN32) 35 | IDXGIFactory* factory = nullptr; 36 | 37 | if (SUCCEEDED(CreateDXGIFactory(IID_PPV_ARGS(&factory)))) 38 | { 39 | IDXGIAdapter* adapter = nullptr; 40 | 41 | if (SUCCEEDED(factory->EnumAdapters(0, &adapter))) 42 | { 43 | DXGI_ADAPTER_DESC desc; 44 | 45 | adapter->GetDesc(&desc); 46 | memcpy(&luid, &desc.AdapterLuid, sizeof(luid)); 47 | adapter->Release(); 48 | } 49 | 50 | factory->Release(); 51 | } 52 | #endif 53 | 54 | return luid; 55 | } 56 | 57 | bool VirtualRealityApiOvr::isRuntimeInstalled() 58 | { 59 | ovrResult result = ovr_Initialize(nullptr); 60 | return OVR_SUCCESS(result); 61 | } 62 | 63 | VirtualRealityApiOvr::VirtualRealityApiOvr() 64 | : m_sessionStarted(false) 65 | , m_sensorSampleTime(0.0) 66 | , m_frameIndex(0) 67 | , m_swapChain(nullptr) 68 | { 69 | } 70 | 71 | VirtualRealityApiOvr::~VirtualRealityApiOvr() 72 | { 73 | // Don't call shutdown. It has been called already at this point. 74 | Q_ASSERT(m_swapChain); 75 | } 76 | 77 | bool VirtualRealityApiOvr::initializeIfHmdIsPresent() 78 | { 79 | if(!m_sessionStarted) { 80 | ovrResult result = ovr_Initialize(nullptr); 81 | if (!OVR_SUCCESS(result)) 82 | { 83 | qDebug() << "Failed to initialize libOVR."; 84 | return false; 85 | } 86 | result = ovr_Create(&m_session, &m_luid); 87 | if (!OVR_SUCCESS(result)) 88 | { 89 | qDebug() << "Failed to create session libOVR."; 90 | return false; 91 | } 92 | m_sessionStarted = true; 93 | } 94 | if (memcmp(&m_luid, &GetDefaultAdapterLuid(), sizeof(m_luid))) // If luid that the Rift is on is not the default adapter LUID... 95 | { 96 | qDebug() << "OpenGL supports only the default graphics adapter."; 97 | return false; 98 | } 99 | return true; 100 | } 101 | 102 | bool VirtualRealityApiOvr::isHmdPresent() 103 | { 104 | return initializeIfHmdIsPresent(); 105 | } 106 | 107 | void VirtualRealityApiOvr::initialize() 108 | { 109 | bool hmdPresent = initializeIfHmdIsPresent(); 110 | if(!hmdPresent) 111 | return; 112 | m_hmdDesc = ovr_GetHmdDesc(m_session); 113 | ovr_SetTrackingOriginType(m_session, ovrTrackingOrigin_FloorLevel); 114 | m_swapChain = new OvrSwapChain(m_session, getRenderTargetSize()); 115 | } 116 | 117 | void VirtualRealityApiOvr::shutdown() 118 | { 119 | if(m_swapChain != nullptr) 120 | delete m_swapChain; 121 | } 122 | 123 | bool VirtualRealityApiOvr::bindFrambufferObject(int hmdId) 124 | { 125 | m_swapChain->bindCurrentChainIndexFramebuffer(); 126 | return true; 127 | } 128 | 129 | void VirtualRealityApiOvr::swapToHeadset() 130 | { 131 | m_swapChain->commit(); 132 | 133 | ovrLayerEyeFov ld; 134 | ld.Header.Type = ovrLayerType_EyeFov; 135 | ld.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; // Because OpenGL. 136 | 137 | ld.ColorTexture[ovrEye_Left] = m_swapChain->ovrTextureChain(); 138 | int halfWidth = m_swapChain->size().width()/2; 139 | int height = m_swapChain->size().height(); 140 | ld.Viewport[ovrEye_Left] = Recti(0, 0, halfWidth, height); 141 | ld.Fov[ovrEye_Left] = m_hmdDesc.DefaultEyeFov[ovrEye_Left]; 142 | ld.RenderPose[ovrEye_Left] = m_eyeRenderPose[ovrEye_Left]; 143 | 144 | ld.ColorTexture[ovrEye_Right] = m_swapChain->ovrTextureChain(); 145 | ld.Viewport[ovrEye_Right] = Recti(halfWidth, 0, halfWidth, height); 146 | ld.Fov[ovrEye_Right] = m_hmdDesc.DefaultEyeFov[ovrEye_Right]; 147 | ld.RenderPose[ovrEye_Right] = m_eyeRenderPose[ovrEye_Right]; 148 | 149 | ld.SensorSampleTime = m_sensorSampleTime; 150 | 151 | ovrLayerHeader* layers = &ld.Header; 152 | ovrResult result = ovr_SubmitFrame(m_session, m_frameIndex, nullptr, &layers, 1); 153 | 154 | if (!OVR_SUCCESS(result)) 155 | { 156 | ovrErrorInfo inf; 157 | ovr_GetLastErrorInfo(&inf); 158 | qDebug() << inf.ErrorString; 159 | return; 160 | } 161 | m_frameIndex++; 162 | } 163 | 164 | void VirtualRealityApiOvr::getEyeMatrices(QMatrix4x4 &leftEye, QMatrix4x4 &rightEye) 165 | { 166 | ovrEyeRenderDesc eyeRenderDesc[ovrEye_Count]; 167 | eyeRenderDesc[ovrEye_Left] = ovr_GetRenderDesc(m_session, ovrEye_Left, m_hmdDesc.DefaultEyeFov[ovrEye_Left]); 168 | eyeRenderDesc[ovrEye_Right] = ovr_GetRenderDesc(m_session, ovrEye_Right, m_hmdDesc.DefaultEyeFov[ovrEye_Right]); 169 | // Get eye poses, feeding in correct IPD offset 170 | ovrPosef HmdToEyeOffset[2] = { eyeRenderDesc[ovrEye_Left].HmdToEyePose, 171 | eyeRenderDesc[ovrEye_Right].HmdToEyePose }; 172 | 173 | 174 | ovr_GetEyePoses(m_session, m_frameIndex, ovrTrue, HmdToEyeOffset, m_eyeRenderPose, &m_sensorSampleTime); 175 | 176 | ovrVector3f &posLeft = m_eyeRenderPose[ovrEye_Left].Position; 177 | ovrVector3f &posRight = m_eyeRenderPose[ovrEye_Right].Position; 178 | ovrQuatf orientLeft = m_eyeRenderPose[ovrEye_Left].Orientation; 179 | ovrQuatf orientRight = m_eyeRenderPose[ovrEye_Right].Orientation; 180 | 181 | QVector3D zero(0.0f,0.0f,0.0f); 182 | Matrix4f finalRollPitchYaw = Matrix4f(orientLeft).Transposed(); 183 | Vector3f finalUp = finalRollPitchYaw.Transform(Vector3f(0, 1, 0)); 184 | Vector3f finalForward = finalRollPitchYaw.Transform(Vector3f(0, 0, -1)); 185 | leftEye.translate(QVector3D(posLeft.x, posLeft.y, posLeft.z)); 186 | leftEye.lookAt(zero, QVector3D(finalForward.x, finalForward.y, finalForward.z), QVector3D(finalUp.x, finalUp.y, finalUp.z)); 187 | finalRollPitchYaw = Matrix4f(orientRight).Transposed(); 188 | finalUp = finalRollPitchYaw.Transform(Vector3f(0, 1, 0)); 189 | finalForward = finalRollPitchYaw.Transform(Vector3f(0, 0, -1)); 190 | rightEye.translate(QVector3D(posRight.x, posRight.y, posRight.z)); 191 | rightEye.lookAt(zero, QVector3D(finalForward.x, finalForward.y, finalForward.z), QVector3D(finalUp.x, finalUp.y, finalUp.z)); 192 | } 193 | 194 | void VirtualRealityApiOvr::getProjectionMatrices(QMatrix4x4 &leftProjection, QMatrix4x4 &rightProjection) 195 | { 196 | Matrix4f projLeft = ovrMatrix4f_Projection(m_hmdDesc.DefaultEyeFov[ovrEye_Left], 0.2f, 1000.0f, ovrProjection_None); 197 | Matrix4f projRight = ovrMatrix4f_Projection(m_hmdDesc.DefaultEyeFov[ovrEye_Right], 0.2f, 1000.0f, ovrProjection_None); 198 | QMatrix4x4 projL(projLeft.M[0][0], projLeft.M[0][1], projLeft.M[0][2], projLeft.M[0][3], 199 | projLeft.M[1][0], projLeft.M[1][1], projLeft.M[1][2], projLeft.M[1][3], 200 | projLeft.M[2][0], projLeft.M[2][1], projLeft.M[2][2], projLeft.M[2][3], 201 | projLeft.M[3][0], projLeft.M[3][1], projLeft.M[3][2], projLeft.M[3][3]); 202 | QMatrix4x4 projR(projRight.M[0][0], projRight.M[0][1], projRight.M[0][2], projRight.M[0][3], 203 | projRight.M[1][0], projRight.M[1][1], projRight.M[1][2], projRight.M[1][3], 204 | projRight.M[2][0], projRight.M[2][1], projRight.M[2][2], projRight.M[2][3], 205 | projRight.M[3][0], projRight.M[3][1], projRight.M[3][2], projRight.M[3][3]); 206 | leftProjection = projL; 207 | rightProjection = projR; 208 | //TODO: don't copy 209 | } 210 | 211 | QList VirtualRealityApiOvr::currentlyTrackedObjects() 212 | { 213 | //TODO: does this work? 214 | //return ovr_GetTrackerCount(m_session); 215 | return QList(); 216 | } 217 | 218 | void VirtualRealityApiOvr::getTrackedObject(int id, QMatrix4x4 &transform) 219 | { 220 | 221 | } 222 | 223 | Qt3DVirtualReality::QVirtualRealityApiBackend::TrackedObjectType VirtualRealityApiOvr::getTrackedObjectType(int id) 224 | { 225 | return Qt3DVirtualReality::QVirtualRealityApiBackend::Other; 226 | } 227 | 228 | void VirtualRealityApiOvr::getTrackedObjectModel(int id, QVector &vertices, QVector &indices, QOpenGLTexture *texture) 229 | { 230 | 231 | } 232 | 233 | void VirtualRealityApiOvr::getMirrorTexture(QOpenGLTexture *outMirrorTexture) 234 | { 235 | 236 | } 237 | 238 | bool VirtualRealityApiOvr::isTriggerTmp() 239 | { 240 | //TO DO: check for real trigger 241 | return false; 242 | } 243 | 244 | qreal VirtualRealityApiOvr::refreshRate(int hmdId) const 245 | { 246 | return m_hmdDesc.DisplayRefreshRate; 247 | } 248 | 249 | QMatrix4x4 VirtualRealityApiOvr::headPose(int hmdId) 250 | { 251 | return QMatrix4x4(); 252 | } 253 | 254 | QSize VirtualRealityApiOvr::getRenderTargetSize() 255 | { 256 | if(m_swapChain == nullptr) 257 | { 258 | ovrSizei idealTextureSizeLeft = ovr_GetFovTextureSize(m_session, ovrEye_Left, m_hmdDesc.DefaultEyeFov[ovrEye_Left], 1.0f); 259 | ovrSizei idealTextureSizeRight = ovr_GetFovTextureSize(m_session, ovrEye_Right, m_hmdDesc.DefaultEyeFov[ovrEye_Right], 1.0f); 260 | return QSize(idealTextureSizeLeft.w+idealTextureSizeRight.w, idealTextureSizeLeft.h); 261 | } 262 | return m_swapChain->size(); 263 | } 264 | 265 | int VirtualRealityApiOvr::timeUntilNextFrame() 266 | { 267 | // TO DO what happens if m_frame has not yet been incremented? 268 | double absolutFrameTime = ovr_GetPredictedDisplayTime(m_session, m_frameIndex-1); 269 | double now = ovr_GetTimeInSeconds(); 270 | return static_cast(std::floor(1000.0*(absolutFrameTime-now))); 271 | } 272 | #endif 273 | -------------------------------------------------------------------------------- /virtualreality/qvirtualrealitygeometry.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | /*! 16 | * \class Qt3DExtras::QVirtualRealityGeometry 17 | * \inheaderfile Qt3DExtras/QVirtualRealityGeometry 18 | * \inmodule Qt3DExtras 19 | * \brief The QVirtualRealityGeometry class allows creation of a virtual reality representation of objects like controllers, hands, tracking cameras, lighthouses or tracking pucks in scenes. 20 | * \since 5.7 21 | * \ingroup geometries 22 | * \inherits Qt3DRender::QGeometry 23 | * 24 | * The QVirtualRealityGeometry class is most commonly used internally by the QVirtualrealityMesh 25 | * but can also be used in custom Qt3DRender::QGeometryRenderer subclasses. 26 | */ 27 | 28 | // TO DO: Refactor from Cone 29 | 30 | #ifndef _USE_MATH_DEFINES 31 | # define _USE_MATH_DEFINES // For MSVC 32 | #endif 33 | 34 | #include "qvirtualrealitygeometry.h" 35 | #include "qvirtualrealitygeometry_p.h" 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | QT_BEGIN_NAMESPACE 45 | 46 | using namespace Qt3DRender; 47 | 48 | namespace Qt3DVirtualReality { 49 | 50 | class VirtualrealityVertexDataFunctor : public QBufferDataGenerator 51 | { 52 | public: 53 | VirtualrealityVertexDataFunctor(QVirtualRealityApiBackend *apibackend, int trackedObjectIndex) 54 | : m_apibackend(apibackend) 55 | , m_trackedObjectIndex(trackedObjectIndex) 56 | {} 57 | 58 | QByteArray operator ()() Q_DECL_OVERRIDE 59 | { 60 | QVector vertices; 61 | QVector indices; 62 | QOpenGLTexture tex(QOpenGLTexture::Target2D); 63 | m_apibackend->getTrackedObjectModel(m_trackedObjectIndex, vertices, indices, &tex); 64 | return QByteArray::fromRawData( reinterpret_cast(vertices.constData()), sizeof(float) * vertices.size()); 65 | } 66 | 67 | bool operator ==(const QBufferDataGenerator &other) const Q_DECL_OVERRIDE 68 | { 69 | const VirtualrealityVertexDataFunctor *otherFunctor = functor_cast(&other); 70 | if (otherFunctor != nullptr) 71 | return (otherFunctor->m_trackedObjectIndex == m_trackedObjectIndex 72 | && otherFunctor->m_apibackend == m_apibackend); 73 | return false; 74 | } 75 | 76 | QT3D_FUNCTOR(VirtualrealityVertexDataFunctor) 77 | 78 | private: 79 | QVirtualRealityApiBackend *m_apibackend; 80 | int m_trackedObjectIndex; 81 | }; 82 | 83 | class VirtualrealityIndexDataFunctor : public QBufferDataGenerator 84 | { 85 | public: 86 | VirtualrealityIndexDataFunctor(QVirtualRealityApiBackend *apibackend, int trackedObjectIndex) 87 | : m_apibackend(apibackend) 88 | , m_trackedObjectIndex(trackedObjectIndex) 89 | {} 90 | 91 | QByteArray operator ()() Q_DECL_OVERRIDE 92 | { 93 | QVector vertices; 94 | QVector indices; 95 | QOpenGLTexture tex(QOpenGLTexture::Target2D); 96 | m_apibackend->getTrackedObjectModel(m_trackedObjectIndex, vertices, indices, &tex); 97 | return QByteArray::fromRawData( reinterpret_cast(indices.constData()), sizeof(float) * indices.size()); 98 | } 99 | 100 | bool operator ==(const QBufferDataGenerator &other) const Q_DECL_OVERRIDE 101 | { 102 | const VirtualrealityIndexDataFunctor *otherFunctor = functor_cast(&other); 103 | if (otherFunctor != nullptr) 104 | return (otherFunctor->m_trackedObjectIndex == m_trackedObjectIndex 105 | && otherFunctor->m_apibackend == m_apibackend); 106 | return false; 107 | } 108 | 109 | QT3D_FUNCTOR(VirtualrealityIndexDataFunctor) 110 | 111 | private: 112 | QVirtualRealityApiBackend *m_apibackend; 113 | int m_trackedObjectIndex; 114 | }; 115 | 116 | 117 | QVirtualRealityGeometryPrivate::QVirtualRealityGeometryPrivate() 118 | : QGeometryPrivate() 119 | , m_trackedObjectIndex(-1) 120 | , m_positionAttribute(nullptr) 121 | , m_normalAttribute(nullptr) 122 | , m_texCoordAttribute(nullptr) 123 | , m_indexAttribute(nullptr) 124 | , m_positionBuffer(nullptr) 125 | , m_vertexBuffer(nullptr) 126 | , m_indexBuffer(nullptr) 127 | , m_apibackend(nullptr) 128 | { 129 | } 130 | 131 | void QVirtualRealityGeometryPrivate::init() 132 | { 133 | Q_Q(QVirtualRealityGeometry); 134 | m_positionAttribute = new QAttribute(q); 135 | m_normalAttribute = new QAttribute(q); 136 | m_texCoordAttribute = new QAttribute(q); 137 | m_indexAttribute = new QAttribute(q); 138 | m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q); 139 | m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q); 140 | 141 | //TO DO: Vertx count and index count lazy. do not retrieve object for this. 142 | // vec3 pos, vec2 tex, vec3 normal 143 | const quint32 elementSize = 3 + 2 + 3; 144 | const quint32 stride = elementSize * sizeof(float); 145 | // QVector vertices; 146 | // QVector indices; 147 | // QOpenGLTexture tex(QOpenGLTexture::Target2D); 148 | // m_apibackend->getTrackedObjectModel(m_trackedObjectIndex, vertices, indices, &tex); 149 | const int faces = 1;//indices.count()/3; 150 | const int nVerts = 3;//vertices.count()/elementSize; 151 | 152 | m_positionAttribute->setName(QAttribute::defaultPositionAttributeName()); 153 | m_positionAttribute->setVertexBaseType(QAttribute::Float); 154 | m_positionAttribute->setVertexSize(3); 155 | m_positionAttribute->setAttributeType(QAttribute::VertexAttribute); 156 | m_positionAttribute->setBuffer(m_vertexBuffer); 157 | m_positionAttribute->setByteStride(stride); 158 | m_positionAttribute->setCount(nVerts); 159 | 160 | m_normalAttribute->setName(QAttribute::defaultNormalAttributeName()); 161 | m_normalAttribute->setVertexBaseType(QAttribute::Float); 162 | m_normalAttribute->setVertexSize(3); 163 | m_normalAttribute->setAttributeType(QAttribute::VertexAttribute); 164 | m_normalAttribute->setBuffer(m_vertexBuffer); 165 | m_normalAttribute->setByteStride(stride); 166 | m_normalAttribute->setByteOffset(3 * sizeof(float)); 167 | m_normalAttribute->setCount(nVerts); 168 | 169 | m_texCoordAttribute->setName(QAttribute::defaultTextureCoordinateAttributeName()); 170 | m_texCoordAttribute->setVertexBaseType(QAttribute::Float); 171 | m_texCoordAttribute->setVertexSize(2); 172 | m_texCoordAttribute->setAttributeType(QAttribute::VertexAttribute); 173 | m_texCoordAttribute->setBuffer(m_vertexBuffer); 174 | m_texCoordAttribute->setByteStride(stride); 175 | m_texCoordAttribute->setByteOffset(6 * sizeof(float)); 176 | m_texCoordAttribute->setCount(nVerts); 177 | 178 | m_indexAttribute->setAttributeType(QAttribute::IndexAttribute); 179 | m_indexAttribute->setVertexBaseType(QAttribute::UnsignedInt); 180 | m_indexAttribute->setBuffer(m_indexBuffer); 181 | 182 | m_indexAttribute->setCount(faces * 3); 183 | 184 | //m_vertexBuffer->setDataGenerator(QSharedPointer::create(m_apibackend, m_trackedObjectIndex)); 185 | //m_indexBuffer->setDataGenerator(QSharedPointer::create(m_apibackend, m_trackedObjectIndex)); 186 | 187 | q->addAttribute(m_positionAttribute); 188 | q->addAttribute(m_normalAttribute); 189 | q->addAttribute(m_texCoordAttribute); 190 | q->addAttribute(m_indexAttribute); 191 | } 192 | 193 | /*! 194 | * \qmltype VirtualrealityGeometry 195 | * \instantiates Qt3DExtras::QVirtualRealityGeometry 196 | * \inqmlmodule Qt3D.Extras 197 | * \brief VirtualrealityGeometry allows creation of a virtualreality in 3D space. 198 | * 199 | * The VirtualrealityGeometry type is most commonly used internally by the VirtualrealityMesh type 200 | * but can also be used in custom GeometryRenderer types.. 201 | */ 202 | 203 | /*! 204 | * \qmlproperty Attribute VirtualrealityGeometry::positionAttribute 205 | * 206 | * Holds the geometry position attribute. 207 | */ 208 | 209 | /*! 210 | * \qmlproperty Attribute VirtualrealityGeometry::normalAttribute 211 | * 212 | * Holds the geometry normal attribute. 213 | */ 214 | 215 | /*! 216 | * \qmlproperty Attribute VirtualrealityGeometry::texCoordAttribute 217 | * 218 | * Holds the geometry texture coordinate attribute. 219 | */ 220 | 221 | /*! 222 | * \qmlproperty Attribute VirtualrealityGeometry::indexAttribute 223 | * 224 | * Holds the geometry index attribute. 225 | */ 226 | 227 | QVirtualRealityGeometry::QVirtualRealityGeometry(QNode *parent) 228 | : QGeometry(*new QVirtualRealityGeometryPrivate, parent) 229 | { 230 | Q_D(QVirtualRealityGeometry); 231 | d->init(); 232 | } 233 | 234 | QVirtualRealityGeometry::QVirtualRealityGeometry(QVirtualRealityGeometryPrivate &dd, QNode *parent) 235 | :QGeometry(dd, parent) 236 | { 237 | Q_D(QVirtualRealityGeometry); 238 | d->init(); 239 | } 240 | 241 | 242 | /*! \internal */ 243 | QVirtualRealityGeometry::~QVirtualRealityGeometry() 244 | { 245 | } 246 | 247 | /*! 248 | * Updates vertices based on geometry properties. 249 | */ 250 | void QVirtualRealityGeometry::updateVertices() 251 | { 252 | Q_D(QVirtualRealityGeometry); 253 | 254 | if(!d->m_apibackend) return; 255 | //TO DO: do not query whole object here. lazy loading of vertex count 256 | QVector vertices; 257 | QVector indices; 258 | QOpenGLTexture tex(QOpenGLTexture::Target2D); 259 | d->m_apibackend->getTrackedObjectModel(d->m_trackedObjectIndex, vertices, indices, &tex); 260 | 261 | d->m_positionAttribute->setCount(vertices.count()/8); 262 | d->m_texCoordAttribute->setCount(vertices.count()/8); 263 | d->m_normalAttribute->setCount(vertices.count()/8); 264 | d->m_vertexBuffer->setDataGenerator(QSharedPointer::create(d->m_apibackend, d->m_trackedObjectIndex)); 265 | } 266 | 267 | /*! 268 | * Updates indices based on geometry properties. 269 | */ 270 | void QVirtualRealityGeometry::updateIndices() 271 | { 272 | Q_D(QVirtualRealityGeometry); 273 | 274 | if(!d->m_apibackend) return; 275 | //TO DO: do not query whole object here. lazy loading of vertex count 276 | QVector vertices; 277 | QVector indices; 278 | QOpenGLTexture tex(QOpenGLTexture::Target2D); 279 | d->m_apibackend->getTrackedObjectModel(d->m_trackedObjectIndex, vertices, indices, &tex); 280 | 281 | d->m_indexAttribute->setCount(indices.count()); 282 | d->m_indexBuffer->setDataGenerator(QSharedPointer::create(d->m_apibackend, d->m_trackedObjectIndex)); 283 | } 284 | 285 | void QVirtualRealityGeometry::setVrApiBackendTmp(QVirtualRealityApiBackend *apibackend) 286 | { 287 | Q_D(QVirtualRealityGeometry); 288 | d->m_apibackend = apibackend; 289 | updateVertices(); 290 | updateIndices(); 291 | } 292 | 293 | int QVirtualRealityGeometry::trackedObjectIndex() const 294 | { 295 | const Q_D(QVirtualRealityGeometry); 296 | return d->m_trackedObjectIndex; 297 | } 298 | 299 | /*! 300 | * \property QVirtualRealityGeometry::positionAttribute 301 | * 302 | * Holds the geometry position attribute. 303 | */ 304 | 305 | /*! 306 | * \property QVirtualRealityGeometry::normalAttribute 307 | * 308 | * Holds the geometry normal attribute. 309 | */ 310 | 311 | /*! 312 | * \property QVirtualRealityGeometry::texCoordAttribute 313 | * 314 | * Holds the geometry texture coordinate attribute. 315 | */ 316 | 317 | /*! 318 | * \property QVirtualRealityGeometry::indexAttribute 319 | * 320 | * Holds the geometry index attribute. 321 | */ 322 | 323 | 324 | QAttribute *QVirtualRealityGeometry::positionAttribute() const 325 | { 326 | Q_D(const QVirtualRealityGeometry); 327 | return d->m_positionAttribute; 328 | } 329 | 330 | QAttribute *QVirtualRealityGeometry::normalAttribute() const 331 | { 332 | Q_D(const QVirtualRealityGeometry); 333 | return d->m_normalAttribute; 334 | } 335 | 336 | QAttribute *QVirtualRealityGeometry::texCoordAttribute() const 337 | { 338 | Q_D(const QVirtualRealityGeometry); 339 | return d->m_texCoordAttribute; 340 | } 341 | 342 | QAttribute *QVirtualRealityGeometry::indexAttribute() const 343 | { 344 | Q_D(const QVirtualRealityGeometry); 345 | return d->m_indexAttribute; 346 | } 347 | 348 | void QVirtualRealityGeometry::setTrackedObjectIndex(int trackedObjectIndex) 349 | { 350 | Q_D(QVirtualRealityGeometry); 351 | if (trackedObjectIndex != d->m_trackedObjectIndex) { 352 | d->m_trackedObjectIndex = trackedObjectIndex; 353 | updateVertices(); 354 | updateIndices(); 355 | Q_EMIT trackedObjectIndexChanged(trackedObjectIndex); 356 | } 357 | } 358 | 359 | } // namespace Qt3DVirtualReality 360 | 361 | QT_END_NAMESPACE 362 | -------------------------------------------------------------------------------- /virtualreality/qheadmounteddisplay.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #include "qheadmounteddisplay.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include "qvirtualrealityapibackend.h" 33 | #include 34 | #include 35 | #include 36 | #include "frontend/qvirtualrealitycamera.h" 37 | #include "frontend/qvirtualrealitymesh.h" 38 | #include 39 | 40 | QT_BEGIN_NAMESPACE 41 | 42 | namespace Qt3DVirtualReality { 43 | 44 | namespace { 45 | 46 | class Qt3DQuickVirtualRealityIncubationController : public QObject, public QQmlIncubationController 47 | { 48 | Q_OBJECT 49 | public: 50 | explicit Qt3DQuickVirtualRealityIncubationController(QHeadMountedDisplay *hmd) 51 | : QObject(hmd) 52 | , m_hmd(hmd) 53 | //, m_incubationTime(std::max(1, int(1000 / hmd->refreshRate()) / 3)) // Allow incubation for 1/3 of a frame. 54 | { 55 | startTimer(hmd->refreshRate()); 56 | } 57 | 58 | void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE 59 | { 60 | int incubationTime = qMax(0, m_hmd->timeUntilNextFrame()-6); // present ~6ms before scanout 61 | qDebug() << "Incubating for" << incubationTime; 62 | if(incubationTime > 0) 63 | incubateFor(incubationTime); 64 | } 65 | 66 | private: 67 | //const int m_incubationTime; 68 | QHeadMountedDisplay *m_hmd; 69 | }; 70 | 71 | } // anonymous 72 | 73 | QHeadMountedDisplay::QHeadMountedDisplay(int hmdId, const QHeadMountedDisplayFormat &formathmd, QVirtualRealityApi *api, QVirtualRealityApiBackend *apibackend) 74 | : QObject() 75 | , m_engine(nullptr) 76 | , m_renderAspect(nullptr) 77 | , m_inputAspect(nullptr) 78 | , m_logicAspect(nullptr) 79 | , m_virtualRealityAspect(nullptr) 80 | , m_initialized(false) 81 | , m_incubationController(nullptr) 82 | , m_api(api) 83 | , m_apibackend(apibackend) 84 | , m_hmdId(hmdId) 85 | , m_fbo(nullptr) 86 | , m_context(nullptr) 87 | , m_surface(new QOffscreenSurface) 88 | , m_rootItem(nullptr) 89 | { 90 | //Note: m_apibackend is not yet initialized here. Wait for openGLContext creation 91 | 92 | QSurfaceFormat format; 93 | // Qt Quick may need a depth and stencil buffer. Always make sure these are available. 94 | format.setDepthBufferSize(16); 95 | format.setStencilBufferSize(8); 96 | format.setProfile(QSurfaceFormat::CoreProfile); 97 | format.setOption(QSurfaceFormat::DebugContext); 98 | 99 | m_context = new QOpenGLContext; 100 | m_context->setFormat(format); 101 | m_context->create(); 102 | 103 | 104 | m_surface = new QOffscreenSurface; 105 | // Pass m_context->format(), not format. Format does not specify and color buffer 106 | // sizes, while the context, that has just been created, reports a format that has 107 | // these values filled in. Pass this to the offscreen surface to make sure it will be 108 | // compatible with the context's configuration. 109 | m_surface->setFormat(m_context->format()); 110 | m_surface->create(); 111 | m_context->makeCurrent(m_surface); 112 | 113 | QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); 114 | 115 | logger->initialize(); 116 | connect(logger, &QOpenGLDebugLogger::messageLogged, this, [](const QOpenGLDebugMessage &debugMessage){ 117 | qDebug() << debugMessage; 118 | }, Qt::DirectConnection); 119 | logger->enableMessages(); 120 | logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); 121 | emit surfaceChanged(m_surface); 122 | 123 | m_engine.reset(new Qt3DCore::Quick::QQmlAspectEngine); 124 | m_renderAspect = new Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous); 125 | m_inputAspect = new Qt3DInput::QInputAspect; 126 | m_logicAspect = new Qt3DLogic::QLogicAspect; 127 | m_virtualRealityAspect = new Qt3DVirtualReality::QVirtualRealityAspect; 128 | m_virtualRealityAspect->setHeadmountedDisplay(this); 129 | //m_virtualRealityAspect->setVirtualRealityApi(m_api); 130 | m_virtualRealityAspect->setVirtualRealityApiBackend(m_apibackend); 131 | 132 | m_engine->aspectEngine()->registerAspect(m_renderAspect); 133 | m_engine->aspectEngine()->registerAspect(m_inputAspect); 134 | m_engine->aspectEngine()->registerAspect(m_logicAspect); 135 | m_engine->aspectEngine()->registerAspect(m_virtualRealityAspect); 136 | connect(this, &QHeadMountedDisplay::requestRun, this, &QHeadMountedDisplay::run, Qt::QueuedConnection); 137 | } 138 | 139 | QHeadMountedDisplay::~QHeadMountedDisplay() 140 | { 141 | if(m_surface) 142 | delete m_surface; 143 | } 144 | 145 | void QHeadMountedDisplay::registerAspect(Qt3DCore::QAbstractAspect *aspect) 146 | { 147 | m_engine->aspectEngine()->registerAspect(aspect); 148 | } 149 | 150 | void QHeadMountedDisplay::registerAspect(const QString &name) 151 | { 152 | m_engine->aspectEngine()->registerAspect(name); 153 | } 154 | 155 | void QHeadMountedDisplay::setSource(const QUrl &source) 156 | { 157 | m_source = source; 158 | if(!m_initialized) 159 | { 160 | // Connect to the QQmlAspectEngine's statusChanged signal so that when the QML is loaded 161 | // and th eobjects hav ebeen instantiated, but before we set them on the QAspectEngine we 162 | // can swoop in and set the window surface and camera on the framegraph and ensure the camera 163 | // respects the window's aspect ratio 164 | connect(m_engine.data(), &Qt3DCore::Quick::QQmlAspectEngine::sceneCreated, 165 | this, &QHeadMountedDisplay::onSceneCreated); 166 | 167 | 168 | qmlRegisterType("vr", 2, 0, "VrCamera"); 169 | qmlRegisterType("vr", 2, 0, "TrackedObjectMesh"); 170 | m_engine->setSource(m_source); 171 | 172 | // Set the QQmlIncubationController on the window 173 | // to benefit from asynchronous incubation 174 | if (!m_incubationController) 175 | m_incubationController = new Qt3DQuickVirtualRealityIncubationController(this); 176 | 177 | m_engine->qmlEngine()->setIncubationController(m_incubationController); 178 | 179 | m_initialized = true; 180 | } 181 | else 182 | { 183 | qDebug() << "source already set, not yet implemented."; // TO DO 184 | } 185 | } 186 | 187 | Qt3DCore::Quick::QQmlAspectEngine *QHeadMountedDisplay::engine() const 188 | { 189 | return m_engine.data(); 190 | } 191 | 192 | qreal QHeadMountedDisplay::refreshRate() 193 | { 194 | Q_ASSERT(m_apibackend); 195 | return m_apibackend->refreshRate(m_hmdId); 196 | } 197 | 198 | QObject *QHeadMountedDisplay::surface() const 199 | { 200 | return qobject_cast(m_surface); 201 | } 202 | 203 | QSize QHeadMountedDisplay::renderTargetSize() const 204 | { 205 | return m_apibackend->getRenderTargetSize(); 206 | } 207 | 208 | int QHeadMountedDisplay::timeUntilNextFrame() 209 | { 210 | return m_apibackend->timeUntilNextFrame(); 211 | } 212 | 213 | QOpenGLContext *QHeadMountedDisplay::context() 214 | { 215 | return m_context; 216 | } 217 | 218 | void QHeadMountedDisplay::onSceneCreated(QObject *rootObject) 219 | { 220 | Q_ASSERT(rootObject); 221 | 222 | setWindowSurface(rootObject); 223 | 224 | m_rootItem = rootObject;//qobject_cast(rootObject); 225 | // if (m_cameraAspectRatioMode == AutomaticAspectRatio) { 226 | // // Set aspect ratio of first camera to match the window 227 | // QList cameras 228 | // = rootObject->findChildren(); 229 | // if (cameras.isEmpty()) { 230 | // qWarning() << "No camera found"; 231 | // } else { 232 | // m_camera = cameras.first(); 233 | // setCameraAspectModeHelper(); 234 | // } 235 | // } 236 | 237 | if(m_rootItem) { 238 | QVirtualrealityCamera *vrCamera = m_rootItem->findChild(); 239 | if(vrCamera) { 240 | QMatrix4x4 projL; 241 | QMatrix4x4 projR; 242 | m_apibackend->getProjectionMatrices(projL, projR); 243 | vrCamera->setProjections(projL, projR); 244 | vrCamera->setLeftNormalizedViewportRect(QRectF(0.0f, 0.0f, 0.5f, 1.0f)); 245 | vrCamera->setRightNormalizedViewportRect(QRectF(0.5f, 0.0f, 0.5f, 1.0f)); 246 | } else { 247 | Q_ASSERT(vrCamera); //TO DO logging 248 | } 249 | } else { 250 | Q_ASSERT(m_rootItem); //TO DO logging 251 | } 252 | 253 | // Set ourselves up as a source of input events for the input aspect 254 | Qt3DInput::QInputSettings *inputSettings = rootObject->findChild(); 255 | if (inputSettings) { 256 | inputSettings->setEventSource(this); 257 | } else { 258 | qWarning() << "No Input Settings found, keyboard and mouse events won't be handled"; 259 | } 260 | Q_EMIT sceneCreated(m_rootItem); 261 | } 262 | 263 | void QHeadMountedDisplay::run() { 264 | 265 | m_context->makeCurrent(m_surface); 266 | 267 | 268 | // QOpenGLFramebufferObjectFormat format; 269 | // format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); 270 | // format.setTextureTarget(GL_TEXTURE_2D); 271 | // format.setSamples(0); 272 | // format.setMipmap(false); 273 | 274 | // QSize renderTargetSize = m_apibackend->getRenderSurfaceSize(); 275 | // if(m_fbo) 276 | // delete m_fbo; 277 | // m_fbo = new QOpenGLFramebufferObject(renderTargetSize, format, m_apibackend->currentTextureId() ); 278 | // m_fbo->bind(); 279 | 280 | //glViewport(0, 0, renderTargetSize.width(), renderTargetSize.height()); 281 | 282 | // Q_ASSERT(false);//TO DO: wrong thread for m_fbo->bind(). need QSGNode. What about createTextureFromId? 283 | // if (m_aspectEngine->rootEntity() != m_item->entity()) 284 | // scheduleRootEntityChange(); 285 | //TODO: QVrSelector. This is the object with all parameters then 286 | QVirtualrealityCamera *vrCamera(nullptr); 287 | QList vrGeometries; 288 | if(m_rootItem) { 289 | vrCamera = m_rootItem->findChild(); 290 | vrGeometries = m_rootItem->findChildren(); 291 | } 292 | m_apibackend->bindFrambufferObject(m_hmdId); 293 | for(QList::iterator iter(vrGeometries.begin()); iter != vrGeometries.end(); ++iter) { 294 | (*iter)->setVrApiBackendTmp(m_apibackend); 295 | } 296 | //static_cast(Qt3DRender::QRenderAspectPrivate::get(m_renderAspect))->jobManager()->waitForAllJobs(); 297 | static_cast(Qt3DRender::QRenderAspectPrivate::get(m_renderAspect))->renderSynchronous(); 298 | QMatrix4x4 leftEye; 299 | QMatrix4x4 rightEye; 300 | m_apibackend->getEyeMatrices(leftEye, rightEye); 301 | if(vrCamera != nullptr) { 302 | vrCamera->update(leftEye, rightEye); 303 | vrCamera->setVrBackendTmp(m_apibackend); // only for transforms 304 | } 305 | m_fbo->bindDefault(); 306 | m_apibackend->swapToHeadset(); 307 | emit requestRun(); 308 | } 309 | 310 | void QHeadMountedDisplay::setWindowSurface(QObject *rootObject) 311 | { 312 | // if(!(m_context = QOpenGLContext::currentContext())) 313 | // { 314 | // m_context = new QOpenGLContext(); 315 | // m_context->create(); 316 | // m_context->makeCurrent(m_surface); 317 | // Q_ASSERT(QOpenGLContext::currentContext() != nullptr); 318 | // } 319 | m_context->makeCurrent(m_surface); 320 | static_cast(Qt3DRender::QRenderAspectPrivate::get(m_renderAspect))->renderInitialize(m_context); 321 | Qt3DRender::QRenderSurfaceSelector *surfaceSelector = Qt3DRender::QRenderSurfaceSelectorPrivate::find(rootObject); 322 | if (surfaceSelector) 323 | surfaceSelector->setSurface(m_surface); 324 | if (m_fbo) { 325 | delete m_fbo; 326 | m_fbo = nullptr; 327 | } 328 | const QSize texSize(m_apibackend->getRenderTargetSize()); 329 | 330 | //TODO: At the moment FBO is recreated each frame 331 | //if (!m_fbo) { 332 | QOpenGLFramebufferObjectFormat format; 333 | format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); 334 | format.setTextureTarget(GL_TEXTURE_2D); 335 | format.setSamples(0); 336 | format.setMipmap(false); 337 | 338 | // QSurfaceFormat notUsedTodo; 339 | // m_apibackend->createSurface(m_hmdId, texSize, notUsedTodo); 340 | emit renderTargetSizeChanged(texSize); 341 | //m_fbo = new QOpenGLFramebufferObject(texSize, format, texId ); 342 | //m_quickWindow->setRenderTarget(m_fbo); 343 | //} 344 | // if(!sizeOkay) 345 | // { 346 | // // Size of m_window can differ from m_quickWindow and rendertarget size 347 | // m_quickWindow->resize(texSize); 348 | // m_quickWindow->contentItem()->setWidth(texSize.width()); 349 | // m_quickWindow->contentItem()->setHeight(texSize.height()); 350 | // m_quickWindow->setGeometry(0, 0, texSize.width(), texSize.height()); 351 | // } 352 | } 353 | 354 | } // Qt3DVirtualReality 355 | 356 | QT_END_NAMESPACE 357 | 358 | #include "qheadmounteddisplay.moc" 359 | -------------------------------------------------------------------------------- /virtualreality/vrbackends/openvr/virtualrealityapiopenvr.cpp: -------------------------------------------------------------------------------- 1 | //**************************************************************************** 2 | //** 3 | //** Author: Daniel Bulla 4 | //** Contact: qt3d-vr@danielbulla.de 5 | //** 6 | //** GNU Lesser General Public License Usage 7 | //** General Public License version 3 as published by the Free Software 8 | //** Foundation and appearing in the file LICENSE.LGPL3 included in the 9 | //** packaging of this file. Please review the following information to 10 | //** ensure the GNU Lesser General Public License version 3 requirements 11 | //** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 12 | //** 13 | //****************************************************************************/ 14 | 15 | #if(QT3DVR_COMPILE_WITH_OPENVR) 16 | #include "virtualrealityapiopenvr.h" 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | //// Process SteamVR controller state 23 | //for( vr::TrackedDeviceIndex_t unDevice = 0; unDevice < vr::k_unMaxTrackedDeviceCount; unDevice++ ) 24 | //{ 25 | // vr::VRControllerState_t state; 26 | // if( m_pHMD->GetControllerState( unDevice, &state, sizeof(state) ) ) 27 | // { 28 | // m_rbShowTrackedDevice[ unDevice ] = state.ulButtonPressed == 0; 29 | // } 30 | //} 31 | 32 | //----------------------------------------------------------------------------- 33 | // Purpose: Helper to get a string from a tracked device property and turn it 34 | // into a std::string 35 | //----------------------------------------------------------------------------- 36 | std::string getTrackedDeviceString( vr::IVRSystem *hmd, vr::TrackedDeviceIndex_t device, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *error = NULL ) 37 | { 38 | uint32_t requiredBufferLen = hmd->GetStringTrackedDeviceProperty( device, prop, NULL, 0, error ); 39 | if( requiredBufferLen == 0 ) 40 | return ""; 41 | 42 | char *buffer = new char[ requiredBufferLen ]; 43 | requiredBufferLen = hmd->GetStringTrackedDeviceProperty( device, prop, buffer, requiredBufferLen, error ); 44 | std::string result = buffer; 45 | delete [] buffer; 46 | return result; 47 | } 48 | 49 | //----------------------------------------------------------------------------- 50 | // Purpose: Gets a Matrix Projection Eye with respect to nEye. 51 | //----------------------------------------------------------------------------- 52 | QMatrix4x4 VirtualRealityApiOpenVR::getHmdMatrixProjectionEye( vr::Hmd_Eye nEye ) 53 | { 54 | if ( !m_hmd ) 55 | return QMatrix4x4(); 56 | float nearClip = 0.2f; 57 | float farClip = 1000.0f; 58 | vr::HmdMatrix44_t mat = m_hmd->GetProjectionMatrix( nEye, nearClip, farClip ); 59 | 60 | return convertSteamVrMatrixToQMatrix4x4(mat); 61 | // return QMatrix4x4( 62 | // mat.m[0][0], mat.m[0][1], -mat.m[0][2], mat.m[0][3], 63 | // mat.m[1][0], mat.m[1][1], -mat.m[1][2], mat.m[1][3], 64 | // mat.m[2][0], mat.m[2][1], -mat.m[2][2], mat.m[2][3], 65 | // mat.m[3][0], mat.m[3][1], -mat.m[3][2], mat.m[3][3] 66 | // ); 67 | } 68 | 69 | //----------------------------------------------------------------------------- 70 | // Purpose: Gets an HMDMatrixPoseEye with respect to nEye. 71 | //----------------------------------------------------------------------------- 72 | QMatrix4x4 VirtualRealityApiOpenVR::getHmdMatrixPoseEye( vr::Hmd_Eye nEye ) 73 | { 74 | if ( !m_hmd ) 75 | return QMatrix4x4(); 76 | 77 | vr::HmdMatrix34_t mat = m_hmd->GetEyeToHeadTransform( nEye ); 78 | return convertSteamVrMatrixToQMatrix4x4(mat);//.inverted(); 79 | } 80 | 81 | //----------------------------------------------------------------------------- 82 | // Purpose: Gets a Current View Projection Matrix with respect to nEye, 83 | // which may be an Eye_Left or an Eye_Right. 84 | //----------------------------------------------------------------------------- 85 | QMatrix4x4 VirtualRealityApiOpenVR::getCurrentViewMatrix( vr::Hmd_Eye nEye ) 86 | { 87 | QMatrix4x4 matMVP; 88 | if( nEye == vr::Eye_Left ) 89 | { 90 | matMVP = m_eyePosLeft * m_hmdPose; 91 | } 92 | else if( nEye == vr::Eye_Right ) 93 | { 94 | matMVP = m_eyePosRight * m_hmdPose; 95 | } 96 | 97 | return matMVP; 98 | } 99 | 100 | //----------------------------------------------------------------------------- 101 | // Purpose: 102 | //----------------------------------------------------------------------------- 103 | void VirtualRealityApiOpenVR::updateHmdMatrixPose() 104 | { 105 | // This queries the pose for user. User gets a good estimation of the HMD pose that will be used. 106 | // However, the engine is free to use a newer estimation for the head pose for rendering, than returned here. 107 | // Only one estimation will be made on the first request of poses per frame. 108 | // This way e.g. not every qml binding will query the vr sdk on its own. 109 | if(m_poseNewEnough) 110 | return; 111 | m_poseNewEnough = true; 112 | if ( !m_hmd ) 113 | return; 114 | 115 | vr::VRCompositor()->WaitGetPoses(m_trackedDevicePose, vr::k_unMaxTrackedDeviceCount, NULL, 0 ); 116 | 117 | m_validPoseCount = 0; 118 | m_poseClasses = ""; 119 | for ( int deviceIndex = 0; deviceIndex < vr::k_unMaxTrackedDeviceCount; ++deviceIndex ) 120 | { 121 | if ( m_trackedDevicePose[deviceIndex].bPoseIsValid ) 122 | { 123 | m_validPoseCount++; 124 | m_devicePose[deviceIndex] = convertSteamVrMatrixToQMatrix4x4( m_trackedDevicePose[deviceIndex].mDeviceToAbsoluteTracking ); 125 | if (m_devClassChar[deviceIndex]==0) 126 | { 127 | switch (m_hmd->GetTrackedDeviceClass(deviceIndex)) 128 | { 129 | case vr::TrackedDeviceClass_Controller: m_devClassChar[deviceIndex] = 'C'; break; 130 | case vr::TrackedDeviceClass_HMD: m_devClassChar[deviceIndex] = 'H'; break; 131 | case vr::TrackedDeviceClass_Invalid: m_devClassChar[deviceIndex] = 'I'; break; 132 | case vr::TrackedDeviceClass_GenericTracker: m_devClassChar[deviceIndex] = 'G'; break; 133 | case vr::TrackedDeviceClass_TrackingReference: m_devClassChar[deviceIndex] = 'T'; break; 134 | default: m_devClassChar[deviceIndex] = '?'; break; 135 | } 136 | } 137 | m_poseClasses += m_devClassChar[deviceIndex]; 138 | } 139 | } 140 | 141 | if ( m_trackedDevicePose[vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid ) 142 | { 143 | m_hmdPose = m_devicePose[vr::k_unTrackedDeviceIndex_Hmd]; 144 | //m_hmdPose = m_hmdPose.inverted(); 145 | } 146 | 147 | m_isTrigger = false; 148 | for( vr::TrackedDeviceIndex_t unDevice = 0; unDevice < vr::k_unMaxTrackedDeviceCount; unDevice++ ) 149 | { 150 | vr::VRControllerState_t state; 151 | if( m_hmd->GetControllerState( unDevice, &state, sizeof(state) ) ) 152 | { 153 | m_isTrigger |= state.ulButtonPressed != 0; 154 | } 155 | } 156 | } 157 | 158 | void VirtualRealityApiOpenVR::setupCameras() 159 | { 160 | m_eyePosLeft = getHmdMatrixPoseEye( vr::Eye_Left ); 161 | m_eyePosRight = getHmdMatrixPoseEye( vr::Eye_Right ); 162 | qDebug() << "Left eye " << m_eyePosLeft.column(3); 163 | qDebug() << "Right eye" << m_eyePosRight.column(3); 164 | } 165 | 166 | //----------------------------------------------------------------------------- 167 | // Purpose: Converts a SteamVR matrix to our local matrix class 168 | //----------------------------------------------------------------------------- 169 | QMatrix4x4 VirtualRealityApiOpenVR::convertSteamVrMatrixToQMatrix4x4( const vr::HmdMatrix34_t matPose ) 170 | { 171 | return QMatrix4x4(matPose.m[0][0], matPose.m[0][1], matPose.m[0][2], matPose.m[0][3], 172 | matPose.m[1][0], matPose.m[1][1], matPose.m[1][2], matPose.m[1][3], 173 | matPose.m[2][0], matPose.m[2][1], matPose.m[2][2], matPose.m[2][3], 174 | 0.0f, 0.0f, 0.0f, 1.0f); 175 | } 176 | 177 | QMatrix4x4 VirtualRealityApiOpenVR::convertSteamVrMatrixToQMatrix4x4( const vr::HmdMatrix44_t matPose ) 178 | { 179 | return QMatrix4x4(matPose.m[0][0], matPose.m[0][1], matPose.m[0][2], matPose.m[0][3], 180 | matPose.m[1][0], matPose.m[1][1], matPose.m[1][2], matPose.m[1][3], 181 | matPose.m[2][0], matPose.m[2][1], matPose.m[2][2], matPose.m[2][3], 182 | matPose.m[3][0], matPose.m[3][1], matPose.m[3][2], matPose.m[3][3]); 183 | } 184 | 185 | //QMatrix4x4 VirtualRealityApiOpenVR::convertSteamVrMatrixToQMatrix4x4( const vr::HmdMatrix44_t matPose ) 186 | //{ 187 | // return QMatrix4x4(matPose.m[0][0], matPose.m[1][0], matPose.m[2][0], matPose.m[3][0], 188 | // matPose.m[0][1], matPose.m[1][1], matPose.m[2][1], matPose.m[3][1], 189 | // matPose.m[0][2], matPose.m[1][2], matPose.m[2][2], matPose.m[3][2], 190 | // matPose.m[0][3], matPose.m[1][3], matPose.m[2][3], matPose.m[3][3]); 191 | //} 192 | 193 | bool VirtualRealityApiOpenVR::isRuntimeInstalled() 194 | { 195 | return vr::VR_IsRuntimeInstalled(); 196 | } 197 | 198 | VirtualRealityApiOpenVR::VirtualRealityApiOpenVR() 199 | : m_fbo(nullptr) 200 | , m_poseNewEnough(false) 201 | , m_isTrigger(false) 202 | { 203 | 204 | } 205 | 206 | bool VirtualRealityApiOpenVR::isHmdPresent() 207 | { 208 | return vr::VR_IsHmdPresent(); 209 | } 210 | 211 | void VirtualRealityApiOpenVR::initialize() 212 | { 213 | vr::EVRInitError error = vr::VRInitError_None; 214 | m_hmd = vr::VR_Init( &error, vr::VRApplication_Scene ); 215 | 216 | if ( error != vr::VRInitError_None ) 217 | { 218 | m_hmd = NULL; 219 | qDebug() << "Unable to init VR runtime:" << vr::VR_GetVRInitErrorAsEnglishDescription( error ); 220 | return; 221 | } 222 | 223 | m_driver = getTrackedDeviceString( m_hmd, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_TrackingSystemName_String ); 224 | m_display = getTrackedDeviceString( m_hmd, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SerialNumber_String ); 225 | 226 | vr::EVRInitError peError = vr::VRInitError_None; 227 | 228 | if ( !vr::VRCompositor() ) 229 | { 230 | qDebug() << "Compositor initialization failed. See log file for details"; 231 | return; 232 | } 233 | setupCameras(); 234 | 235 | m_fbo = new QOpenGLFramebufferObject(getRenderTargetSize(), QOpenGLFramebufferObject::Depth); 236 | m_fbo->addColorAttachment(m_fbo->size(), GL_RGBA8); 237 | } 238 | 239 | void VirtualRealityApiOpenVR::shutdown() 240 | { 241 | if( m_hmd ) { 242 | vr::VR_Shutdown(); 243 | m_hmd = NULL; 244 | } 245 | if(m_fbo) { 246 | delete m_fbo; 247 | m_fbo = nullptr; 248 | } 249 | } 250 | 251 | 252 | void VirtualRealityApiOpenVR::processVrEvent( const vr::VREvent_t & event ) 253 | { 254 | switch( event.eventType ) 255 | { 256 | case vr::VREvent_TrackedDeviceActivated: 257 | { 258 | // SetupRenderModelForTrackedDevice( event.trackedDeviceIndex ); 259 | qDebug() << "Device" << event.trackedDeviceIndex << "attached. Setting up render model."; 260 | } 261 | break; 262 | case vr::VREvent_TrackedDeviceDeactivated: 263 | { 264 | qDebug() << "Device" << event.trackedDeviceIndex << "detached."; 265 | } 266 | break; 267 | case vr::VREvent_TrackedDeviceUpdated: 268 | { 269 | qDebug() << "Device" << event.trackedDeviceIndex << "updated."; 270 | } 271 | break; 272 | } 273 | } 274 | 275 | bool VirtualRealityApiOpenVR::bindFrambufferObject(int hmdId) 276 | { 277 | return m_fbo->bind(); 278 | } 279 | 280 | qreal VirtualRealityApiOpenVR::refreshRate(int hmdId) const 281 | { 282 | return 90.f; 283 | } 284 | 285 | QMatrix4x4 VirtualRealityApiOpenVR::headPose(int hmdId) 286 | { 287 | updateHmdMatrixPose(); 288 | return m_hmdPose; 289 | } 290 | 291 | QSize VirtualRealityApiOpenVR::getRenderTargetSize() 292 | { 293 | if ( !m_hmd ) return QSize(0, 0); 294 | uint32_t width, height; 295 | m_hmd->GetRecommendedRenderTargetSize( &width, &height ); 296 | return QSize(width*2, height); 297 | //return QSize(width, height); 298 | } 299 | 300 | int VirtualRealityApiOpenVR::timeUntilNextFrame() 301 | { 302 | return 1000/90; 303 | } 304 | 305 | void VirtualRealityApiOpenVR::swapToHeadset() 306 | { 307 | vr::Texture_t leftEyeTexture = {(void*)m_fbo->handle(), vr::TextureType_OpenGL, vr::ColorSpace_Gamma }; 308 | vr::VRTextureBounds_t leftViewport = {0.0f, 0.0f, 0.5f, 1.0f}; 309 | vr::VRCompositor()->Submit(vr::Eye_Left, &leftEyeTexture, &leftViewport ); 310 | vr::Texture_t rightEyeTexture = {(void*)m_fbo->handle(), vr::TextureType_OpenGL, vr::ColorSpace_Gamma }; 311 | vr::VRTextureBounds_t rightViewport = {0.5f, 0.0f, 1.0f, 1.0f}; 312 | vr::VRCompositor()->Submit(vr::Eye_Right, &rightEyeTexture, &rightViewport ); 313 | m_poseNewEnough = false; 314 | // QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); 315 | // f->glFlush(); 316 | // f->glFinish(); 317 | } 318 | 319 | void VirtualRealityApiOpenVR::getEyeMatrices(QMatrix4x4 &leftEye, QMatrix4x4 &rightEye) 320 | { 321 | updateHmdMatrixPose(); 322 | leftEye = getCurrentViewMatrix(vr::Eye_Left); 323 | rightEye = getCurrentViewMatrix(vr::Eye_Right); 324 | } 325 | 326 | void VirtualRealityApiOpenVR::getProjectionMatrices(QMatrix4x4 &leftProjection, QMatrix4x4 &rightProjection) 327 | { 328 | leftProjection = getHmdMatrixProjectionEye( vr::Eye_Left ); 329 | rightProjection = getHmdMatrixProjectionEye( vr::Eye_Right ); 330 | } 331 | 332 | QList VirtualRealityApiOpenVR::currentlyTrackedObjects() 333 | { 334 | QList tracked; 335 | for( uint32_t unTrackedDevice = vr::k_unTrackedDeviceIndex_Hmd + 1; unTrackedDevice < vr::k_unMaxTrackedDeviceCount; unTrackedDevice++ ) { 336 | if( m_hmd->IsTrackedDeviceConnected( unTrackedDevice ) ) 337 | tracked.push_back(unTrackedDevice); 338 | } 339 | return tracked; 340 | } 341 | 342 | void VirtualRealityApiOpenVR::getTrackedObject(int id, QMatrix4x4 &transform) 343 | { 344 | if( id >= vr::k_unMaxTrackedDeviceCount) { 345 | qWarning("Requested tracked object: Index out of bounds."); 346 | return; 347 | } 348 | if( !m_hmd->IsTrackedDeviceConnected( id ) ) { 349 | qWarning((QString("Requested VR Device was not connected. (id: ") + QString::number(id) + ")").toLatin1()); 350 | return; 351 | } 352 | transform = m_devicePose[ id ]; 353 | } 354 | 355 | Qt3DVirtualReality::QVirtualRealityApiBackend::TrackedObjectType VirtualRealityApiOpenVR::getTrackedObjectType(int id) 356 | { 357 | return Qt3DVirtualReality::QVirtualRealityApiBackend::Other; 358 | } 359 | bool VirtualRealityApiOpenVR::isTriggerTmp() 360 | { 361 | return m_isTrigger; 362 | } 363 | 364 | void VirtualRealityApiOpenVR::getTrackedObjectModel(int id, QVector &vertices, QVector &indices, QOpenGLTexture *texture) 365 | { 366 | if( id >= vr::k_unMaxTrackedDeviceCount) { 367 | qWarning("Requested tracked object vertices: Index out of bounds."); 368 | return; 369 | } 370 | 371 | if (m_models.contains(id)){ 372 | vertices = m_models[id]->vertices; 373 | indices = m_models[id]->indices; 374 | texture = m_models[id]->texture; 375 | return; 376 | } 377 | 378 | std::string sRenderModelName = getTrackedDeviceString( m_hmd, id, vr::Prop_RenderModelName_String ); 379 | 380 | //TODO: load renderModels only once 381 | 382 | vr::RenderModel_t *pModel; 383 | vr::EVRRenderModelError error; 384 | while ( 1 ) { 385 | error = vr::VRRenderModels()->LoadRenderModel_Async( sRenderModelName.c_str(), &pModel ); 386 | if ( error != vr::VRRenderModelError_Loading ) 387 | break; 388 | QThread::currentThread()->sleep( 1 ); 389 | } 390 | 391 | if ( error != vr::VRRenderModelError_None ) { 392 | qWarning( "Unable to load render model %s - %s\n", sRenderModelName.c_str(), vr::VRRenderModels()->GetRenderModelErrorNameFromEnum( error ) ); 393 | return; 394 | } 395 | 396 | vr::RenderModel_TextureMap_t *pTexture; 397 | while ( 1 ) { 398 | error = vr::VRRenderModels()->LoadTexture_Async( pModel->diffuseTextureId, &pTexture ); 399 | if ( error != vr::VRRenderModelError_Loading ) 400 | break; 401 | QThread::currentThread()->sleep( 1 ); 402 | } 403 | 404 | if ( error != vr::VRRenderModelError_None ) { 405 | qWarning( "Unable to load render texture id:%d for render model %s\n", pModel->diffuseTextureId, sRenderModelName.c_str() ); 406 | vr::VRRenderModels()->FreeRenderModel( pModel ); 407 | return; 408 | } 409 | 410 | //Position, Normal, Texture 411 | vertices.resize(pModel->unVertexCount * (3 + 3 + 2)); 412 | memcpy(vertices.data(), pModel->rVertexData, sizeof(float) * vertices.size()); 413 | indices.resize(pModel->unTriangleCount * 3); 414 | for(int i=0; iunTriangleCount; i++) { 415 | indices[i*3 ] = pModel->rIndexData[i*3 ]; 416 | indices[i*3+1] = pModel->rIndexData[i*3+1]; 417 | indices[i*3+2] = pModel->rIndexData[i*3+2]; 418 | } 419 | 420 | //texture = new QOpenGLTexture(QOpenGLTexture::BindingTarget2D); 421 | texture->setSize(pTexture->unWidth, pTexture->unHeight); 422 | texture->setData( QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, pTexture->rubTextureMapData ); 423 | 424 | m_models.insert(id,new TrackedObjectModel(vertices, indices, texture)); 425 | 426 | vr::VRRenderModels()->FreeRenderModel( pModel ); 427 | vr::VRRenderModels()->FreeTexture( pTexture ); 428 | } 429 | 430 | void VirtualRealityApiOpenVR::getMirrorTexture(QOpenGLTexture *outMirrorTexture) 431 | { 432 | 433 | } 434 | #endif 435 | --------------------------------------------------------------------------------