mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +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.apply();
|
||||
|
||||
if (Stereo::getMultiview() && mMultiviewResolveProgram)
|
||||
{
|
||||
state.pushStateSet(mMultiviewResolveStateSet);
|
||||
state.apply();
|
||||
}
|
||||
|
||||
state.applyTextureAttribute(0, bufferData.sceneTex);
|
||||
resolveViewport->apply(state);
|
||||
|
||||
drawGeometry(renderInfo);
|
||||
state.popStateSet();
|
||||
|
||||
if (Stereo::getMultiview() && mMultiviewResolveProgram)
|
||||
{
|
||||
state.popStateSet();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <osg/Camera>
|
||||
#include <osg/FrameBufferObject>
|
||||
#include <osg/Texture>
|
||||
#include <osg/Texture2DArray>
|
||||
#include <osgUtil/CullVisitor>
|
||||
|
||||
#include <components/stereo/stereomanager.hpp>
|
||||
|
@ -12,6 +14,7 @@
|
|||
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
PingPongCull::PingPongCull(PostProcessor* pp)
|
||||
: mViewportStateset(nullptr)
|
||||
, mPostProcessor(pp)
|
||||
|
@ -66,6 +69,11 @@ namespace MWRender
|
|||
{
|
||||
renderStage->setMultisampleResolveFramebufferObject(postProcessor->getFbo(PostProcessor::FBO_Primary, 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)
|
||||
|
|
|
@ -86,6 +86,14 @@ namespace
|
|||
case GL_TEXTURE_2D_ARRAY:
|
||||
static_cast<osg::Texture2DArray*>(tex)->setTextureSize(w, h, 2);
|
||||
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:
|
||||
throw std::logic_error("Invalid texture type received");
|
||||
}
|
||||
|
@ -233,7 +241,7 @@ namespace MWRender
|
|||
mUBO = ext && ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
|
||||
mStateUpdater = new fx::StateUpdater(mUBO);
|
||||
|
||||
if (!SceneUtil::AutoDepth::isReversed() && !mSoftParticles && !mUsePostProcessing)
|
||||
if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !mSoftParticles && !mUsePostProcessing)
|
||||
return;
|
||||
|
||||
enable(mUsePostProcessing);
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#include <osgUtil/RenderStage>
|
||||
#include <osgUtil/CullVisitor>
|
||||
|
||||
#ifdef OSG_HAS_MULTIVIEW
|
||||
#include <osg/Texture2DMultisampleArray>
|
||||
#endif
|
||||
|
||||
#include <components/sceneutil/nodecallback.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
@ -242,6 +246,97 @@ namespace Stereo
|
|||
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*>
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -16,6 +16,11 @@ namespace osg
|
|||
class Texture2DArray;
|
||||
}
|
||||
|
||||
namespace osgUtil
|
||||
{
|
||||
class RenderStage;
|
||||
}
|
||||
|
||||
namespace Stereo
|
||||
{
|
||||
class UpdateRenderStagesCallback;
|
||||
|
@ -35,6 +40,9 @@ namespace Stereo
|
|||
//! Creates a Texture2D as a texture view into a Texture2DArray
|
||||
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 MultiviewFramebuffer
|
||||
{
|
||||
|
@ -77,6 +85,7 @@ namespace Stereo
|
|||
std::array<osg::ref_ptr<osg::Texture2D>, 2> mColorTexture;
|
||||
std::array<osg::ref_ptr<osg::Texture2D>, 2> mDepthTexture;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <string>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/misc/constants.hpp>
|
||||
|
||||
#include <components/sceneutil/statesetupdater.hpp>
|
||||
#include <components/sceneutil/visitor.hpp>
|
||||
|
@ -69,7 +70,6 @@ namespace Stereo
|
|||
|
||||
void applyLeft(osg::StateSet* stateset, osgUtil::CullVisitor* nv) override
|
||||
{
|
||||
osg::Matrix dummy;
|
||||
auto* uProjectionMatrix = stateset->getUniform("projectionMatrix");
|
||||
if (uProjectionMatrix)
|
||||
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
|
||||
{
|
||||
osg::Matrix dummy;
|
||||
auto* uProjectionMatrix = stateset->getUniform("projectionMatrix");
|
||||
if (uProjectionMatrix)
|
||||
uProjectionMatrix->set(mManager->computeEyeViewOffset(1) * mManager->computeEyeProjection(1, SceneUtil::AutoDepth::isReversed()));
|
||||
|
@ -135,7 +134,7 @@ namespace Stereo
|
|||
: mViewer(viewer)
|
||||
, mMainCamera(mViewer->getCamera())
|
||||
, mUpdateCallback(new StereoUpdateCallback(this))
|
||||
, mMasterProjectionMatrix(osg::Matrix::identity())
|
||||
, mMasterProjectionMatrix(osg::Matrixd::identity())
|
||||
, mEyeResolutionOverriden(false)
|
||||
, mEyeResolutionOverride(0,0)
|
||||
, mFrustumManager(nullptr)
|
||||
|
@ -322,7 +321,6 @@ namespace Stereo
|
|||
|
||||
near_ = Settings::Manager::getFloat("near clip", "Camera");
|
||||
far_ = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||
auto projectionMatrix = mMainCamera->getProjectionMatrix();
|
||||
|
||||
if (mUpdateViewCallback)
|
||||
{
|
||||
|
@ -342,15 +340,25 @@ namespace Stereo
|
|||
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.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);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* ds = osg::DisplaySettings::instance().get();
|
||||
auto viewMatrix = mMainCamera->getViewMatrix();
|
||||
mViewOffsetMatrix[0] = osg::Matrix::inverse(viewMatrix) * ds->computeLeftEyeViewImplementation(viewMatrix);
|
||||
mViewOffsetMatrix[1] = osg::Matrix::inverse(viewMatrix) * ds->computeRightEyeViewImplementation(viewMatrix);
|
||||
auto projectionMatrix = mMainCamera->getProjectionMatrix();
|
||||
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[1] = ds->computeRightEyeProjectionImplementation(projectionMatrix);
|
||||
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,
|
||||
//! 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.
|
||||
//! 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::Callback> mUpdateCallback;
|
||||
std::string mError;
|
||||
osg::Matrix mMasterProjectionMatrix;
|
||||
osg::Matrixd mMasterProjectionMatrix;
|
||||
std::shared_ptr<MultiviewFramebuffer> mMultiviewFramebuffer;
|
||||
bool mEyeResolutionOverriden;
|
||||
osg::Vec2i mEyeResolutionOverride;
|
||||
|
||||
std::array<View, 2> mView;
|
||||
std::array<osg::Matrix, 2> mViewOffsetMatrix;
|
||||
std::array<osg::Matrix, 2> mProjectionMatrix;
|
||||
std::array<osg::Matrix, 2> mProjectionMatrixReverseZ;
|
||||
std::array<osg::Matrixd, 2> mViewOffsetMatrix;
|
||||
std::array<osg::Matrixd, 2> mProjectionMatrix;
|
||||
std::array<osg::Matrixd, 2> mProjectionMatrixReverseZ;
|
||||
|
||||
std::unique_ptr<StereoFrustumManager> mFrustumManager;
|
||||
std::shared_ptr<UpdateViewCallback> mUpdateViewCallback;
|
||||
|
|
Loading…
Reference in a new issue