1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 15:59:54 +00:00

Merge branch 'postprocessor-stereo' into 'master'

[Postprocessing] Stereo integration

See merge request OpenMW/openmw!1988
This commit is contained in:
psi29a 2022-06-21 15:55:06 +00:00
commit feef257584
29 changed files with 578 additions and 179 deletions

View file

@ -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<osg::Depth> mDepth;

View file

@ -2,6 +2,10 @@
#include <components/shader/shadermanager.hpp>
#include <components/debug/debuglog.hpp>
#include <components/stereo/stereomanager.hpp>
#include <components/stereo/multiview.hpp>
#include <osg/Texture2DArray>
#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<osg::Texture2D*>(tex));
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2d));
}
break;
case GL_TEXTURE_2D_ARRAY:
{
#ifdef OSG_HAS_MULTIVIEW
auto* tex2dArray = new osg::Texture2DArray(*static_cast<osg::Texture2DArray*>(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();

View file

@ -38,11 +38,11 @@ namespace MWRender
void setSceneTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex) { mBufferData[frameId].sceneTex = tex; }
void setLDRSceneTexture(size_t frameId, osg::ref_ptr<osg::Texture2D> tex) { mBufferData[frameId].sceneTexLDR = tex; }
void setLDRSceneTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex) { mBufferData[frameId].sceneTexLDR = tex; }
void setDepthTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex) { mBufferData[frameId].depthTex = tex; }
void setNormalsTexture(size_t frameId, osg::ref_ptr<osg::Texture2D> tex) { mBufferData[frameId].normalsTex = tex; }
void setNormalsTexture(size_t frameId, osg::ref_ptr<osg::Texture> 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<osg::Program> mFallbackProgram;
osg::ref_ptr<osg::Program> mMultiviewResolveProgram;
osg::ref_ptr<osg::StateSet> mFallbackStateSet;
osg::ref_ptr<osg::StateSet> mMultiviewResolveStateSet;
mutable osg::ref_ptr<osg::FrameBufferObject> mMultiviewResolveFramebuffer;
struct BufferData
{
@ -73,12 +76,13 @@ namespace MWRender
osg::ref_ptr<osg::Texture> sceneTex;
osg::ref_ptr<osg::Texture> depthTex;
osg::ref_ptr<osg::Texture2D> sceneTexLDR;
osg::ref_ptr<osg::Texture2D> normalsTex;
osg::ref_ptr<osg::Texture> sceneTexLDR;
osg::ref_ptr<osg::Texture> normalsTex;
};
mutable std::array<BufferData, 2> mBufferData;
mutable std::array<osg::ref_ptr<osg::FrameBufferObject>, 3> mFbos;
mutable osg::ref_ptr<osg::Viewport> mRenderViewport;
mutable bool mLoggedLastError = false;
};

View file

@ -4,11 +4,31 @@
#include <osg/FrameBufferObject>
#include <osgUtil/CullVisitor>
#include <components/stereo/stereomanager.hpp>
#include <components/stereo/multiview.hpp>
#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<MWRender::PostProcessor*>(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);
}
}

View file

@ -7,15 +7,27 @@
#include "postprocessor.hpp"
namespace osg
{
class StateSet;
class Viewport;
}
namespace MWRender
{
class PostProcessor;
class PingPongCull : public SceneUtil::NodeCallback<PingPongCull, osg::Node*, osgUtil::CullVisitor*>
{
public:
PingPongCull(PostProcessor* pp);
~PingPongCull();
void operator()(osg::Node* node, osgUtil::CullVisitor* nv);
private:
osg::Matrixf mLastViewMatrix;
std::array<osg::Matrixf, 2> mLastViewMatrix;
osg::ref_ptr<osg::StateSet> mViewportStateset;
osg::ref_ptr<osg::Viewport> mViewport;
PostProcessor* mPostProcessor;
};
}

View file

@ -5,9 +5,14 @@
#include <osg/Texture1D>
#include <osg/Texture2D>
#include <osg/Texture2DMultisample>
#include <osg/Texture3D>
#include <osg/Texture2DArray>
#ifdef OSG_HAS_MULTIVIEW
#include <osg/Texture2DMultisampleArray>
#endif
#include <components/settings/settings.hpp>
#include <components/sceneutil/depth.hpp>
#include <components/sceneutil/color.hpp>
@ -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<osg::Texture2D*>(tex)->setTextureSize(w, h);
break;
case GL_TEXTURE_2D_ARRAY:
static_cast<osg::Texture2DArray*>(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<osg::Texture2D*>(tex);
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2d));
}
break;
case GL_TEXTURE_2D_ARRAY:
{
#ifdef OSG_HAS_MULTIVIEW
auto* tex2dArray = static_cast<osg::Texture2DArray*>(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<osg::RenderBuffer> 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<float>(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<osg::RenderBuffer> 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<osg::RenderBuffer> 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<osg::RenderBuffer> 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<osg::RenderBuffer> 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<fx::Technique>(*mVFS, *mRendering.getResourceSystem()->getImageManager(), name, mWidth, mHeight, mUBO, mNormalsSupported);
auto technique = std::make_shared<fx::Technique>(*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;
}
}

View file

@ -55,7 +55,7 @@ namespace MWRender
{
public:
using FBOArray = std::array<osg::ref_ptr<osg::FrameBufferObject>, 5>;
using TextureArray = std::array<osg::ref_ptr<osg::Texture2D>, 5>;
using TextureArray = std::array<osg::ref_ptr<osg::Texture>, 5>;
using TechniqueList = std::vector<std::shared_ptr<fx::Technique>>;
enum TextureIndex
@ -94,7 +94,7 @@ namespace MWRender
osg::ref_ptr<osg::FrameBufferObject> getFbo(FBOIndex index, unsigned int frameId) { return mFbos[frameId][index]; }
osg::ref_ptr<osg::Texture2D> getTexture(TextureIndex index, unsigned int frameId) { return mTextures[frameId][index]; }
osg::ref_ptr<osg::Texture> getTexture(TextureIndex index, unsigned int frameId) { return mTextures[frameId][index]; }
osg::ref_ptr<osg::FrameBufferObject> 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<osg::Texture2D> mMainTemplate;
osg::ref_ptr<osg::Texture> mMainTemplate;
osg::ref_ptr<fx::StateUpdater> mStateUpdater;
osg::ref_ptr<PingPongCull> mPingPongCull;

View file

@ -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)

View file

@ -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)

View file

@ -22,6 +22,7 @@
#include <components/misc/rng.hpp>
#include <components/stereo/stereomanager.hpp>
#include <components/stereo/multiview.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/resource/imagemanager.hpp>
@ -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)

View file

@ -2,10 +2,17 @@
#include <osg/BlendFunc>
#include <osg/Texture2D>
#include <osg/Texture2DArray>
#ifdef OSG_HAS_MULTIVIEW
#include <osg/Texture2DMultisampleArray>
#endif
#include <osgUtil/RenderStage>
#include <components/shader/shadermanager.hpp>
#include <components/stereo/multiview.hpp>
#include <components/stereo/stereomanager.hpp>
namespace MWRender
{
@ -24,8 +31,10 @@ namespace MWRender
mStateSet->setTextureAttributeAndModes(0, dummyTexture);
osg::ref_ptr<osg::Shader> vertex = shaderManager.getShader("blended_depth_postpass_vertex.glsl", {}, osg::Shader::VERTEX);
osg::ref_ptr<osg::Shader> fragment = shaderManager.getShader("blended_depth_postpass_fragment.glsl", {}, osg::Shader::FRAGMENT);
Shader::ShaderManager::DefineMap defines;
Stereo::Manager::instance().shaderStereoDefines(defines);
osg::ref_ptr<osg::Shader> vertex = shaderManager.getShader("blended_depth_postpass_vertex.glsl", defines, osg::Shader::VERTEX);
osg::ref_ptr<osg::Shader> 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");
}
}
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<osg::Texture2DArray*>(tex), layer, 0);
#ifdef OSG_HAS_MULTIVIEW
if (tex->getTextureTarget() == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
return osg::FrameBufferAttachment(static_cast<osg::Texture2DMultisampleArray*>(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));
}
}

View file

@ -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<osg::ref_ptr<osg::FrameBufferObject>, 2> mFbo;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMsaaFbo;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mOpaqueFbo;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveLeftSource;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveRightSource;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveLeftTarget;
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveRightTarget;
private:
osg::ref_ptr<osg::StateSet> mStateSet;
bool mPostPass;
@ -35,4 +42,4 @@ namespace MWRender
}
#endif
#endif

View file

@ -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";

View file

@ -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()));

View file

@ -20,9 +20,11 @@ namespace fx
mData.get<InvProjectionMatrix>() = osg::Matrixf::inverse(matrix);
}
void setViewMatrix(const osg::Matrixf& matrix) { mData.get<ViewMatrix>() = matrix; }
void setInvViewMatrix(const osg::Matrixf& matrix) { mData.get<InvViewMatrix>() = matrix; }
void setViewMatrix(const osg::Matrixf& matrix)
{
mData.get<ViewMatrix>() = matrix;
mData.get<InvViewMatrix>() = osg::Matrixf::inverse(matrix);
}
void setPrevViewMatrix(const osg::Matrixf& matrix) { mData.get<PrevViewMatrix>() = matrix;}
@ -197,4 +199,4 @@ namespace fx
};
}
#endif
#endif

View file

@ -456,7 +456,7 @@ namespace Resource
mConvertAlphaTestToAlphaToCoverage = convert;
}
void SceneManager::setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texturePing, osg::ref_ptr<osg::Texture2D> texturePong)
void SceneManager::setOpaqueDepthTex(osg::ref_ptr<osg::Texture> texturePing, osg::ref_ptr<osg::Texture> texturePong)
{
mOpaqueDepthTex = { texturePing, texturePong };
}

View file

@ -109,7 +109,7 @@ namespace Resource
void setSupportedLightingMethods(const SceneUtil::LightManager::SupportedMethods& supported);
bool isSupportedLightingMethod(SceneUtil::LightingMethod method) const;
void setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texturePing, osg::ref_ptr<osg::Texture2D> texturePong);
void setOpaqueDepthTex(osg::ref_ptr<osg::Texture> texturePing, osg::ref_ptr<osg::Texture> texturePong);
enum class UBOBinding
{
@ -213,7 +213,7 @@ namespace Resource
SceneUtil::LightManager::SupportedMethods mSupportedLightingMethods;
bool mConvertAlphaTestToAlphaToCoverage;
bool mSupportsNormalsRT;
std::array<osg::ref_ptr<osg::Texture2D>, 2> mOpaqueDepthTex;
std::array<osg::ref_ptr<osg::Texture>, 2> mOpaqueDepthTex;
osg::ref_ptr<Resource::SharedStateManager> mSharedStateManager;
mutable std::mutex mSharedStateMutex;

View file

@ -40,7 +40,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<osg::ref_ptr<osg::Texture2D>, 2>& textures, int unit)
void setTexturesAndUnit(const std::array<osg::ref_ptr<osg::Texture>, 2>& textures, int unit)
{
mTextures = textures;
mUnit = unit;
@ -69,7 +69,7 @@ namespace
}
private:
mutable std::array<osg::ref_ptr<osg::Texture2D>, 2> mTextures;
mutable std::array<osg::ref_ptr<osg::Texture>, 2> mTextures;
int mUnit;
};
}
@ -982,7 +982,7 @@ namespace Shader
mConvertAlphaTestToAlphaToCoverage = convert;
}
void ShaderVisitor::setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texturePing, osg::ref_ptr<osg::Texture2D> texturePong)
void ShaderVisitor::setOpaqueDepthTex(osg::ref_ptr<osg::Texture> texturePing, osg::ref_ptr<osg::Texture> texturePong)
{
mOpaqueDepthTex = { texturePing, texturePong };
}

View file

@ -48,7 +48,7 @@ namespace Shader
void setConvertAlphaTestToAlphaToCoverage(bool convert);
void setOpaqueDepthTex(osg::ref_ptr<osg::Texture2D> texturePing, osg::ref_ptr<osg::Texture2D> texturePong);
void setOpaqueDepthTex(osg::ref_ptr<osg::Texture> texturePing, osg::ref_ptr<osg::Texture> texturePong);
void setSupportsNormalsRT(bool supports) { mSupportsNormalsRT = supports; }
@ -122,7 +122,7 @@ namespace Shader
bool adjustGeometry(osg::Geometry& sourceGeometry, const ShaderRequirements& reqs);
osg::ref_ptr<const osg::Program> mProgramTemplate;
std::array<osg::ref_ptr<osg::Texture2D>, 2> mOpaqueDepthTex;
std::array<osg::ref_ptr<osg::Texture>, 2> mOpaqueDepthTex;
};
class ReinstateRemovedStateVisitor : public osg::NodeVisitor

View file

@ -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<MultiviewFramebuffer>(static_cast<int>(eyeRes.x()), static_cast<int>(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];

View file

@ -68,7 +68,6 @@ namespace Stereo
void setCullCallback(osg::ref_ptr<osg::NodeCallback> 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<View, 2> mView;
std::array<osg::Matrix, 2> mViewMatrix;
std::array<osg::Matrix, 2> mViewOffsetMatrix;
std::array<osg::Matrix, 2> mProjectionMatrix;
std::array<osg::Matrix, 2> mProjectionMatrixReverseZ;

View file

@ -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

View file

@ -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;

View file

@ -2,6 +2,8 @@
varying vec2 uv;
#include "openmw_vertex.h.glsl"
void main()
{
gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -18,8 +18,3 @@ vec4 mw_viewToClip(vec4 pos)
{
return projectionMatrix * pos;
}
vec4 mw_viewStereoAdjust(vec4 pos)
{
return pos;
}

View file

@ -3,5 +3,4 @@
vec4 mw_modelToClip(vec4 pos);
vec4 mw_modelToView(vec4 pos);
vec4 mw_viewToClip(vec4 pos);
vec4 mw_viewStereoAdjust(vec4 pos);
vec4 mw_viewToClip(vec4 pos);

View file

@ -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;
}