More stereo-postprocessing integration

post_malone
Mads Buvik Sandvei 3 years ago committed by Petr Mikheev
parent fa29dd05fc
commit 6dc727cf8f

@ -130,11 +130,24 @@ namespace MWRender
state.pushStateSet(mFallbackStateSet); state.pushStateSet(mFallbackStateSet);
state.apply(); state.apply();
if (Stereo::getMultiview() && mMultiviewResolveProgram)
{
state.pushStateSet(mMultiviewResolveStateSet);
state.apply();
}
state.applyTextureAttribute(0, bufferData.sceneTex); state.applyTextureAttribute(0, bufferData.sceneTex);
resolveViewport->apply(state); resolveViewport->apply(state);
drawGeometry(renderInfo); drawGeometry(renderInfo);
state.popStateSet(); state.popStateSet();
if (Stereo::getMultiview() && mMultiviewResolveProgram)
{
state.popStateSet();
}
return; return;
} }

@ -2,6 +2,8 @@
#include <osg/Camera> #include <osg/Camera>
#include <osg/FrameBufferObject> #include <osg/FrameBufferObject>
#include <osg/Texture>
#include <osg/Texture2DArray>
#include <osgUtil/CullVisitor> #include <osgUtil/CullVisitor>
#include <components/stereo/stereomanager.hpp> #include <components/stereo/stereomanager.hpp>
@ -12,6 +14,7 @@
namespace MWRender namespace MWRender
{ {
PingPongCull::PingPongCull(PostProcessor* pp) PingPongCull::PingPongCull(PostProcessor* pp)
: mViewportStateset(nullptr) : mViewportStateset(nullptr)
, mPostProcessor(pp) , mPostProcessor(pp)
@ -66,6 +69,11 @@ namespace MWRender
{ {
renderStage->setMultisampleResolveFramebufferObject(postProcessor->getFbo(PostProcessor::FBO_Primary, frameId)); renderStage->setMultisampleResolveFramebufferObject(postProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId)); renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId));
// The MultiView patch has a bug where it does not update resolve layers if the resolve framebuffer is changed.
// So we do blit manually in this case
if (Stereo::getMultiview() && !renderStage->getDrawCallback())
Stereo::setMultiviewMSAAResolveCallback(renderStage);
} }
if (mViewportStateset) if (mViewportStateset)

@ -86,6 +86,14 @@ namespace
case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_2D_ARRAY:
static_cast<osg::Texture2DArray*>(tex)->setTextureSize(w, h, 2); static_cast<osg::Texture2DArray*>(tex)->setTextureSize(w, h, 2);
break; break;
case GL_TEXTURE_2D_MULTISAMPLE:
static_cast<osg::Texture2DMultisample*>(tex)->setTextureSize(w, h);
break;
#ifdef OSG_HAS_MULTIVIEW
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
static_cast<osg::Texture2DMultisampleArray*>(tex)->setTextureSize(w, h, 2);
break;
#endif
default: default:
throw std::logic_error("Invalid texture type received"); throw std::logic_error("Invalid texture type received");
} }
@ -233,7 +241,7 @@ namespace MWRender
mUBO = ext && ext->isUniformBufferObjectSupported && mGLSLVersion >= 330; mUBO = ext && ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
mStateUpdater = new fx::StateUpdater(mUBO); mStateUpdater = new fx::StateUpdater(mUBO);
if (!SceneUtil::AutoDepth::isReversed() && !mSoftParticles && !mUsePostProcessing) if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !mSoftParticles && !mUsePostProcessing)
return; return;
enable(mUsePostProcessing); enable(mUsePostProcessing);

@ -7,6 +7,10 @@
#include <osgUtil/RenderStage> #include <osgUtil/RenderStage>
#include <osgUtil/CullVisitor> #include <osgUtil/CullVisitor>
#ifdef OSG_HAS_MULTIVIEW
#include <osg/Texture2DMultisampleArray>
#endif
#include <components/sceneutil/nodecallback.hpp> #include <components/sceneutil/nodecallback.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
@ -242,6 +246,97 @@ namespace Stereo
return texture2d; return texture2d;
} }
#ifdef OSG_HAS_MULTIVIEW
//! Draw callback that, if set on a RenderStage, resolves MSAA after draw. Needed when using custom fbo/resolve fbos on renderstages in combination with multiview.
struct MultiviewMSAAResolveCallback : public osgUtil::RenderBin::DrawCallback
{
void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) override
{
osgUtil::RenderStage* stage = static_cast<osgUtil::RenderStage*>(bin);
auto msaaFbo = stage->getFrameBufferObject();
auto resolveFbo = stage->getMultisampleResolveFramebufferObject();
if (msaaFbo != mMsaaFbo)
{
mMsaaFbo = msaaFbo;
setupMsaaLayers();
}
if (resolveFbo != mFbo)
{
mFbo = resolveFbo;
setupLayers();
}
// Null the resolve framebuffer to keep osg from doing redundant work.
stage->setMultisampleResolveFramebufferObject(nullptr);
// Do the actual render work
bin->drawImplementation(renderInfo, previous);
// Blit layers
osg::State& state = *renderInfo.getState();
osg::GLExtensions* ext = state.get<osg::GLExtensions>();
for (int i = 0; i < 2; i++)
{
mLayers[i]->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
mMsaaLayers[i]->apply(state, osg::FrameBufferObject::READ_FRAMEBUFFER);
ext->glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
msaaFbo->apply(state, osg::FrameBufferObject::READ_DRAW_FRAMEBUFFER);
}
void setupLayers()
{
const auto& attachments = mFbo->getAttachmentMap();
for (int i = 0; i < 2; i++)
{
mLayers[i] = new osg::FrameBufferObject;
// Intentionally not using ref& so attachment can be non-const
for (auto [component, attachment] : attachments)
{
osg::Texture2DArray* texture = static_cast<osg::Texture2DArray*>(attachment.getTexture());
mLayers[i]->setAttachment(component, osg::FrameBufferAttachment(texture, i));
mWidth = texture->getTextureWidth();
mHeight = texture->getTextureHeight();
}
}
}
void setupMsaaLayers()
{
const auto& attachments = mMsaaFbo->getAttachmentMap();
for (int i = 0; i < 2; i++)
{
mMsaaLayers[i] = new osg::FrameBufferObject;
// Intentionally not using ref& so attachment can be non-const
for (auto [component, attachment] : attachments)
{
osg::Texture2DMultisampleArray* texture = static_cast<osg::Texture2DMultisampleArray*>(attachment.getTexture());
mMsaaLayers[i]->setAttachment(component, osg::FrameBufferAttachment(texture, i));
mWidth = texture->getTextureWidth();
mHeight = texture->getTextureHeight();
}
}
}
osg::ref_ptr<osg::FrameBufferObject> mFbo;
osg::ref_ptr<osg::FrameBufferObject> mMsaaFbo;
osg::ref_ptr<osg::FrameBufferObject> mLayers[2];
osg::ref_ptr<osg::FrameBufferObject> mMsaaLayers[2];
int mWidth;
int mHeight;
};
#endif
void setMultiviewMSAAResolveCallback(osgUtil::RenderStage* renderStage)
{
#ifdef OSG_HAS_MULTIVIEW
if (Stereo::getMultiview())
{
renderStage->setDrawCallback(new MultiviewMSAAResolveCallback);
}
#endif
}
class UpdateRenderStagesCallback : public SceneUtil::NodeCallback<UpdateRenderStagesCallback, osg::Node*, osgUtil::CullVisitor*> class UpdateRenderStagesCallback : public SceneUtil::NodeCallback<UpdateRenderStagesCallback, osg::Node*, osgUtil::CullVisitor*>
{ {
public: public:

@ -16,6 +16,11 @@ namespace osg
class Texture2DArray; class Texture2DArray;
} }
namespace osgUtil
{
class RenderStage;
}
namespace Stereo namespace Stereo
{ {
class UpdateRenderStagesCallback; class UpdateRenderStagesCallback;
@ -35,6 +40,9 @@ namespace Stereo
//! Creates a Texture2D as a texture view into a Texture2DArray //! Creates a Texture2D as a texture view into a Texture2DArray
osg::ref_ptr<osg::Texture2D> createTextureView_Texture2DFromTexture2DArray(osg::Texture2DArray* textureArray, int layer); osg::ref_ptr<osg::Texture2D> createTextureView_Texture2DFromTexture2DArray(osg::Texture2DArray* textureArray, int layer);
//! Sets up a draw callback on the render stage that performs the MSAA resolve operation
void setMultiviewMSAAResolveCallback(osgUtil::RenderStage* renderStage);
//! Class that manages the specifics of GL_OVR_Multiview aware framebuffers, separating the layers into separate framebuffers, and disabling //! Class that manages the specifics of GL_OVR_Multiview aware framebuffers, separating the layers into separate framebuffers, and disabling
class MultiviewFramebuffer class MultiviewFramebuffer
{ {
@ -77,6 +85,7 @@ namespace Stereo
std::array<osg::ref_ptr<osg::Texture2D>, 2> mColorTexture; std::array<osg::ref_ptr<osg::Texture2D>, 2> mColorTexture;
std::array<osg::ref_ptr<osg::Texture2D>, 2> mDepthTexture; std::array<osg::ref_ptr<osg::Texture2D>, 2> mDepthTexture;
}; };
} }
#endif #endif

@ -19,6 +19,7 @@
#include <string> #include <string>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/misc/constants.hpp>
#include <components/sceneutil/statesetupdater.hpp> #include <components/sceneutil/statesetupdater.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
@ -69,7 +70,6 @@ namespace Stereo
void applyLeft(osg::StateSet* stateset, osgUtil::CullVisitor* nv) override void applyLeft(osg::StateSet* stateset, osgUtil::CullVisitor* nv) override
{ {
osg::Matrix dummy;
auto* uProjectionMatrix = stateset->getUniform("projectionMatrix"); auto* uProjectionMatrix = stateset->getUniform("projectionMatrix");
if (uProjectionMatrix) if (uProjectionMatrix)
uProjectionMatrix->set(mManager->computeEyeViewOffset(0) * mManager->computeEyeProjection(0, SceneUtil::AutoDepth::isReversed())); uProjectionMatrix->set(mManager->computeEyeViewOffset(0) * mManager->computeEyeProjection(0, SceneUtil::AutoDepth::isReversed()));
@ -77,7 +77,6 @@ namespace Stereo
void applyRight(osg::StateSet* stateset, osgUtil::CullVisitor* nv) override void applyRight(osg::StateSet* stateset, osgUtil::CullVisitor* nv) override
{ {
osg::Matrix dummy;
auto* uProjectionMatrix = stateset->getUniform("projectionMatrix"); auto* uProjectionMatrix = stateset->getUniform("projectionMatrix");
if (uProjectionMatrix) if (uProjectionMatrix)
uProjectionMatrix->set(mManager->computeEyeViewOffset(1) * mManager->computeEyeProjection(1, SceneUtil::AutoDepth::isReversed())); uProjectionMatrix->set(mManager->computeEyeViewOffset(1) * mManager->computeEyeProjection(1, SceneUtil::AutoDepth::isReversed()));
@ -135,7 +134,7 @@ namespace Stereo
: mViewer(viewer) : mViewer(viewer)
, mMainCamera(mViewer->getCamera()) , mMainCamera(mViewer->getCamera())
, mUpdateCallback(new StereoUpdateCallback(this)) , mUpdateCallback(new StereoUpdateCallback(this))
, mMasterProjectionMatrix(osg::Matrix::identity()) , mMasterProjectionMatrix(osg::Matrixd::identity())
, mEyeResolutionOverriden(false) , mEyeResolutionOverriden(false)
, mEyeResolutionOverride(0,0) , mEyeResolutionOverride(0,0)
, mFrustumManager(nullptr) , mFrustumManager(nullptr)
@ -322,7 +321,6 @@ namespace Stereo
near_ = Settings::Manager::getFloat("near clip", "Camera"); near_ = Settings::Manager::getFloat("near clip", "Camera");
far_ = Settings::Manager::getFloat("viewing distance", "Camera"); far_ = Settings::Manager::getFloat("viewing distance", "Camera");
auto projectionMatrix = mMainCamera->getProjectionMatrix();
if (mUpdateViewCallback) if (mUpdateViewCallback)
{ {
@ -342,15 +340,25 @@ namespace Stereo
masterView.fov.angleUp = std::max(mView[0].fov.angleUp, mView[1].fov.angleUp); masterView.fov.angleUp = std::max(mView[0].fov.angleUp, mView[1].fov.angleUp);
masterView.fov.angleLeft = std::min(mView[0].fov.angleLeft, mView[1].fov.angleLeft); masterView.fov.angleLeft = std::min(mView[0].fov.angleLeft, mView[1].fov.angleLeft);
masterView.fov.angleRight = std::max(mView[0].fov.angleRight, mView[1].fov.angleRight); masterView.fov.angleRight = std::max(mView[0].fov.angleRight, mView[1].fov.angleRight);
projectionMatrix = masterView.perspectiveMatrix(near_, far_, false); auto projectionMatrix = masterView.perspectiveMatrix(near_, far_, false);
mMainCamera->setProjectionMatrix(projectionMatrix); mMainCamera->setProjectionMatrix(projectionMatrix);
} }
else else
{ {
auto* ds = osg::DisplaySettings::instance().get(); auto* ds = osg::DisplaySettings::instance().get();
auto viewMatrix = mMainCamera->getViewMatrix(); auto viewMatrix = mMainCamera->getViewMatrix();
mViewOffsetMatrix[0] = osg::Matrix::inverse(viewMatrix) * ds->computeLeftEyeViewImplementation(viewMatrix); auto projectionMatrix = mMainCamera->getProjectionMatrix();
mViewOffsetMatrix[1] = osg::Matrix::inverse(viewMatrix) * ds->computeRightEyeViewImplementation(viewMatrix); auto s = ds->getEyeSeparation() * Constants::UnitsPerMeter;
mViewOffsetMatrix[0] = osg::Matrixd(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
s, 0.0, 0.0, 1.0);
mViewOffsetMatrix[1] = osg::Matrixd(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
-s, 0.0, 0.0, 1.0);
mProjectionMatrix[0] = ds->computeLeftEyeProjectionImplementation(projectionMatrix); mProjectionMatrix[0] = ds->computeLeftEyeProjectionImplementation(projectionMatrix);
mProjectionMatrix[1] = ds->computeRightEyeProjectionImplementation(projectionMatrix); mProjectionMatrix[1] = ds->computeRightEyeProjectionImplementation(projectionMatrix);
if (SceneUtil::AutoDepth::isReversed()) if (SceneUtil::AutoDepth::isReversed())

@ -87,7 +87,7 @@ namespace Stereo
//! The projection intended for rendering. When reverse Z is enabled, this is not the same as the camera's projection matrix, //! The projection intended for rendering. When reverse Z is enabled, this is not the same as the camera's projection matrix,
//! and therefore must be provided to the manager explicitly. //! and therefore must be provided to the manager explicitly.
void setMasterProjectionMatrix(const osg::Matrix& projectionMatrix) { mMasterProjectionMatrix = projectionMatrix; } void setMasterProjectionMatrix(const osg::Matrixd& projectionMatrix) { mMasterProjectionMatrix = projectionMatrix; }
//! Causes the subgraph represented by the node to draw to the full viewport. //! Causes the subgraph represented by the node to draw to the full viewport.
//! This has no effect if stereo is not enabled //! This has no effect if stereo is not enabled
@ -109,15 +109,15 @@ namespace Stereo
osg::ref_ptr<osg::Camera> mMainCamera; osg::ref_ptr<osg::Camera> mMainCamera;
osg::ref_ptr<osg::Callback> mUpdateCallback; osg::ref_ptr<osg::Callback> mUpdateCallback;
std::string mError; std::string mError;
osg::Matrix mMasterProjectionMatrix; osg::Matrixd mMasterProjectionMatrix;
std::shared_ptr<MultiviewFramebuffer> mMultiviewFramebuffer; std::shared_ptr<MultiviewFramebuffer> mMultiviewFramebuffer;
bool mEyeResolutionOverriden; bool mEyeResolutionOverriden;
osg::Vec2i mEyeResolutionOverride; osg::Vec2i mEyeResolutionOverride;
std::array<View, 2> mView; std::array<View, 2> mView;
std::array<osg::Matrix, 2> mViewOffsetMatrix; std::array<osg::Matrixd, 2> mViewOffsetMatrix;
std::array<osg::Matrix, 2> mProjectionMatrix; std::array<osg::Matrixd, 2> mProjectionMatrix;
std::array<osg::Matrix, 2> mProjectionMatrixReverseZ; std::array<osg::Matrixd, 2> mProjectionMatrixReverseZ;
std::unique_ptr<StereoFrustumManager> mFrustumManager; std::unique_ptr<StereoFrustumManager> mFrustumManager;
std::shared_ptr<UpdateViewCallback> mUpdateViewCallback; std::shared_ptr<UpdateViewCallback> mUpdateViewCallback;

Loading…
Cancel
Save