From b0e4c7e76a2b97f14eedfa333746effc38fe8b8b Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Tue, 21 Jun 2022 15:55:06 +0000 Subject: [PATCH] [Postprocessing] Stereo integration --- apps/openmw/mwrender/npcanimation.cpp | 2 + apps/openmw/mwrender/pingpongcanvas.cpp | 94 ++++++- apps/openmw/mwrender/pingpongcanvas.hpp | 12 +- apps/openmw/mwrender/pingpongcull.cpp | 51 +++- apps/openmw/mwrender/pingpongcull.hpp | 14 +- apps/openmw/mwrender/postprocessor.cpp | 244 +++++++++++++----- apps/openmw/mwrender/postprocessor.hpp | 9 +- apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/screenshotmanager.cpp | 4 +- apps/openmw/mwrender/skyutil.cpp | 60 ++++- apps/openmw/mwrender/transparentpass.cpp | 75 +++++- apps/openmw/mwrender/transparentpass.hpp | 9 +- components/debug/gldebug.cpp | 5 + components/fx/pass.cpp | 39 ++- components/fx/stateupdater.hpp | 10 +- components/resource/scenemanager.cpp | 2 +- components/resource/scenemanager.hpp | 4 +- components/shader/shadervisitor.cpp | 6 +- components/shader/shadervisitor.hpp | 4 +- components/stereo/stereomanager.cpp | 51 ++-- components/stereo/stereomanager.hpp | 2 - files/shaders/CMakeLists.txt | 2 + .../blended_depth_postpass_vertex.glsl | 3 +- files/shaders/fullscreen_tri_vertex.glsl | 2 + files/shaders/multiview_resolve_fragment.glsl | 18 ++ files/shaders/multiview_resolve_vertex.glsl | 9 + files/shaders/openmw_vertex.glsl | 5 - files/shaders/openmw_vertex.h.glsl | 3 +- files/shaders/openmw_vertex_multiview.glsl | 14 +- 29 files changed, 578 insertions(+), 179 deletions(-) create mode 100644 files/shaders/multiview_resolve_fragment.glsl create mode 100644 files/shaders/multiview_resolve_vertex.glsl diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ba44a94cd9..00798604ce 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -361,6 +361,8 @@ public: glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); bin->drawImplementation(renderInfo, previous); } + + state->checkGLErrors("after DepthClearCallback::drawImplementation"); } osg::ref_ptr mDepth; diff --git a/apps/openmw/mwrender/pingpongcanvas.cpp b/apps/openmw/mwrender/pingpongcanvas.cpp index 507a41e1f0..3fea60f216 100644 --- a/apps/openmw/mwrender/pingpongcanvas.cpp +++ b/apps/openmw/mwrender/pingpongcanvas.cpp @@ -2,6 +2,10 @@ #include #include +#include +#include + +#include #include "postprocessor.hpp" @@ -9,6 +13,7 @@ namespace MWRender { PingPongCanvas::PingPongCanvas(Shader::ShaderManager& shaderManager) : mFallbackStateSet(new osg::StateSet) + , mMultiviewResolveStateSet(new osg::StateSet) { setUseDisplayList(false); setUseVertexBufferObjects(true); @@ -25,12 +30,21 @@ namespace MWRender mHDRDriver = HDRDriver(shaderManager); mHDRDriver.disable(); - auto fallbackVertex = shaderManager.getShader("fullscreen_tri_vertex.glsl", {}, osg::Shader::VERTEX); - auto fallbackFragment = shaderManager.getShader("fullscreen_tri_fragment.glsl", {}, osg::Shader::FRAGMENT); + Shader::ShaderManager::DefineMap defines; + Stereo::Manager::instance().shaderStereoDefines(defines); + + auto fallbackVertex = shaderManager.getShader("fullscreen_tri_vertex.glsl", defines, osg::Shader::VERTEX); + auto fallbackFragment = shaderManager.getShader("fullscreen_tri_fragment.glsl", defines, osg::Shader::FRAGMENT); mFallbackProgram = shaderManager.getProgram(fallbackVertex, fallbackFragment); mFallbackStateSet->setAttributeAndModes(mFallbackProgram); mFallbackStateSet->addUniform(new osg::Uniform("omw_SamplerLastShader", 0)); + + auto multiviewResolveVertex = shaderManager.getShader("multiview_resolve_vertex.glsl", {}, osg::Shader::VERTEX); + auto multiviewResolveFragment = shaderManager.getShader("multiview_resolve_fragment.glsl", {}, osg::Shader::FRAGMENT); + mMultiviewResolveProgram = shaderManager.getProgram(multiviewResolveVertex, multiviewResolveFragment); + mMultiviewResolveStateSet->setAttributeAndModes(mMultiviewResolveProgram); + mMultiviewResolveStateSet->addUniform(new osg::Uniform("omw_SamplerLastShader", 0)); } void PingPongCanvas::setCurrentFrameData(size_t frameId, fx::DispatchArray&& data) @@ -51,6 +65,29 @@ namespace MWRender osg::Geometry::drawImplementation(renderInfo); } + static void attachCloneOfTemplate(osg::FrameBufferObject* fbo, osg::Camera::BufferComponent component, osg::Texture* tex) + { + switch (tex->getTextureTarget()) + { + case GL_TEXTURE_2D: + { + auto* tex2d = new osg::Texture2D(*static_cast(tex)); + fbo->setAttachment(component, osg::FrameBufferAttachment(tex2d)); + } + break; + case GL_TEXTURE_2D_ARRAY: + { +#ifdef OSG_HAS_MULTIVIEW + auto* tex2dArray = new osg::Texture2DArray(*static_cast(tex)); + fbo->setAttachment(component, osg::FrameBufferAttachment(tex2dArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0)); +#endif + } + break; + default: + throw std::logic_error("Invalid texture type received"); + } + } + void PingPongCanvas::drawImplementation(osg::RenderInfo& renderInfo) const { osg::State& state = *renderInfo.getState(); @@ -76,7 +113,7 @@ namespace MWRender filtered.push_back(i); } - auto* viewport = state.getCurrentViewport(); + auto* resolveViewport = state.getCurrentViewport(); if (filtered.empty() || !bufferData.postprocessing) { @@ -94,7 +131,7 @@ namespace MWRender state.pushStateSet(mFallbackStateSet); state.apply(); state.applyTextureAttribute(0, bufferData.sceneTex); - viewport->apply(state); + resolveViewport->apply(state); drawGeometry(renderInfo); state.popStateSet(); @@ -108,14 +145,30 @@ namespace MWRender for (auto& fbo : mFbos) { fbo = new osg::FrameBufferObject; - fbo->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(new osg::Texture2D(*bufferData.sceneTexLDR))); + attachCloneOfTemplate(fbo, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR); fbo->apply(state); glClearColor(0.5, 0.5, 0.5, 1); glClear(GL_COLOR_BUFFER_BIT); } + if (Stereo::getMultiview()) + { + mMultiviewResolveFramebuffer = new osg::FrameBufferObject(); + attachCloneOfTemplate(mMultiviewResolveFramebuffer, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR); + mMultiviewResolveFramebuffer->apply(state); + glClearColor(0.5, 0.5, 0.5, 1); + glClear(GL_COLOR_BUFFER_BIT); + + mMultiviewResolveStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, (osg::Texture*)mMultiviewResolveFramebuffer->getAttachment(osg::Camera::COLOR_BUFFER0).getTexture()); + } + mHDRDriver.dirty(bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight()); + if (Stereo::getStereo()) + mRenderViewport = new osg::Viewport(0, 0, bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight()); + else + mRenderViewport = nullptr; + bufferData.dirty = false; } @@ -148,6 +201,11 @@ namespace MWRender destinationFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); lastApplied = destinationHandle; } + else if (Stereo::getMultiview()) + { + mMultiviewResolveFramebuffer->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); + lastApplied = mMultiviewResolveFramebuffer->getHandle(cid); + } else { ext->glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0); @@ -173,19 +231,22 @@ namespace MWRender for (size_t passIndex = 0; passIndex < node.mPasses.size(); ++passIndex) { + if (mRenderViewport) + mRenderViewport->apply(state); const auto& pass = node.mPasses[passIndex]; bool lastPass = passIndex == node.mPasses.size() - 1; + //VR-TODO: This won't actually work for tex2darrays if (lastShader == 0) pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, bufferData.sceneTex); else - pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, (osg::Texture2D*)mFbos[lastShader - GL_COLOR_ATTACHMENT0_EXT]->getAttachment(osg::Camera::COLOR_BUFFER0).getTexture()); + pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, (osg::Texture*)mFbos[lastShader - GL_COLOR_ATTACHMENT0_EXT]->getAttachment(osg::Camera::COLOR_BUFFER0).getTexture()); if (lastDraw == 0) pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, bufferData.sceneTex); else - pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, (osg::Texture2D*)mFbos[lastDraw - GL_COLOR_ATTACHMENT0_EXT]->getAttachment(osg::Camera::COLOR_BUFFER0).getTexture()); + pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, (osg::Texture*)mFbos[lastDraw - GL_COLOR_ATTACHMENT0_EXT]->getAttachment(osg::Camera::COLOR_BUFFER0).getTexture()); if (pass.mRenderTarget) { @@ -203,6 +264,10 @@ namespace MWRender else if (pass.mResolve && index == filtered.back()) { bindDestinationFbo(); + if (!destinationFbo && !Stereo::getMultiview()) + { + resolveViewport->apply(state); + } } else if (lastPass) { @@ -237,6 +302,21 @@ namespace MWRender state.popStateSet(); } + if (Stereo::getMultiview() && mMultiviewResolveProgram) + { + ext->glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0); + lastApplied = 0; + + resolveViewport->apply(state); + state.pushStateSet(mMultiviewResolveStateSet); + state.apply(); + + drawGeometry(renderInfo); + + state.popStateSet(); + state.apply(); + } + if (lastApplied != destinationHandle) { bindDestinationFbo(); diff --git a/apps/openmw/mwrender/pingpongcanvas.hpp b/apps/openmw/mwrender/pingpongcanvas.hpp index 1887c97325..8df141f587 100644 --- a/apps/openmw/mwrender/pingpongcanvas.hpp +++ b/apps/openmw/mwrender/pingpongcanvas.hpp @@ -38,11 +38,11 @@ namespace MWRender void setSceneTexture(size_t frameId, osg::ref_ptr tex) { mBufferData[frameId].sceneTex = tex; } - void setLDRSceneTexture(size_t frameId, osg::ref_ptr tex) { mBufferData[frameId].sceneTexLDR = tex; } + void setLDRSceneTexture(size_t frameId, osg::ref_ptr tex) { mBufferData[frameId].sceneTexLDR = tex; } void setDepthTexture(size_t frameId, osg::ref_ptr tex) { mBufferData[frameId].depthTex = tex; } - void setNormalsTexture(size_t frameId, osg::ref_ptr tex) { mBufferData[frameId].normalsTex = tex; } + void setNormalsTexture(size_t frameId, osg::ref_ptr tex) { mBufferData[frameId].normalsTex = tex; } void setHDR(size_t frameId, bool hdr) { mBufferData[frameId].hdr = hdr; } @@ -58,7 +58,10 @@ namespace MWRender mutable HDRDriver mHDRDriver; osg::ref_ptr mFallbackProgram; + osg::ref_ptr mMultiviewResolveProgram; osg::ref_ptr mFallbackStateSet; + osg::ref_ptr mMultiviewResolveStateSet; + mutable osg::ref_ptr mMultiviewResolveFramebuffer; struct BufferData { @@ -73,12 +76,13 @@ namespace MWRender osg::ref_ptr sceneTex; osg::ref_ptr depthTex; - osg::ref_ptr sceneTexLDR; - osg::ref_ptr normalsTex; + osg::ref_ptr sceneTexLDR; + osg::ref_ptr normalsTex; }; mutable std::array mBufferData; mutable std::array, 3> mFbos; + mutable osg::ref_ptr mRenderViewport; mutable bool mLoggedLastError = false; }; diff --git a/apps/openmw/mwrender/pingpongcull.cpp b/apps/openmw/mwrender/pingpongcull.cpp index 2bec155bbb..7c3f774a61 100644 --- a/apps/openmw/mwrender/pingpongcull.cpp +++ b/apps/openmw/mwrender/pingpongcull.cpp @@ -4,11 +4,31 @@ #include #include +#include +#include + #include "postprocessor.hpp" #include "pingpongcanvas.hpp" namespace MWRender { + PingPongCull::PingPongCull(PostProcessor* pp) + : mViewportStateset(nullptr) + , mPostProcessor(pp) + { + if (Stereo::getStereo()) + { + mViewportStateset = new osg::StateSet(); + mViewport = new osg::Viewport(0, 0, pp->renderWidth(), pp->renderHeight()); + mViewportStateset->setAttribute(mViewport); + } + } + + PingPongCull::~PingPongCull() + { + // Instantiate osg::ref_ptr<> destructor + } + void PingPongCull::operator()(osg::Node* node, osgUtil::CullVisitor* cv) { osgUtil::RenderStage* renderStage = cv->getCurrentRenderStage(); @@ -17,10 +37,19 @@ namespace MWRender MWRender::PostProcessor* postProcessor = dynamic_cast(cv->getCurrentCamera()->getUserData()); + if (Stereo::getStereo()) + { + auto& sm = Stereo::Manager::instance(); + auto view = sm.getEye(cv); + int index = view == Stereo::Eye::Right ? 1 : 0; + auto projectionMatrix = sm.computeEyeViewOffset(index) * sm.computeEyeProjection(index, true); + postProcessor->getStateUpdater()->setProjectionMatrix(projectionMatrix); + } + postProcessor->getStateUpdater()->setViewMatrix(cv->getCurrentCamera()->getViewMatrix()); - postProcessor->getStateUpdater()->setInvViewMatrix(cv->getCurrentCamera()->getInverseViewMatrix()); - postProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix); - mLastViewMatrix = cv->getCurrentCamera()->getViewMatrix(); + postProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix[0]); + mLastViewMatrix[0] = cv->getCurrentCamera()->getViewMatrix(); + postProcessor->getStateUpdater()->setEyePos(cv->getEyePoint()); postProcessor->getStateUpdater()->setEyeVec(cv->getLookVectorLocal()); @@ -28,11 +57,8 @@ namespace MWRender { renderStage->setMultisampleResolveFramebufferObject(nullptr); renderStage->setFrameBufferObject(nullptr); - traverse(node, cv); - return; } - - if (!postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId)) + else if (!postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId)) { renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Primary, frameId)); } @@ -42,6 +68,15 @@ namespace MWRender renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId)); } - traverse(node, cv); + if (mViewportStateset) + { + mViewport->setViewport(0, 0, mPostProcessor->renderWidth(), mPostProcessor->renderHeight()); + renderStage->setViewport(mViewport); + cv->pushStateSet(mViewportStateset.get()); + traverse(node, cv); + cv->popStateSet(); + } + else + traverse(node, cv); } } diff --git a/apps/openmw/mwrender/pingpongcull.hpp b/apps/openmw/mwrender/pingpongcull.hpp index d4514e20d3..da6c0c3c68 100644 --- a/apps/openmw/mwrender/pingpongcull.hpp +++ b/apps/openmw/mwrender/pingpongcull.hpp @@ -7,15 +7,27 @@ #include "postprocessor.hpp" +namespace osg +{ + class StateSet; + class Viewport; +} + namespace MWRender { class PostProcessor; class PingPongCull : public SceneUtil::NodeCallback { public: + PingPongCull(PostProcessor* pp); + ~PingPongCull(); + void operator()(osg::Node* node, osgUtil::CullVisitor* nv); private: - osg::Matrixf mLastViewMatrix; + std::array mLastViewMatrix; + osg::ref_ptr mViewportStateset; + osg::ref_ptr mViewport; + PostProcessor* mPostProcessor; }; } diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index fc9bcb693a..8fb2a2bbe9 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -5,9 +5,14 @@ #include #include +#include #include #include +#ifdef OSG_HAS_MULTIVIEW +#include +#endif + #include #include #include @@ -66,9 +71,102 @@ namespace cv->pushStateSet(stateset); traverse(camera, cv); - cv->popViewport(); + cv->popStateSet(); } }; + + + static void setTextureSize(osg::Texture* tex, int w, int h) + { + switch (tex->getTextureTarget()) + { + case GL_TEXTURE_2D: + static_cast(tex)->setTextureSize(w, h); + break; + case GL_TEXTURE_2D_ARRAY: + static_cast(tex)->setTextureSize(w, h, 2); + break; + default: + throw std::logic_error("Invalid texture type received"); + } + } + + static void setAttachment(osg::FrameBufferObject* fbo, osg::Camera::BufferComponent component, osg::Texture* tex) + { + switch (tex->getTextureTarget()) + { + case GL_TEXTURE_2D: + { + auto* tex2d = static_cast(tex); + fbo->setAttachment(component, osg::FrameBufferAttachment(tex2d)); + } + break; + case GL_TEXTURE_2D_ARRAY: + { +#ifdef OSG_HAS_MULTIVIEW + auto* tex2dArray = static_cast(tex); + fbo->setAttachment(component, osg::FrameBufferAttachment(tex2dArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0)); +#endif + } + break; + default: + throw std::logic_error("Invalid texture type received"); + } + } + + enum class Usage + { + RENDER_BUFFER, + TEXTURE, + }; + + static osg::FrameBufferAttachment createFrameBufferAttachmentFromTemplate(Usage usage, int width, int height, osg::Texture* template_, int samples) + { + if (usage == Usage::RENDER_BUFFER && !Stereo::getMultiview()) + { + osg::ref_ptr attachment = new osg::RenderBuffer(width, height, template_->getInternalFormat(), samples); + return osg::FrameBufferAttachment(attachment); + } + + osg::FrameBufferAttachment attachment; + +#ifdef OSG_HAS_MULTIVIEW + if (Stereo::getMultiview()) + { + if (samples > 1) + { + attachment = osg::FrameBufferAttachment(new osg::Texture2DMultisampleArray(), osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0); + } + else + { + attachment = osg::FrameBufferAttachment(new osg::Texture2DArray(), osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0); + } + } + else +#endif + { + if (samples > 1) + { + attachment = osg::FrameBufferAttachment(new osg::Texture2DMultisample()); + } + else + { + attachment = osg::FrameBufferAttachment(new osg::Texture2D()); + } + } + + osg::Texture* texture = attachment.getTexture(); + setTextureSize(texture, width, height); + texture->setSourceFormat(template_->getSourceFormat()); + texture->setSourceType(template_->getSourceType()); + texture->setInternalFormat(template_->getInternalFormat()); + texture->setFilter(osg::Texture2D::MIN_FILTER, template_->getFilter(osg::Texture2D::MIN_FILTER)); + texture->setFilter(osg::Texture2D::MAG_FILTER, template_->getFilter(osg::Texture2D::MAG_FILTER)); + texture->setWrap(osg::Texture::WRAP_S, template_->getWrap(osg::Texture2D::WRAP_S)); + texture->setWrap(osg::Texture::WRAP_T, template_->getWrap(osg::Texture2D::WRAP_T)); + + return attachment; + } } namespace MWRender @@ -99,7 +197,7 @@ namespace MWRender , mPrevPassLights(false) , mMainTemplate(new osg::Texture2D) { - mSoftParticles = Settings::Manager::getBool("soft particles", "Shaders") && !Stereo::getStereo() && !Stereo::getMultiview(); + mSoftParticles = Settings::Manager::getBool("soft particles", "Shaders"); mUsePostProcessing = Settings::Manager::getBool("enabled", "Post Processing"); osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext(); @@ -121,14 +219,21 @@ namespace MWRender Log(Debug::Error) << "'glDisablei' unsupported, pass normals will not be available to shaders."; if (mSoftParticles) + { for (int i = 0; i < 2; ++i) - mTextures[i][Tex_OpaqueDepth] = new osg::Texture2D; + { + if (Stereo::getMultiview()) + mTextures[i][Tex_OpaqueDepth] = new osg::Texture2DArray; + else + mTextures[i][Tex_OpaqueDepth] = new osg::Texture2D; + } + } mGLSLVersion = ext->glslLanguageVersion * 100; mUBO = ext && ext->isUniformBufferObjectSupported && mGLSLVersion >= 330; mStateUpdater = new fx::StateUpdater(mUBO); - if (!SceneUtil::AutoDepth::isReversed() && !mSoftParticles && !mUsePostProcessing && !Stereo::getStereo() && !Stereo::getMultiview()) + if (!SceneUtil::AutoDepth::isReversed() && !mSoftParticles && !mUsePostProcessing) return; enable(mUsePostProcessing); @@ -142,11 +247,18 @@ namespace MWRender void PostProcessor::resize() { + mHUDCamera->resize(mWidth, mHeight); + mViewer->getCamera()->resize(mWidth, mHeight); + if (Stereo::getStereo()) + Stereo::Manager::instance().screenResolutionChanged(); + + auto width = renderWidth(); + auto height = renderHeight(); for (auto& technique : mTechniques) { for (auto& [name, rt] : technique->getRenderTargetsMap()) { - const auto [w, h] = rt.mSize.get(mWidth, mHeight); + const auto [w, h] = rt.mSize.get(width, height); rt.mTarget->setTextureSize(w, h); } } @@ -156,10 +268,8 @@ namespace MWRender createTexturesAndCamera(frameId); createObjectsForFrame(frameId); - mHUDCamera->resize(mWidth, mHeight); - mViewer->getCamera()->resize(mWidth, mHeight); mRendering.updateProjectionMatrix(); - mRendering.setScreenRes(mWidth, mHeight); + mRendering.setScreenRes(width, height); dirtyTechniques(); @@ -168,8 +278,6 @@ namespace MWRender mDirty = true; mDirtyFrameId = !frameId; - if (Stereo::getStereo()) - Stereo::Manager::instance().screenResolutionChanged(); } void PostProcessor::populateTechniqueFiles() @@ -191,7 +299,7 @@ namespace MWRender mReload = true; mEnabled = true; bool postPass = Settings::Manager::getBool("transparent postpass", "Post Processing"); - mUsePostProcessing = usePostProcessing && !Stereo::getStereo() && !Stereo::getMultiview(); + mUsePostProcessing = usePostProcessing; mDisableDepthPasses = !mSoftParticles && !postPass; @@ -199,7 +307,7 @@ namespace MWRender mDisableDepthPasses = true; #endif - if (!mDisableDepthPasses && !Stereo::getStereo() && !Stereo::getMultiview()) + if (!mDisableDepthPasses) { mTransparentDepthPostPass = new TransparentDepthBinCallback(mRendering.getResourceSystem()->getSceneManager()->getShaderManager(), postPass); osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass); @@ -240,7 +348,7 @@ namespace MWRender if (!mSoftParticles) osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(nullptr); - if (!SceneUtil::AutoDepth::isReversed() && !mSoftParticles && !Stereo::getStereo() && !Stereo::getMultiview()) + if (!SceneUtil::AutoDepth::isReversed() && !mSoftParticles) { removeChild(mHUDCamera); setCullCallback(nullptr); @@ -289,25 +397,7 @@ namespace MWRender mPingPongCanvas->setMask(frameId, mUnderwater, mExteriorFlag); mPingPongCanvas->setHDR(frameId, getHDR()); - if (Stereo::getStereo()) - { - auto& sm = Stereo::Manager::instance(); - - int index = sm.getEye(cv) == Stereo::Eye::Left ? 0 : 1; - - mPingPongCanvas->setSceneTexture(frameId, sm.multiviewFramebuffer()->layerColorBuffer(index)); - mPingPongCanvas->setDepthTexture(frameId, sm.multiviewFramebuffer()->layerDepthBuffer(index)); - } - else if (Stereo::getMultiview()) - { - auto& sm = Stereo::Manager::instance(); - - mPingPongCanvas->setSceneTexture(frameId, sm.multiviewFramebuffer()->multiviewColorBuffer()); - mPingPongCanvas->setDepthTexture(frameId, sm.multiviewFramebuffer()->multiviewDepthBuffer()); - } - else - { - mPingPongCanvas->setSceneTexture(frameId, getTexture(Tex_Scene, frameId)); + mPingPongCanvas->setSceneTexture(frameId, getTexture(Tex_Scene, frameId)); if (mDisableDepthPasses) mPingPongCanvas->setDepthTexture(frameId, getTexture(Tex_Depth, frameId)); else @@ -315,12 +405,12 @@ namespace MWRender mPingPongCanvas->setLDRSceneTexture(frameId, getTexture(Tex_Scene_LDR, frameId)); - if (mTransparentDepthPostPass) - { - mTransparentDepthPostPass->mFbo[frameId] = mFbos[frameId][FBO_Primary]; - mTransparentDepthPostPass->mMsaaFbo[frameId] = mFbos[frameId][FBO_Multisample]; - mTransparentDepthPostPass->mOpaqueFbo[frameId] = mFbos[frameId][FBO_OpaqueDepth]; - } + if (mTransparentDepthPostPass) + { + mTransparentDepthPostPass->mFbo[frameId] = mFbos[frameId][FBO_Primary]; + mTransparentDepthPostPass->mMsaaFbo[frameId] = mFbos[frameId][FBO_Multisample]; + mTransparentDepthPostPass->mOpaqueFbo[frameId] = mFbos[frameId][FBO_OpaqueDepth]; + mTransparentDepthPostPass->dirtyFrame(frameId); } size_t frame = cv->getTraversalNumber(); @@ -331,7 +421,6 @@ namespace MWRender if (frame != mLastFrameNumber) { mLastFrameNumber = frame; - auto stamp = cv->getFrameStamp(); mStateUpdater->setSimulationTime(static_cast(stamp->getSimulationTime())); @@ -440,29 +529,29 @@ namespace MWRender void PostProcessor::createObjectsForFrame(size_t frameId) { - if (Stereo::getStereo() || Stereo::getMultiview()) - return; - auto& fbos = mFbos[frameId]; auto& textures = mTextures[frameId]; + auto width = renderWidth(); + auto height = renderHeight(); for (auto& tex : textures) { if (!tex) continue; - tex->setTextureSize(mWidth, mHeight); + setTextureSize(tex, width, height); tex->dirtyTextureObject(); } fbos[FBO_Primary] = new osg::FrameBufferObject; - fbos[FBO_Primary]->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(textures[Tex_Scene])); + setAttachment(fbos[FBO_Primary], osg::Camera::COLOR_BUFFER0, textures[Tex_Scene]); if (mNormals && mNormalsSupported) - fbos[FBO_Primary]->setAttachment(osg::Camera::COLOR_BUFFER1, osg::FrameBufferAttachment(textures[Tex_Normal])); - fbos[FBO_Primary]->setAttachment(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, osg::FrameBufferAttachment(textures[Tex_Depth])); + setAttachment(fbos[FBO_Primary], osg::Camera::COLOR_BUFFER1, textures[Tex_Normal]); + setAttachment(fbos[FBO_Primary], osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, textures[Tex_Depth]); fbos[FBO_FirstPerson] = new osg::FrameBufferObject; - osg::ref_ptr fpDepthRb = new osg::RenderBuffer(mWidth, mHeight, textures[Tex_Depth]->getInternalFormat(), mSamples > 1 ? mSamples : 0); + + auto fpDepthRb = createFrameBufferAttachmentFromTemplate(Usage::RENDER_BUFFER, width, height, textures[Tex_Depth], mSamples); fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER, osg::FrameBufferAttachment(fpDepthRb)); // When MSAA is enabled we must first render to a render buffer, then @@ -471,33 +560,33 @@ namespace MWRender if (mSamples > 1) { fbos[FBO_Multisample] = new osg::FrameBufferObject; - osg::ref_ptr colorRB = new osg::RenderBuffer(mWidth, mHeight, textures[Tex_Scene]->getInternalFormat(), mSamples); + auto colorRB = createFrameBufferAttachmentFromTemplate(Usage::RENDER_BUFFER, width, height, textures[Tex_Scene], mSamples); if (mNormals && mNormalsSupported) { - osg::ref_ptr normalRB = new osg::RenderBuffer(mWidth, mHeight, textures[Tex_Normal]->getInternalFormat(), mSamples); - fbos[FBO_Multisample]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, osg::FrameBufferAttachment(normalRB)); - fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, osg::FrameBufferAttachment(normalRB)); + auto normalRB = createFrameBufferAttachmentFromTemplate(Usage::RENDER_BUFFER, width, height, textures[Tex_Normal], mSamples); + fbos[FBO_Multisample]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, normalRB); + fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, normalRB); } - osg::ref_ptr depthRB = new osg::RenderBuffer(mWidth, mHeight, textures[Tex_Depth]->getInternalFormat(), mSamples); - fbos[FBO_Multisample]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(colorRB)); - fbos[FBO_Multisample]->setAttachment(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER, osg::FrameBufferAttachment(depthRB)); - fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(colorRB)); + auto depthRB = createFrameBufferAttachmentFromTemplate(Usage::RENDER_BUFFER, width, height, textures[Tex_Depth], mSamples); + fbos[FBO_Multisample]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, colorRB); + fbos[FBO_Multisample]->setAttachment(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER, depthRB); + fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, colorRB); fbos[FBO_Intercept] = new osg::FrameBufferObject; - fbos[FBO_Intercept]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(textures[Tex_Scene])); - fbos[FBO_Intercept]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, osg::FrameBufferAttachment(textures[Tex_Normal])); + setAttachment(fbos[FBO_Intercept], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, textures[Tex_Scene]); + setAttachment(fbos[FBO_Intercept], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, textures[Tex_Normal]); } else { - fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(textures[Tex_Scene])); + setAttachment(fbos[FBO_FirstPerson], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, textures[Tex_Scene]); if (mNormals && mNormalsSupported) - fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, osg::FrameBufferAttachment(textures[Tex_Normal])); + setAttachment(fbos[FBO_FirstPerson], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, textures[Tex_Normal]); } if (textures[Tex_OpaqueDepth]) { fbos[FBO_OpaqueDepth] = new osg::FrameBufferObject; - fbos[FBO_OpaqueDepth]->setAttachment(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER, osg::FrameBufferAttachment(textures[Tex_OpaqueDepth])); + setAttachment(fbos[FBO_OpaqueDepth], osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER, textures[Tex_OpaqueDepth]); } #ifdef __APPLE__ @@ -600,7 +689,7 @@ namespace MWRender { const auto& rt = technique->getRenderTargetsMap()[pass->getTarget()]; - const auto [w, h] = rt.mSize.get(mWidth, mHeight); + const auto [w, h] = rt.mSize.get(renderWidth(), renderHeight()); subPass.mRenderTexture = new osg::Texture2D(*rt.mTarget); renderTargetCache[rt.mTarget] = subPass.mRenderTexture; @@ -690,11 +779,19 @@ namespace MWRender { auto& textures = mTextures[frameId]; + auto width = renderWidth(); + auto height = renderHeight(); + for (auto& texture : textures) { if (!texture) - texture = new osg::Texture2D; - texture->setTextureSize(mWidth, mHeight); + { + if (Stereo::getMultiview()) + texture = new osg::Texture2DArray; + else + texture = new osg::Texture2D; + } + setTextureSize(texture, width, height); texture->setSourceFormat(GL_RGBA); texture->setSourceType(GL_UNSIGNED_BYTE); texture->setInternalFormat(GL_RGBA); @@ -719,7 +816,7 @@ namespace MWRender textures[Tex_Scene]->setWrap(osg::Texture::WRAP_T, mMainTemplate->getWrap(osg::Texture2D::WRAP_T)); } - auto setupDepth = [] (osg::Texture2D* tex) { + auto setupDepth = [] (osg::Texture* tex) { tex->setSourceFormat(GL_DEPTH_STENCIL_EXT); tex->setSourceType(SceneUtil::AutoDepth::depthSourceType()); tex->setInternalFormat(SceneUtil::AutoDepth::depthInternalFormat()); @@ -750,11 +847,10 @@ namespace MWRender mHUDCamera->setViewport(0, 0, mWidth, mHeight); mViewer->getCamera()->removeCullCallback(mPingPongCull); - mPingPongCull = new PingPongCull; + mPingPongCull = new PingPongCull(this); mViewer->getCamera()->addCullCallback(mPingPongCull); mPingPongCanvas = new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()); - mHUDCamera->addChild(mPingPongCanvas); mHUDCamera->setNodeMask(Mask_RenderToTexture); @@ -778,7 +874,7 @@ namespace MWRender if (Misc::StringUtils::ciEqual(technique->getName(), name)) return technique; - auto technique = std::make_shared(*mVFS, *mRendering.getResourceSystem()->getImageManager(), name, mWidth, mHeight, mUBO, mNormalsSupported); + auto technique = std::make_shared(*mVFS, *mRendering.getResourceSystem()->getImageManager(), name, renderWidth(), renderHeight(), mUBO, mNormalsSupported); technique->compile(); @@ -854,5 +950,19 @@ namespace MWRender if (technique->getDynamic()) disableTechnique(technique); } + + int PostProcessor::renderWidth() const + { + if (Stereo::getStereo()) + return Stereo::Manager::instance().eyeResolution().x(); + return mWidth; + } + + int PostProcessor::renderHeight() const + { + if (Stereo::getStereo()) + return Stereo::Manager::instance().eyeResolution().y(); + return mHeight; + } } diff --git a/apps/openmw/mwrender/postprocessor.hpp b/apps/openmw/mwrender/postprocessor.hpp index 01a9e1088c..2fa3e5622a 100644 --- a/apps/openmw/mwrender/postprocessor.hpp +++ b/apps/openmw/mwrender/postprocessor.hpp @@ -55,7 +55,7 @@ namespace MWRender { public: using FBOArray = std::array, 5>; - using TextureArray = std::array, 5>; + using TextureArray = std::array, 5>; using TechniqueList = std::vector>; enum TextureIndex @@ -94,7 +94,7 @@ namespace MWRender osg::ref_ptr getFbo(FBOIndex index, unsigned int frameId) { return mFbos[frameId][index]; } - osg::ref_ptr getTexture(TextureIndex index, unsigned int frameId) { return mTextures[frameId][index]; } + osg::ref_ptr getTexture(TextureIndex index, unsigned int frameId) { return mTextures[frameId][index]; } osg::ref_ptr getPrimaryFbo(unsigned int frameId) { return mFbos[frameId][FBO_Multisample] ? mFbos[frameId][FBO_Multisample] : mFbos[frameId][FBO_Primary]; } @@ -177,6 +177,9 @@ namespace MWRender void disableDynamicShaders(); + int renderWidth() const; + int renderHeight() const; + private: void populateTechniqueFiles(); @@ -242,7 +245,7 @@ namespace MWRender bool mUBO; int mGLSLVersion; - osg::ref_ptr mMainTemplate; + osg::ref_ptr mMainTemplate; osg::ref_ptr mStateUpdater; osg::ref_ptr mPingPongCull; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e639880b37..df14f7263c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -110,14 +110,14 @@ namespace MWRender { auto* uProjectionMatrix = stateset->getUniform("projectionMatrix"); if (uProjectionMatrix) - uProjectionMatrix->set(Stereo::Manager::instance().computeEyeProjection(0, SceneUtil::AutoDepth::isReversed())); + uProjectionMatrix->set(Stereo::Manager::instance().computeEyeViewOffset(0) * Stereo::Manager::instance().computeEyeProjection(0, SceneUtil::AutoDepth::isReversed())); } void applyRight(osg::StateSet* stateset, osgUtil::CullVisitor* nv) override { auto* uProjectionMatrix = stateset->getUniform("projectionMatrix"); if (uProjectionMatrix) - uProjectionMatrix->set(Stereo::Manager::instance().computeEyeProjection(1, SceneUtil::AutoDepth::isReversed())); + uProjectionMatrix->set(Stereo::Manager::instance().computeEyeViewOffset(1) * Stereo::Manager::instance().computeEyeProjection(1, SceneUtil::AutoDepth::isReversed())); } void setProjectionMatrix(const osg::Matrixf& projectionMatrix) diff --git a/apps/openmw/mwrender/screenshotmanager.cpp b/apps/openmw/mwrender/screenshotmanager.cpp index 64961bf037..40665cc250 100644 --- a/apps/openmw/mwrender/screenshotmanager.cpp +++ b/apps/openmw/mwrender/screenshotmanager.cpp @@ -109,9 +109,7 @@ namespace MWRender size_t frameId = renderInfo.getState()->getFrameStamp()->getFrameNumber() % 2; osg::FrameBufferObject* fbo = nullptr; - if (Stereo::getStereo()) - fbo = Stereo::Manager::instance().multiviewFramebuffer()->layerFbo(0); - else if (postProcessor && postProcessor->getFbo(PostProcessor::FBO_Primary, frameId)) + if (postProcessor && postProcessor->getFbo(PostProcessor::FBO_Primary, frameId)) fbo = postProcessor->getFbo(PostProcessor::FBO_Primary, frameId); if (fbo) diff --git a/apps/openmw/mwrender/skyutil.cpp b/apps/openmw/mwrender/skyutil.cpp index 843582064b..00bc2aef89 100644 --- a/apps/openmw/mwrender/skyutil.cpp +++ b/apps/openmw/mwrender/skyutil.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -604,33 +605,63 @@ namespace MWRender } - class SkyMultiviewStatesetUpdater: public SceneUtil::StateSetUpdater + class SkyStereoStatesetUpdater : public SceneUtil::StateSetUpdater { public: - SkyMultiviewStatesetUpdater() + SkyStereoStatesetUpdater() { } protected: - virtual void setDefaults(osg::StateSet* stateset) + void setDefaults(osg::StateSet* stateset) override { - stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "viewMatrixMultiView", 2), osg::StateAttribute::OVERRIDE); + if (Stereo::getMultiview()) + stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2), osg::StateAttribute::OVERRIDE); + else + stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrix"), osg::StateAttribute::OVERRIDE); + } - virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) + void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) override { - auto* viewMatrixMultiViewUniform = stateset->getUniform("viewMatrixMultiView"); - auto& sm = Stereo::Manager::instance(); - - for (int view : {0, 1}) + if (Stereo::getMultiview()) { - auto viewOffsetMatrix = sm.computeEyeViewOffset(view); - for (int col : {0, 1, 2}) - viewOffsetMatrix(3, col) = 0; + auto* projectionMatrixMultiViewUniform = stateset->getUniform("projectionMatrixMultiView"); + auto& sm = Stereo::Manager::instance(); - viewMatrixMultiViewUniform->setElement(view, viewOffsetMatrix); + for (int view : {0, 1}) + { + auto projectionMatrix = sm.computeEyeProjection(view, true); + auto viewOffsetMatrix = sm.computeEyeViewOffset(view); + for (int col : {0, 1, 2}) + viewOffsetMatrix(3, col) = 0; + + projectionMatrixMultiViewUniform->setElement(view, viewOffsetMatrix * projectionMatrix); + } } } + void applyLeft(osg::StateSet* stateset, osgUtil::CullVisitor* /*cv*/) override + { + auto& sm = Stereo::Manager::instance(); + auto* projectionMatrixUniform = stateset->getUniform("projectionMatrix"); + auto projectionMatrix = sm.computeEyeProjection(0, true); + auto viewOffsetMatrix = sm.computeEyeViewOffset(0); + for (int col : {0, 1, 2}) + viewOffsetMatrix(3, col) = 0; + + projectionMatrixUniform->set(viewOffsetMatrix * projectionMatrix); + } + void applyRight(osg::StateSet* stateset, osgUtil::CullVisitor* /*cv*/) override + { + auto& sm = Stereo::Manager::instance(); + auto* projectionMatrixUniform = stateset->getUniform("projectionMatrix"); + auto projectionMatrix = sm.computeEyeProjection(1, true); + auto viewOffsetMatrix = sm.computeEyeViewOffset(1); + for (int col : {0, 1, 2}) + viewOffsetMatrix(3, col) = 0; + + projectionMatrixUniform->set(viewOffsetMatrix * projectionMatrix); + } private: }; @@ -643,7 +674,8 @@ namespace MWRender setCullingActive(false); addCullCallback(new CameraRelativeTransformCullCallback); - addCullCallback(new SkyMultiviewStatesetUpdater); + if (Stereo::getStereo()) + addCullCallback(new SkyStereoStatesetUpdater); } CameraRelativeTransform::CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) diff --git a/apps/openmw/mwrender/transparentpass.cpp b/apps/openmw/mwrender/transparentpass.cpp index e5368e7f3e..084eca1cdb 100644 --- a/apps/openmw/mwrender/transparentpass.cpp +++ b/apps/openmw/mwrender/transparentpass.cpp @@ -2,10 +2,17 @@ #include #include +#include + +#ifdef OSG_HAS_MULTIVIEW +#include +#endif #include #include +#include +#include namespace MWRender { @@ -24,8 +31,10 @@ namespace MWRender mStateSet->setTextureAttributeAndModes(0, dummyTexture); - osg::ref_ptr vertex = shaderManager.getShader("blended_depth_postpass_vertex.glsl", {}, osg::Shader::VERTEX); - osg::ref_ptr fragment = shaderManager.getShader("blended_depth_postpass_fragment.glsl", {}, osg::Shader::FRAGMENT); + Shader::ShaderManager::DefineMap defines; + Stereo::Manager::instance().shaderStereoDefines(defines); + osg::ref_ptr vertex = shaderManager.getShader("blended_depth_postpass_vertex.glsl", defines, osg::Shader::VERTEX); + osg::ref_ptr fragment = shaderManager.getShader("blended_depth_postpass_fragment.glsl", defines, osg::Shader::FRAGMENT); mStateSet->setAttributeAndModes(new osg::BlendFunc, modeOff); mStateSet->setAttributeAndModes(shaderManager.getProgram(vertex, fragment), modeOn); @@ -59,9 +68,22 @@ namespace MWRender const osg::Texture* tex = opaqueFbo->getAttachment(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER).getTexture(); - opaqueFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); - - ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + if (Stereo::getMultiview()) + { + if (!mMultiviewDepthResolveLeftSource[frameId]) + setupMultiviewDepthResolveBuffers(frameId); + mMultiviewDepthResolveLeftTarget[frameId]->apply(state, osg::FrameBufferObject::BindTarget::DRAW_FRAMEBUFFER); + mMultiviewDepthResolveLeftSource[frameId]->apply(state, osg::FrameBufferObject::BindTarget::READ_FRAMEBUFFER); + ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + mMultiviewDepthResolveRightTarget[frameId]->apply(state, osg::FrameBufferObject::BindTarget::DRAW_FRAMEBUFFER); + mMultiviewDepthResolveRightSource[frameId]->apply(state, osg::FrameBufferObject::BindTarget::READ_FRAMEBUFFER); + ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + else + { + opaqueFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); + ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } msaaFbo ? msaaFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER) : fbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); @@ -80,6 +102,47 @@ namespace MWRender bin->setStateSet(restore); msaaFbo ? msaaFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER) : fbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER); + state.checkGLErrors("after TransparentDepthBinCallback::drawImplementation"); } -} \ No newline at end of file + void TransparentDepthBinCallback::dirtyFrame(int frameId) + { + mMultiviewDepthResolveLeftSource[frameId] = mMultiviewDepthResolveRightSource[frameId] = nullptr; + mMultiviewDepthResolveLeftTarget[frameId] = mMultiviewDepthResolveRightTarget[frameId] = nullptr; + } + + osg::FrameBufferAttachment makeSingleLayerAttachmentFromMultilayerAttachment(osg::FrameBufferAttachment attachment, int layer) + { + osg::Texture* tex = attachment.getTexture(); + + if (tex->getTextureTarget() == GL_TEXTURE_2D_ARRAY) + return osg::FrameBufferAttachment(static_cast(tex), layer, 0); + +#ifdef OSG_HAS_MULTIVIEW + if (tex->getTextureTarget() == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) + return osg::FrameBufferAttachment(static_cast(tex), layer, 0); +#endif + + Log(Debug::Error) << "Attempted to extract a layer from an unlayered texture"; + + return osg::FrameBufferAttachment(); + } + + void TransparentDepthBinCallback::setupMultiviewDepthResolveBuffers(int frameId) + { + const osg::FrameBufferObject::BufferComponent component = osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER; + const auto& sourceFbo = mMsaaFbo[frameId] ? mMsaaFbo[frameId] : mFbo[frameId]; + const auto& sourceAttachment = sourceFbo->getAttachment(component); + mMultiviewDepthResolveLeftSource[frameId] = new osg::FrameBufferObject; + mMultiviewDepthResolveLeftSource[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(sourceAttachment, 0)); + mMultiviewDepthResolveRightSource[frameId] = new osg::FrameBufferObject; + mMultiviewDepthResolveRightSource[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(sourceAttachment, 1)); + const auto& targetFbo = mOpaqueFbo[frameId]; + const auto& targetAttachment = targetFbo->getAttachment(component); + mMultiviewDepthResolveLeftTarget[frameId] = new osg::FrameBufferObject; + mMultiviewDepthResolveLeftTarget[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(targetAttachment, 0)); + mMultiviewDepthResolveRightTarget[frameId] = new osg::FrameBufferObject; + mMultiviewDepthResolveRightTarget[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(targetAttachment, 1)); + } + +} diff --git a/apps/openmw/mwrender/transparentpass.hpp b/apps/openmw/mwrender/transparentpass.hpp index a933dde989..a9093acbf1 100644 --- a/apps/openmw/mwrender/transparentpass.hpp +++ b/apps/openmw/mwrender/transparentpass.hpp @@ -23,11 +23,18 @@ namespace MWRender TransparentDepthBinCallback(Shader::ShaderManager& shaderManager, bool postPass); void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) override; + void dirtyFrame(int frameId); + void setupMultiviewDepthResolveBuffers(int frameId); std::array, 2> mFbo; std::array, 2> mMsaaFbo; std::array, 2> mOpaqueFbo; + std::array, 2> mMultiviewDepthResolveLeftSource; + std::array, 2> mMultiviewDepthResolveRightSource; + std::array, 2> mMultiviewDepthResolveLeftTarget; + std::array, 2> mMultiviewDepthResolveRightTarget; + private: osg::ref_ptr mStateSet; bool mPostPass; @@ -35,4 +42,4 @@ namespace MWRender } -#endif \ No newline at end of file +#endif diff --git a/components/debug/gldebug.cpp b/components/debug/gldebug.cpp index a0c7aa6206..81bd7eb003 100644 --- a/components/debug/gldebug.cpp +++ b/components/debug/gldebug.cpp @@ -82,18 +82,23 @@ namespace Debug break; case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: typeStr = "DEPRECATED_BEHAVIOR"; + logSeverity = Warning; break; case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: typeStr = "UNDEFINED_BEHAVIOR"; + logSeverity = Warning; break; case GL_DEBUG_TYPE_PORTABILITY: typeStr = "PORTABILITY"; + logSeverity = Debug; break; case GL_DEBUG_TYPE_PERFORMANCE: typeStr = "PERFORMANCE"; + logSeverity = Debug; break; case GL_DEBUG_TYPE_OTHER: typeStr = "OTHER"; + logSeverity = Debug; break; default: typeStr = "UNDEFINED"; diff --git a/components/fx/pass.cpp b/components/fx/pass.cpp index d264ceae2a..b32dd2e0b1 100644 --- a/components/fx/pass.cpp +++ b/components/fx/pass.cpp @@ -29,6 +29,19 @@ namespace #endif omw_Out vec2 omw_TexCoord; +void main() +{ + omw_Position = vec4(omw_Vertex.xy, 0.0, 1.0); + omw_TexCoord = omw_Position.xy * 0.5 + 0.5; +})GLSL"; + + constexpr char s_DefaultVertexMultiview[] = R"GLSL( +layout(num_views = 2) in; +#if OMW_USE_BINDINGS + omw_In vec2 omw_Vertex; +#endif +omw_Out vec2 omw_TexCoord; + void main() { omw_Position = vec4(omw_Vertex.xy, 0.0, 1.0); @@ -81,6 +94,11 @@ uniform @builtinSampler omw_SamplerNormals; uniform vec4 omw_PointLights[@pointLightCount]; uniform int omw_PointLightsCount; +#if OMW_MULTIVIEW +uniform mat4 projectionMatrixMultiView[2]; +uniform mat4 invProjectionMatrixMultiView[2]; +#endif + int omw_GetPointLightCount() { return omw_PointLightsCount; @@ -112,6 +130,25 @@ float omw_GetPointLightRadius(int index) uniform _omw_data omw; #endif + +mat4 omw_ProjectionMatrix() +{ +#if OMW_MULTIVIEW + return projectionMatrixMultiView[gl_ViewID_OVR]; +#else + return omw.projectionMatrix; +#endif +} + +mat4 omw_InvProjectionMatrix() +{ +#if OMW_MULTIVIEW + return invProjectionMatrixMultiView[gl_ViewID_OVR]; +#else + return omw.invProjectionMatrix; +#endif +} + float omw_GetDepth(vec2 uv) { #if OMW_MULTIVIEW @@ -266,7 +303,7 @@ float omw_GetPointLightRadius(int index) if (mType == Type::Pixel) { if (!mVertex) - mVertex = new osg::Shader(osg::Shader::VERTEX, s_DefaultVertex); + mVertex = new osg::Shader(osg::Shader::VERTEX, Stereo::getMultiview() ? s_DefaultVertexMultiview : s_DefaultVertex); mVertex->setShaderSource(getPassHeader(technique, preamble).append(mVertex->getShaderSource())); mFragment->setShaderSource(getPassHeader(technique, preamble, true).append(mFragment->getShaderSource())); diff --git a/components/fx/stateupdater.hpp b/components/fx/stateupdater.hpp index 39098c5e2f..b2beb8d576 100644 --- a/components/fx/stateupdater.hpp +++ b/components/fx/stateupdater.hpp @@ -20,9 +20,11 @@ namespace fx mData.get() = osg::Matrixf::inverse(matrix); } - void setViewMatrix(const osg::Matrixf& matrix) { mData.get() = matrix; } - - void setInvViewMatrix(const osg::Matrixf& matrix) { mData.get() = matrix; } + void setViewMatrix(const osg::Matrixf& matrix) + { + mData.get() = matrix; + mData.get() = osg::Matrixf::inverse(matrix); + } void setPrevViewMatrix(const osg::Matrixf& matrix) { mData.get() = matrix;} @@ -197,4 +199,4 @@ namespace fx }; } -#endif \ No newline at end of file +#endif diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index a2779109ac..7dc2c6af41 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -430,7 +430,7 @@ namespace Resource mConvertAlphaTestToAlphaToCoverage = convert; } - void SceneManager::setOpaqueDepthTex(osg::ref_ptr texturePing, osg::ref_ptr texturePong) + void SceneManager::setOpaqueDepthTex(osg::ref_ptr texturePing, osg::ref_ptr texturePong) { mOpaqueDepthTex = { texturePing, texturePong }; } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index ba5c75f7ea..82adef9dc9 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -109,7 +109,7 @@ namespace Resource void setSupportedLightingMethods(const SceneUtil::LightManager::SupportedMethods& supported); bool isSupportedLightingMethod(SceneUtil::LightingMethod method) const; - void setOpaqueDepthTex(osg::ref_ptr texturePing, osg::ref_ptr texturePong); + void setOpaqueDepthTex(osg::ref_ptr texturePing, osg::ref_ptr texturePong); enum class UBOBinding { @@ -213,7 +213,7 @@ namespace Resource SceneUtil::LightManager::SupportedMethods mSupportedLightingMethods; bool mConvertAlphaTestToAlphaToCoverage; bool mSupportsNormalsRT; - std::array, 2> mOpaqueDepthTex; + std::array, 2> mOpaqueDepthTex; osg::ref_ptr mSharedStateManager; mutable std::mutex mSharedStateMutex; diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 57fe2cb0e8..b1a1832946 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -39,7 +39,7 @@ namespace OpaqueDepthAttribute(const OpaqueDepthAttribute& copy, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) : osg::StateAttribute(copy, copyop), mTextures(copy.mTextures), mUnit(copy.mUnit) {} - void setTexturesAndUnit(const std::array, 2>& textures, int unit) + void setTexturesAndUnit(const std::array, 2>& textures, int unit) { mTextures = textures; mUnit = unit; @@ -68,7 +68,7 @@ namespace } private: - mutable std::array, 2> mTextures; + mutable std::array, 2> mTextures; int mUnit; }; } @@ -970,7 +970,7 @@ namespace Shader mConvertAlphaTestToAlphaToCoverage = convert; } - void ShaderVisitor::setOpaqueDepthTex(osg::ref_ptr texturePing, osg::ref_ptr texturePong) + void ShaderVisitor::setOpaqueDepthTex(osg::ref_ptr texturePing, osg::ref_ptr texturePong) { mOpaqueDepthTex = { texturePing, texturePong }; } diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index cd1ca421d9..3ddcd9815f 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -48,7 +48,7 @@ namespace Shader void setConvertAlphaTestToAlphaToCoverage(bool convert); - void setOpaqueDepthTex(osg::ref_ptr texturePing, osg::ref_ptr texturePong); + void setOpaqueDepthTex(osg::ref_ptr texturePing, osg::ref_ptr texturePong); void setSupportsNormalsRT(bool supports) { mSupportsNormalsRT = supports; } @@ -122,7 +122,7 @@ namespace Shader bool adjustGeometry(osg::Geometry& sourceGeometry, const ShaderRequirements& reqs); osg::ref_ptr mProgramTemplate; - std::array, 2> mOpaqueDepthTex; + std::array, 2> mOpaqueDepthTex; }; class ReinstateRemovedStateVisitor : public osg::NodeVisitor diff --git a/components/stereo/stereomanager.cpp b/components/stereo/stereomanager.cpp index 3cca855e7e..645fc59f29 100644 --- a/components/stereo/stereomanager.cpp +++ b/components/stereo/stereomanager.cpp @@ -72,7 +72,7 @@ namespace Stereo osg::Matrix dummy; auto* uProjectionMatrix = stateset->getUniform("projectionMatrix"); if (uProjectionMatrix) - uProjectionMatrix->set(mManager->computeEyeProjection(0, SceneUtil::AutoDepth::isReversed())); + uProjectionMatrix->set(mManager->computeEyeViewOffset(0) * mManager->computeEyeProjection(0, SceneUtil::AutoDepth::isReversed())); } void applyRight(osg::StateSet* stateset, osgUtil::CullVisitor* nv) override @@ -80,7 +80,7 @@ namespace Stereo osg::Matrix dummy; auto* uProjectionMatrix = stateset->getUniform("projectionMatrix"); if (uProjectionMatrix) - uProjectionMatrix->set(mManager->computeEyeProjection(1, SceneUtil::AutoDepth::isReversed())); + uProjectionMatrix->set(mManager->computeEyeViewOffset(1) * mManager->computeEyeProjection(1, SceneUtil::AutoDepth::isReversed())); } private: @@ -99,8 +99,8 @@ namespace Stereo protected: virtual void setDefaults(osg::StateSet* stateset) { - stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "viewMatrixMultiView", 2)); stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2)); + stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "invProjectionMatrixMultiView", 2)); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) @@ -248,25 +248,23 @@ namespace Stereo osg::Matrixd computeLeftEyeProjection(const osg::Matrixd& projection) const override { (void)projection; - return mManager->computeEyeProjection(0, false); + return mManager->computeEyeViewOffset(0) * mManager->computeEyeProjection(0, false); } osg::Matrixd computeLeftEyeView(const osg::Matrixd& view) const override { - (void)view; - return mManager->computeEyeView(0); + return view; } osg::Matrixd computeRightEyeProjection(const osg::Matrixd& projection) const override { (void)projection; - return mManager->computeEyeProjection(1, false); + return mManager->computeEyeViewOffset(1) * mManager->computeEyeProjection(1, false); } osg::Matrixd computeRightEyeView(const osg::Matrixd& view) const override { - (void)view; - return mManager->computeEyeView(1); + return view; } Manager* mManager; @@ -305,15 +303,16 @@ namespace Stereo void Manager::updateStereoFramebuffer() { + //VR-TODO: in VR, still need to have this framebuffer attached before the postprocessor is created auto samples = Settings::Manager::getInt("antialiasing", "Video"); auto eyeRes = eyeResolution(); - if (mMultiviewFramebuffer) - mMultiviewFramebuffer->detachFrom(mMainCamera); + //if (mMultiviewFramebuffer) + // mMultiviewFramebuffer->detachFrom(mMainCamera); mMultiviewFramebuffer = std::make_shared(static_cast(eyeRes.x()), static_cast(eyeRes.y()), samples); mMultiviewFramebuffer->attachColorComponent(SceneUtil::Color::colorSourceFormat(), SceneUtil::Color::colorSourceType(), SceneUtil::Color::colorInternalFormat()); mMultiviewFramebuffer->attachDepthComponent(SceneUtil::AutoDepth::depthSourceFormat(), SceneUtil::AutoDepth::depthSourceType(), SceneUtil::AutoDepth::depthInternalFormat()); - mMultiviewFramebuffer->attachTo(mMainCamera); + //mMultiviewFramebuffer->attachTo(mMainCamera); } void Manager::update() @@ -328,17 +327,14 @@ namespace Stereo if (mUpdateViewCallback) { mUpdateViewCallback->updateView(mView[0], mView[1]); - auto viewMatrix = mMainCamera->getViewMatrix(); mViewOffsetMatrix[0] = mView[0].viewMatrix(true); mViewOffsetMatrix[1] = mView[1].viewMatrix(true); - mViewMatrix[0] = viewMatrix * mViewOffsetMatrix[0]; - mViewMatrix[1] = viewMatrix * mViewOffsetMatrix[1]; mProjectionMatrix[0] = mView[0].perspectiveMatrix(near_, far_, false); mProjectionMatrix[1] = mView[1].perspectiveMatrix(near_, far_, false); if (SceneUtil::AutoDepth::isReversed()) { mProjectionMatrixReverseZ[0] = mView[0].perspectiveMatrix(near_, far_, true); - mProjectionMatrixReverseZ[1] = mView[1].perspectiveMatrix(near_, far_, true); + mProjectionMatrixReverseZ[1] = mView[1].perspectiveMatrix(near_, far_, true); } View masterView; @@ -353,10 +349,8 @@ namespace Stereo { auto* ds = osg::DisplaySettings::instance().get(); auto viewMatrix = mMainCamera->getViewMatrix(); - mViewMatrix[0] = ds->computeLeftEyeViewImplementation(viewMatrix); - mViewMatrix[1] = ds->computeRightEyeViewImplementation(viewMatrix); - mViewOffsetMatrix[0] = osg::Matrix::inverse(viewMatrix) * mViewMatrix[0]; - mViewOffsetMatrix[1] = osg::Matrix::inverse(viewMatrix) * mViewMatrix[1]; + mViewOffsetMatrix[0] = osg::Matrix::inverse(viewMatrix) * ds->computeLeftEyeViewImplementation(viewMatrix); + mViewOffsetMatrix[1] = osg::Matrix::inverse(viewMatrix) * ds->computeRightEyeViewImplementation(viewMatrix); mProjectionMatrix[0] = ds->computeLeftEyeProjectionImplementation(projectionMatrix); mProjectionMatrix[1] = ds->computeRightEyeProjectionImplementation(projectionMatrix); if (SceneUtil::AutoDepth::isReversed()) @@ -368,21 +362,23 @@ namespace Stereo mFrustumManager->update( { - mViewOffsetMatrix[0] * mProjectionMatrix[0], - mViewOffsetMatrix[1] * mProjectionMatrix[1] + mViewOffsetMatrix[0] * mProjectionMatrix[0], + mViewOffsetMatrix[1] * mProjectionMatrix[1] }); } void Manager::updateMultiviewStateset(osg::StateSet* stateset) { // Update stereo uniforms - auto * viewMatrixMultiViewUniform = stateset->getUniform("viewMatrixMultiView"); auto * projectionMatrixMultiViewUniform = stateset->getUniform("projectionMatrixMultiView"); + auto * invProjectionMatrixMultiViewUniform = stateset->getUniform("invProjectionMatrixMultiView"); for (int view : {0, 1}) { - viewMatrixMultiViewUniform->setElement(view, mViewOffsetMatrix[view]); - projectionMatrixMultiViewUniform->setElement(view, computeEyeProjection(view, SceneUtil::AutoDepth::isReversed())); + auto projectionMatrix = computeEyeViewOffset(view) * computeEyeProjection(view, SceneUtil::AutoDepth::isReversed()); + auto invProjectionMatrix = osg::Matrix::inverse(projectionMatrix); + projectionMatrixMultiViewUniform->setElement(view, projectionMatrix); + invProjectionMatrixMultiViewUniform->setElement(view, invProjectionMatrix); } } @@ -401,11 +397,6 @@ namespace Stereo return reverseZ ? mProjectionMatrixReverseZ[view] : mProjectionMatrix[view]; } - osg::Matrixd Manager::computeEyeView(int view) const - { - return mViewMatrix[view]; - } - osg::Matrixd Manager::computeEyeViewOffset(int view) const { return mViewOffsetMatrix[view]; diff --git a/components/stereo/stereomanager.hpp b/components/stereo/stereomanager.hpp index 41c05b8785..48af043fd7 100644 --- a/components/stereo/stereomanager.hpp +++ b/components/stereo/stereomanager.hpp @@ -68,7 +68,6 @@ namespace Stereo void setCullCallback(osg::ref_ptr cb); osg::Matrixd computeEyeProjection(int view, bool reverseZ) const; - osg::Matrixd computeEyeView(int view) const; osg::Matrixd computeEyeViewOffset(int view) const; //! Sets up any definitions necessary for stereo rendering @@ -116,7 +115,6 @@ namespace Stereo osg::Vec2i mEyeResolutionOverride; std::array mView; - std::array mViewMatrix; std::array mViewOffsetMatrix; std::array mProjectionMatrix; std::array mProjectionMatrixReverseZ; diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index affb3fc940..05fe62bf0a 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -34,6 +34,8 @@ set(SHADER_FILES shadowcasting_vertex.glsl shadowcasting_fragment.glsl vertexcolors.glsl + multiview_resolve_vertex.glsl + multiview_resolve_fragment.glsl nv_default_vertex.glsl nv_default_fragment.glsl nv_nolighting_vertex.glsl diff --git a/files/shaders/blended_depth_postpass_vertex.glsl b/files/shaders/blended_depth_postpass_vertex.glsl index 471a2df16a..ee27507983 100644 --- a/files/shaders/blended_depth_postpass_vertex.glsl +++ b/files/shaders/blended_depth_postpass_vertex.glsl @@ -5,11 +5,12 @@ uniform mat4 projectionMatrix; varying vec2 diffuseMapUV; varying float alphaPassthrough; +#include "openmw_vertex.h.glsl" #include "vertexcolors.glsl" void main() { - gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); + gl_Position = mw_modelToClip(gl_Vertex); if (colorMode == 2) alphaPassthrough = gl_Color.a; diff --git a/files/shaders/fullscreen_tri_vertex.glsl b/files/shaders/fullscreen_tri_vertex.glsl index 794e0827c4..1166a44a54 100644 --- a/files/shaders/fullscreen_tri_vertex.glsl +++ b/files/shaders/fullscreen_tri_vertex.glsl @@ -2,6 +2,8 @@ varying vec2 uv; +#include "openmw_vertex.h.glsl" + void main() { gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0); diff --git a/files/shaders/multiview_resolve_fragment.glsl b/files/shaders/multiview_resolve_fragment.glsl new file mode 100644 index 0000000000..c0a137464f --- /dev/null +++ b/files/shaders/multiview_resolve_fragment.glsl @@ -0,0 +1,18 @@ +#version 120 +#extension GL_EXT_texture_array : require + +varying vec2 uv; +uniform sampler2DArray omw_SamplerLastShader; + +void main() +{ + int view = 0; + vec3 uvz = vec3(uv.x * 2., uv.y, 0); + if(uvz.x > 1.) + { + uvz.x -= 1.; + uvz.z = 1; + } + + gl_FragColor = texture2DArray(omw_SamplerLastShader, uvz); +} \ No newline at end of file diff --git a/files/shaders/multiview_resolve_vertex.glsl b/files/shaders/multiview_resolve_vertex.glsl new file mode 100644 index 0000000000..794e0827c4 --- /dev/null +++ b/files/shaders/multiview_resolve_vertex.glsl @@ -0,0 +1,9 @@ +#version 120 + +varying vec2 uv; + +void main() +{ + gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0); + uv = gl_Position.xy * 0.5 + 0.5; +} diff --git a/files/shaders/openmw_vertex.glsl b/files/shaders/openmw_vertex.glsl index 68a98c7880..b671570348 100644 --- a/files/shaders/openmw_vertex.glsl +++ b/files/shaders/openmw_vertex.glsl @@ -18,8 +18,3 @@ vec4 mw_viewToClip(vec4 pos) { return projectionMatrix * pos; } - -vec4 mw_viewStereoAdjust(vec4 pos) -{ - return pos; -} diff --git a/files/shaders/openmw_vertex.h.glsl b/files/shaders/openmw_vertex.h.glsl index 3794121656..9d7f496a6a 100644 --- a/files/shaders/openmw_vertex.h.glsl +++ b/files/shaders/openmw_vertex.h.glsl @@ -3,5 +3,4 @@ vec4 mw_modelToClip(vec4 pos); vec4 mw_modelToView(vec4 pos); -vec4 mw_viewToClip(vec4 pos); -vec4 mw_viewStereoAdjust(vec4 pos); \ No newline at end of file +vec4 mw_viewToClip(vec4 pos); \ No newline at end of file diff --git a/files/shaders/openmw_vertex_multiview.glsl b/files/shaders/openmw_vertex_multiview.glsl index c860112d5c..64230a6e4a 100644 --- a/files/shaders/openmw_vertex_multiview.glsl +++ b/files/shaders/openmw_vertex_multiview.glsl @@ -8,24 +8,18 @@ layout(num_views = @numViews) in; #include "openmw_vertex.h.glsl" uniform mat4 projectionMatrixMultiView[@numViews]; -uniform mat4 viewMatrixMultiView[@numViews]; vec4 mw_modelToClip(vec4 pos) { - return projectionMatrixMultiView[gl_ViewID_OVR] * mw_modelToView(pos); + return mw_viewToClip(mw_modelToView(pos)); } vec4 mw_modelToView(vec4 pos) { - return viewMatrixMultiView[gl_ViewID_OVR] * gl_ModelViewMatrix * pos; + return gl_ModelViewMatrix * pos; } vec4 mw_viewToClip(vec4 pos) { - return projectionMatrixMultiView[gl_ViewID_OVR] * viewMatrixMultiView[gl_ViewID_OVR] * pos; -} - -vec4 mw_viewStereoAdjust(vec4 pos) -{ - return viewMatrixMultiView[gl_ViewID_OVR] * pos; -} + return projectionMatrixMultiView[gl_ViewID_OVR] * pos; +} \ No newline at end of file