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:
parent
5bf9a32437
commit
bb0d7fc0a7
4 changed files with 111 additions and 11 deletions
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue