1
0
Fork 0

VR: Implement mirroring of VR to desktop

Set up the default camera as a mirror of the VR view when needed, using
a new CameraInfo flag named VR_MIRROR based on a camera property
"vr-mirror" which is set on the default camera group. When set this flag
causes the compositor to be constructed (and reloaded) using
buildVRMirrorCompositor() and osgXR's mirror camera setup code, rather
than the usual Compositor::create().
This commit is contained in:
James Hogan 2021-08-05 09:29:28 +01:00
parent 7bea10a8e4
commit 7db47beb0e
No known key found for this signature in database
GPG key ID: 35CEE4862B1023F2
4 changed files with 101 additions and 11 deletions

View file

@ -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)

View file

@ -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.

View file

@ -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];

View file

@ -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);