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:
parent
7bea10a8e4
commit
7db47beb0e
4 changed files with 101 additions and 11 deletions
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue