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