mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-31 16:36:41 +00:00
More stereo-postprocessing integration
This commit is contained in:
parent
fa29dd05fc
commit
6dc727cf8f
7 changed files with 154 additions and 13 deletions
|
@ -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…
Reference in a new issue