1
0
Fork 0

src/Viewer: Move splash to cam group camera

Move the splash screen from the scene root to a camera group camera,
just below the GUI camera. This has a number of advantages, mainly VR
related:
 - The splash FBO will only be rendered once per frame. Currently it
   appears to be rendered for both near & far cameras, and with
   stereoscopic rendering for both left & right (even though it splats
   right across both views at the moment), so 2 or 4 times.
 - It makes it possible to render the splash fullscreen on the desktop
   window, while presenting it on a 3d quad in VR (possibly via an
   OpenXR composition layer so the runtime can keep rendering it
   smoothly while FlightGear framerate drops during loading.
This commit is contained in:
James Hogan 2022-02-09 23:11:17 +00:00
parent 5bf9a32437
commit bb0d7fc0a7
No known key found for this signature in database
GPG key ID: 35CEE4862B1023F2
4 changed files with 111 additions and 11 deletions

View file

@ -23,6 +23,7 @@
#include "FGEventHandler.hxx" #include "FGEventHandler.hxx"
#include "WindowBuilder.hxx" #include "WindowBuilder.hxx"
#include "WindowSystemAdapter.hxx" #include "WindowSystemAdapter.hxx"
#include "splash.hxx"
#include "sview.hxx" #include "sview.hxx"
#include "VRManager.hxx" #include "VRManager.hxx"
@ -211,7 +212,7 @@ void CameraGroup::update(const osg::Vec3d& position,
for (const auto &info : _cameras) { for (const auto &info : _cameras) {
osg::Matrix view_matrix; osg::Matrix view_matrix;
if (info->flags & CameraInfo::GUI) if (info->flags & (CameraInfo::SPLASH | CameraInfo::GUI))
view_matrix = osg::Matrix::identity(); view_matrix = osg::Matrix::identity();
else if ((info->flags & CameraInfo::VIEW_ABSOLUTE) != 0) else if ((info->flags & CameraInfo::VIEW_ABSOLUTE) != 0)
view_matrix = info->viewOffset; view_matrix = info->viewOffset;
@ -219,7 +220,7 @@ void CameraGroup::update(const osg::Vec3d& position,
view_matrix = masterView * info->viewOffset; view_matrix = masterView * info->viewOffset;
osg::Matrix proj_matrix; osg::Matrix proj_matrix;
if (info->flags & CameraInfo::GUI) { if (info->flags & (CameraInfo::SPLASH | CameraInfo::GUI)) {
const osg::GraphicsContext::Traits *traits = const osg::GraphicsContext::Traits *traits =
info->compositor->getGraphicsContext()->getTraits(); info->compositor->getGraphicsContext()->getTraits();
proj_matrix = osg::Matrix::ortho2D(0, traits->width, 0, traits->height); proj_matrix = osg::Matrix::ortho2D(0, traits->width, 0, traits->height);
@ -254,7 +255,8 @@ void CameraGroup::update(const osg::Vec3d& position,
} }
osg::Matrix new_proj_matrix = proj_matrix; osg::Matrix new_proj_matrix = proj_matrix;
if ((info->flags & CameraInfo::GUI) == 0 && if ((info->flags & CameraInfo::SPLASH) == 0 &&
(info->flags & CameraInfo::GUI) == 0 &&
(info->flags & CameraInfo::FIXED_NEAR_FAR) == 0) { (info->flags & CameraInfo::FIXED_NEAR_FAR) == 0) {
makeNewProjMat(proj_matrix, _zNear, _zFar, new_proj_matrix); makeNewProjMat(proj_matrix, _zNear, _zFar, new_proj_matrix);
} }
@ -741,6 +743,78 @@ void CameraGroup::removeCamera(CameraInfo *info)
} }
} }
void CameraGroup::buildSplashCamera(SGPropertyNode* cameraNode,
GraphicsWindow* window)
{
WindowBuilder* wBuild = WindowBuilder::getWindowBuilder();
const SGPropertyNode* windowNode = (cameraNode
? cameraNode->getNode("window")
: 0);
if (!window && windowNode) {
// New style window declaration / definition
window = wBuild->buildWindow(windowNode, true /*isMainWindow*/);
}
if (!window) { // buildWindow can fail
SG_LOG(SG_VIEW, SG_WARN, "CameraGroup::buildSplashCamera: failed to build a window");
return;
}
Camera* camera = new Camera;
camera->setName("SplashCamera");
camera->setAllowEventFocus(false);
camera->setGraphicsContext(window->gc.get());
// If a viewport isn't set on the camera, then it's hard to dig it
// out of the SceneView objects in the viewer, and the coordinates
// of mouse events are somewhat bizzare.
osg::Viewport* viewport = new osg::Viewport(
0, 0, window->gc->getTraits()->width, window->gc->getTraits()->height);
camera->setViewport(viewport);
camera->setClearMask(0);
camera->setInheritanceMask(CullSettings::ALL_VARIABLES
& ~(CullSettings::COMPUTE_NEAR_FAR_MODE
| CullSettings::CULLING_MODE
| CullSettings::CLEAR_MASK
));
camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
camera->setCullingMode(osg::CullSettings::NO_CULLING);
camera->setProjectionResizePolicy(osg::Camera::FIXED);
// The camera group will always update the camera
camera->setReferenceFrame(Transform::ABSOLUTE_RF);
// XXX Camera needs to be drawn just before GUI; eventually the render order
// should be assigned by a camera manager.
camera->setRenderOrder(osg::Camera::POST_RENDER, 9999);
// Add splash screen!
camera->addChild(globals->get_renderer()->getSplash());
Pass* pass = new Pass;
pass->camera = camera;
pass->useMastersSceneData = false;
// For now we just build a simple Compositor directly from C++ space that
// encapsulates a single osg::Camera. This could be improved by letting
// users change the Compositor config in XML space, for example to be able
// to add post-processing to a HUD.
// However, since many other parts of FG require direct access to the GUI
// osg::Camera object, this is fine for now.
Compositor* compositor = new Compositor(_viewer, window->gc, viewport);
compositor->addPass(pass);
const int cameraFlags = CameraInfo::SPLASH;
CameraInfo* info = new CameraInfo(cameraFlags);
info->name = "Splash camera";
info->viewOffset = osg::Matrix::identity();
info->projOffset = osg::Matrix::identity();
info->compositor.reset(compositor);
_cameras.push_back(info);
// Disable statistics for the splash camera.
camera->setStats(0);
}
void CameraGroup::buildGUICamera(SGPropertyNode* cameraNode, void CameraGroup::buildGUICamera(SGPropertyNode* cameraNode,
GraphicsWindow* window) GraphicsWindow* window)
{ {
@ -874,6 +948,8 @@ CameraGroup* CameraGroup::buildCameraGroup(osgViewer::View* view,
cgroup->buildCamera(pNode); cgroup->buildCamera(pNode);
} else if (name == "window") { } else if (name == "window") {
WindowBuilder::getWindowBuilder()->buildWindow(pNode); WindowBuilder::getWindowBuilder()->buildWindow(pNode);
} else if (name == "splash") {
cgroup->buildSplashCamera(pNode);
} else if (name == "gui") { } else if (name == "gui") {
cgroup->buildGUICamera(pNode); cgroup->buildGUICamera(pNode);
} }
@ -1033,8 +1109,8 @@ void reloadCompositors(CameraGroup *cgroup)
Compositor::resetOrderOffset(); Compositor::resetOrderOffset();
for (auto &info : cgroup->_cameras) { for (auto &info : cgroup->_cameras) {
// Ignore the GUI camera // Ignore the splash & GUI camera
if (info->flags & CameraInfo::GUI) if (info->flags & (CameraInfo::SPLASH | CameraInfo::GUI))
continue; continue;
// Get the viewport and the graphics context from the old Compositor // Get the viewport and the graphics context from the old Compositor
osg::ref_ptr<osg::Viewport> viewport = info->compositor->getViewport(); osg::ref_ptr<osg::Viewport> viewport = info->compositor->getViewport();
@ -1109,9 +1185,12 @@ void CameraGroup::buildDefaultGroup(osgViewer::View* viewer)
setValue(masterCamera->getNode("vr-mirror", true), true); setValue(masterCamera->getNode("vr-mirror", true), true);
} }
SGPropertyNode* nameNode = masterCamera->getNode("window/name"); SGPropertyNode* nameNode = masterCamera->getNode("window/name");
if (nameNode) if (nameNode) {
setValue(cgroupNode->getNode("gui/window/name", true), setValue(cgroupNode->getNode("gui/window/name", true),
nameNode->getStringValue()); nameNode->getStringValue());
setValue(cgroupNode->getNode("splash/window/name", true),
nameNode->getStringValue());
}
} }
CameraGroup* cgroup = buildCameraGroup(viewer, cgroupNode); CameraGroup* cgroup = buildCameraGroup(viewer, cgroupNode);

View file

@ -71,7 +71,8 @@ struct CameraInfo : public osg::Referenced
FIXED_NEAR_FAR = 0x20, /**< take the near far values in the FIXED_NEAR_FAR = 0x20, /**< take the near far values in the
projection for real. */ 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. */ VR_MIRROR = 0x80, /**< Switch to a mirror of VR. */
SPLASH = 0x100 /**< For splash screen. */
}; };
CameraInfo(unsigned flags_) : CameraInfo(unsigned flags_) :
@ -165,6 +166,16 @@ public:
* @param info the camera info to remove. * @param info the camera info to remove.
*/ */
void removeCamera(CameraInfo *info); void removeCamera(CameraInfo *info);
/** Create a camera from properties that will draw the splash screen and add
* it to the camera group.
* @param cameraNode the property node. This can be 0, in which
* case a default GUI camera is created.
* @param window the GraphicsWindow to use for the splash camera. If
* this is 0, the window is determined from the property node.
* @return a CameraInfo object for the GUI camera.
*/
void buildSplashCamera(SGPropertyNode* cameraNode,
GraphicsWindow* window = 0);
/** Create a camera from properties that will draw the GUI and add /** Create a camera from properties that will draw the GUI and add
* it to the camera group. * it to the camera group.
* @param cameraNode the property node. This can be 0, in which * @param cameraNode the property node. This can be 0, in which

View file

@ -345,7 +345,8 @@ bool FGScenerySwitchCallback::scenery_enabled = false;
FGRenderer::FGRenderer() : FGRenderer::FGRenderer() :
_sky(NULL), _sky(NULL),
MaximumTextureSize(0) MaximumTextureSize(0),
_splash(nullptr)
{ {
_root = new osg::Group; _root = new osg::Group;
_root->setName("fakeRoot"); _root->setName("fakeRoot");
@ -427,8 +428,7 @@ FGRenderer::preinit( void )
view->setDatabasePager(FGScenery::getPagerSingleton()); view->setDatabasePager(FGScenery::getPagerSingleton());
_quickDrawable = nullptr; _quickDrawable = nullptr;
_splash = new SplashScreen; getSplash();
_viewerSceneRoot->addChild(_splash);
if (composite_viewer) { if (composite_viewer) {
// Nothing to do - composite_viewer->addView() will tell view to use // Nothing to do - composite_viewer->addView() will tell view to use
@ -1166,6 +1166,14 @@ FGRenderer::setPlanes( double zNear, double zFar )
// _planes->set( osg::Vec3f( - zFar, - zFar * zNear, zFar - zNear ) ); // _planes->set( osg::Vec3f( - zFar, - zFar * zNear, zFar - zNear ) );
} }
SplashScreen*
FGRenderer::getSplash()
{
if (!_splash)
_splash = new SplashScreen;
return _splash;
}
bool bool
fgDumpSceneGraphToFile(const char* filename) fgDumpSceneGraphToFile(const char* filename)
{ {

View file

@ -99,6 +99,8 @@ public:
void setPlanes( double zNear, double zFar ); void setPlanes( double zNear, double zFar );
SplashScreen* getSplash();
protected: protected:
int composite_viewer_enabled = -1; int composite_viewer_enabled = -1;
osg::ref_ptr<osgViewer::Viewer> viewer; osg::ref_ptr<osgViewer::Viewer> viewer;
@ -133,7 +135,7 @@ protected:
void setupRoot(); void setupRoot();
SplashScreen* _splash; osg::ref_ptr<SplashScreen> _splash;
QQuickDrawable* _quickDrawable = nullptr; QQuickDrawable* _quickDrawable = nullptr;
flightgear::PUICamera* _puiCamera = nullptr; flightgear::PUICamera* _puiCamera = nullptr;
}; };