diff --git a/src/Viewer/CameraGroup.cxx b/src/Viewer/CameraGroup.cxx index 3ec5f6853..586e5bbad 100644 --- a/src/Viewer/CameraGroup.cxx +++ b/src/Viewer/CameraGroup.cxx @@ -24,6 +24,7 @@ #include "WindowBuilder.hxx" #include "WindowSystemAdapter.hxx" #include "sview.hxx" +#include "VRManager.hxx" #include <simgear/math/SGRect.hxx> #include <simgear/props/props.hxx> @@ -494,6 +495,10 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode) return nullptr; } + // Set vr-mirror flag so camera switches to VR mirror when appropriate. + if (cameraNode->getBoolValue("vr-mirror", false)) + cameraFlags |= CameraInfo::VR_MIRROR; + osg::Matrix vOff; const SGPropertyNode* viewNode = cameraNode->getNode("view"); if (viewNode) { @@ -700,11 +705,16 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode) SViewSetCompositorParams(options, compositor_path); - Compositor *compositor = Compositor::create(_viewer, - window->gc, - viewport, - compositor_path, - options); + Compositor *compositor = nullptr; + if (info->flags & CameraInfo::VR_MIRROR) + compositor = buildVRMirrorCompositor(window->gc, viewport); + if (!compositor) + compositor = Compositor::create(_viewer, + window->gc, + viewport, + compositor_path, + options); + if (compositor) { info->compositor.reset(compositor); } else { @@ -807,6 +817,50 @@ void CameraGroup::buildGUICamera(SGPropertyNode* cameraNode, camera->setStats(0); } +Compositor *CameraGroup::buildVRMirrorCompositor(osg::GraphicsContext* gc, + osg::Viewport *viewport) +{ +#ifdef ENABLE_OSGXR + if (VRManager::instance()->getUseMirror()) { + Camera* camera = new Camera; + camera->setName("VRMirror"); + camera->setAllowEventFocus(false); + camera->setGraphicsContext(gc); + camera->setViewport(viewport); + camera->setClearMask(0); + camera->setInheritanceMask(CullSettings::ALL_VARIABLES + & ~(CullSettings::COMPUTE_NEAR_FAR_MODE + | CullSettings::CULLING_MODE + | CullSettings::CLEAR_MASK + )); + camera->setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR); + camera->setCullingMode(CullSettings::NO_CULLING); + camera->setProjectionResizePolicy(Camera::FIXED); + + // The camera group will always update the camera + camera->setReferenceFrame(Transform::ABSOLUTE_RF); + + // Mirror camera needs to be drawn after VR cameras and before GUI + camera->setRenderOrder(Camera::POST_RENDER, 9000); + + // Let osgXR do the mirror camera setup + VRManager::instance()->setupMirrorCamera(camera); + + Pass *pass = new Pass; + pass->camera = camera; + pass->useMastersSceneData = false; + + // We just build a simple Compositor directly from C++ space that + // encapsulates a single osg::Camera. + Compositor *compositor = new Compositor(_viewer, gc, viewport); + compositor->addPass(pass); + + return compositor; + } +#endif + return nullptr; +} + CameraGroup* CameraGroup::buildCameraGroup(osgViewer::View* view, SGPropertyNode* gnode) { @@ -994,11 +1048,16 @@ void reloadCompositors(CameraGroup *cgroup) std::string compositor_path = info->compositor_path.empty() ? fgGetString("/sim/rendering/default-compositor", "Compositor/default") : info->compositor_path; - info->compositor.reset(Compositor::create(cgroup->_viewer, - gc, - viewport, - compositor_path, - options)); + Compositor *compositor = nullptr; + if (info->flags & CameraInfo::VR_MIRROR) + compositor = cgroup->buildVRMirrorCompositor(gc, viewport); + if (!compositor) + compositor = Compositor::create(cgroup->_viewer, + gc, + viewport, + compositor_path, + options); + info->compositor.reset(compositor); if (info->reloadCompositorCallback.valid()) info->reloadCompositorCallback->postReloadCompositor(cgroup, info); @@ -1041,6 +1100,8 @@ void CameraGroup::buildDefaultGroup(osgViewer::View* viewer) masterCamera = cgroupNode->getChild("camera", cameras.size(), true); setValue(masterCamera->getNode("window/name", true), windowBuilder->getDefaultWindowName()); + // Use VR mirror compositor when VR is enabled. + setValue(masterCamera->getNode("vr-mirror", true), true); } SGPropertyNode* nameNode = masterCamera->getNode("window/name"); if (nameNode) diff --git a/src/Viewer/CameraGroup.hxx b/src/Viewer/CameraGroup.hxx index 6e0bc58aa..ce5ccf363 100644 --- a/src/Viewer/CameraGroup.hxx +++ b/src/Viewer/CameraGroup.hxx @@ -70,7 +70,8 @@ struct CameraInfo : public osg::Referenced camera. */ FIXED_NEAR_FAR = 0x20, /**< take the near far values in the projection for real. */ - ENABLE_MASTER_ZOOM = 0x40 /**< Can apply the zoom algorithm. */ + ENABLE_MASTER_ZOOM = 0x40, /**< Can apply the zoom algorithm. */ + VR_MIRROR = 0x80 /**< Switch to a mirror of VR. */ }; CameraInfo(unsigned flags_) : @@ -224,6 +225,13 @@ protected: float _zFar; float _nearField; + /** Create a compositor for a VR mirror. + * @param gc the graphics context to use. + * @param viewport the viewport to render to. + * @return a new compositor or nullptr if no VR mirror is needed. + */ + simgear::compositor::Compositor *buildVRMirrorCompositor(osg::GraphicsContext *gc, + osg::Viewport *viewport); /** Build a complete CameraGroup from a property node. * @param viewer the viewer associated with this camera group. * @param wbuilder the window builder to be used for this camera group. diff --git a/src/Viewer/VRManager.cxx b/src/Viewer/VRManager.cxx index 6da3b72d8..5159614b3 100644 --- a/src/Viewer/VRManager.cxx +++ b/src/Viewer/VRManager.cxx @@ -232,6 +232,24 @@ void VRManager::doDestroyView(osgXR::View *xrView) } } +void VRManager::onRunning() +{ + // Reload compositors to trigger switch to mirror of VR + CameraGroup *cgroup = CameraGroup::getDefault(); + reloadCompositors(cgroup); +} + +void VRManager::onStopped() +{ + // As long as we're not in the process of destroying FlightGear, reload + // compositors to trigger switch away from mirror of VR + if (!isDestroying()) + { + CameraGroup *cgroup = CameraGroup::getDefault(); + reloadCompositors(cgroup); + } +} + void VRManager::preReloadCompositor(CameraGroup *cgroup, CameraInfo *info) { osgXR::View *xrView = _xrViews[info]; diff --git a/src/Viewer/VRManager.hxx b/src/Viewer/VRManager.hxx index 6c1c61020..71694a1bf 100644 --- a/src/Viewer/VRManager.hxx +++ b/src/Viewer/VRManager.hxx @@ -90,6 +90,9 @@ class VRManager : public osgXR::Manager void doCreateView(osgXR::View *xrView) override; void doDestroyView(osgXR::View *xrView) override; + void onRunning() override; + void onStopped() override; + void preReloadCompositor(CameraGroup *cgroup, CameraInfo *info); void postReloadCompositor(CameraGroup *cgroup, CameraInfo *info);