From b9efba55e7bc2dc458901a4eb9b6602454d2d7db Mon Sep 17 00:00:00 2001 From: James Hogan <james@albanarts.com> Date: Wed, 15 Jun 2022 23:57:33 +0100 Subject: [PATCH] src/Viewer/splash: VR splash screen Use a quad composition layer object from osgXR 0.3.9 to make the splash screen VR friendly. This allows the OpenXR compositor to redraw the quad without any updates from flightgear, which is particularly helpful as flightgear makes no attempt at a reasonable VR frame rate during initialisation. The quad is positioned 2 meters from the user, with an aspect ratio matching the desktop window. The quad is blended using an unpremultiplied alpha channel which is forced to a given alpha value by osgXR. The splash is effectively already rendered to an FBO as non-linear SRGB, so this is made explicit in the internal texture format, with the rendering to the desktop window using GL_FRAMEBUFFER_SRGB to ensure it is properly re-encoded. --- CMakeLists.txt | 2 +- src/Viewer/splash.cxx | 38 +++++++++++++++++++++++++++++++++++++- src/Viewer/splash.hxx | 14 ++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 99e8c3ab9..29ac80778 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,7 +158,7 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR endif() if (ENABLE_VR_DEFAULT) - find_package(osgXR 0.3.3 QUIET) + find_package(osgXR 0.3.9 QUIET) if (osgXR_FOUND) set(SYSTEM_OSGXR_DEFAULT 1) endif() diff --git a/src/Viewer/splash.cxx b/src/Viewer/splash.cxx index 6a874559d..8fec18368 100644 --- a/src/Viewer/splash.cxx +++ b/src/Viewer/splash.cxx @@ -57,6 +57,7 @@ #include <Main/util.hxx> #include "splash.hxx" #include "renderer.hxx" +#include "VRManager.hxx" #include <sstream> @@ -79,6 +80,19 @@ public: SplashScreen::SplashScreen() : _splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true)) { +#ifdef ENABLE_OSGXR + uint32_t splashW = 1920, splashH = 1080; + float aspect = (float)splashW / splashH; + _splashSwapchain = new osgXR::Swapchain(splashW, splashH); + _splashSwapchain->setAlphaBits(8); + _splashSwapchain->allowRGBEncoding(osgXR::Swapchain::Encoding::ENCODING_SRGB); + _splashLayer = new osgXR::CompositionLayerQuad(flightgear::VRManager::instance()); + _splashLayer->setSubImage(_splashSwapchain); + _splashLayer->setSize(osg::Vec2f(aspect, 1.0f)); + _splashLayer->setPosition(osg::Vec3f(0, 0, -2.0f)); + _splashLayer->setAlphaMode(osgXR::CompositionLayer::BLEND_ALPHA_UNPREMULT); +#endif + setName("splashGroup"); setUpdateCallback(new SplashScreenUpdateCallback); } @@ -91,7 +105,7 @@ void SplashScreen::createNodes() { // setup the base geometry _splashFBOTexture = new osg::Texture2D; - _splashFBOTexture->setInternalFormat(GL_RGB); + _splashFBOTexture->setInternalFormat(GL_SRGB8); _splashFBOTexture->setResizeNonPowerOfTwoHint(false); _splashFBOTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); _splashFBOTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); @@ -226,6 +240,7 @@ void SplashScreen::createNodes() stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); stateSet->setRenderBinDetails(1000, "RenderBin"); stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + stateSet->setMode(GL_FRAMEBUFFER_SRGB, osg::StateAttribute::ON); geometry = osg::createTexturedQuadGeometry(osg::Vec3(0.0, 0.0, 0.0), osg::Vec3(1.0, 0.0, 0.0), @@ -244,6 +259,9 @@ void SplashScreen::createNodes() geode = new osg::Geode; geode->addDrawable(geometry); +#ifdef ENABLE_OSGXR + _splashSwapchain->attachToMirror(stateSet); +#endif _splashQuadCamera->addChild(geode); addChild(_splashQuadCamera); } @@ -325,6 +343,9 @@ osg::ref_ptr<osg::Camera> SplashScreen::createFBOCamera() c->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); c->setRenderOrder(osg::Camera::PRE_RENDER); c->attach(osg::Camera::COLOR_BUFFER, _splashFBOTexture); +#ifdef ENABLE_OSGXR + _splashSwapchain->attachToCamera(c); +#endif osg::StateSet* stateSet = c->getOrCreateStateSet(); stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF); @@ -570,11 +591,18 @@ void SplashScreen::doUpdate() removeChild(0, getNumChildren()); _splashFBOCamera = nullptr; _splashQuadCamera = nullptr; +#ifdef ENABLE_OSGXR + _splashLayer->setVisible(false); +#endif } else if (getNumChildren() == 0) { createNodes(); _splashStartTime.stamp(); resize(fgGetInt("/sim/startup/xsize"), fgGetInt("/sim/startup/ysize")); +#ifdef ENABLE_OSGXR + _splashLayer->setVisible(true); + _splashSwapchain->setForcedAlpha(alpha); +#endif } else { (*_splashFSQuadColor)[0] = osg::Vec4(1.0, 1.0, 1.0, _splashAlphaNode->getFloatValue()); _splashFSQuadColor->dirty(); @@ -603,6 +631,9 @@ void SplashScreen::doUpdate() } updateSplashSpinner(); updateTipText(); +#ifdef ENABLE_OSGXR + _splashSwapchain->setForcedAlpha(alpha); +#endif } } @@ -686,6 +717,11 @@ void SplashScreen::resize( int width, int height ) _splashFBOCamera->setViewport(0, 0, width, height); _splashFBOCamera->setProjectionMatrixAsOrtho2D(-width * 0.5, width * 0.5, -height * 0.5, height * 0.5); +#ifdef ENABLE_OSGXR + float aspect = (float)width / height; + _splashSwapchain->setSize(width, height); + _splashLayer->setSize(osg::Vec2f(aspect, 1.0f)); +#endif const double screenAspectRatio = static_cast<double>(width) / height; diff --git a/src/Viewer/splash.hxx b/src/Viewer/splash.hxx index 9350c8225..5b50059a4 100644 --- a/src/Viewer/splash.hxx +++ b/src/Viewer/splash.hxx @@ -25,9 +25,16 @@ #ifndef _SPLASH_HXX #define _SPLASH_HXX +#include <config.h> + #include <osg/Group> #include <osgText/Text> +#ifdef ENABLE_OSGXR +#include <osgXR/CompositionLayerQuad> +#include <osgXR/Swapchain> +#endif + #include <simgear/props/props.hxx> #include <simgear/timing/timestamp.hxx> @@ -117,6 +124,13 @@ private: osg::ref_ptr<osg::Camera> _splashQuadCamera; std::vector<ImageItem> _imageItems; + +#ifdef ENABLE_OSGXR + // Splash as OpenXR composition layer + osg::ref_ptr<osgXR::Swapchain> _splashSwapchain; + osg::ref_ptr<osgXR::CompositionLayerQuad> _splashLayer; +#endif + std::vector<TextItem> _items; SGTimeStamp _splashStartTime;