mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-27 23:37:20 +00:00
[renderer] render scene exclusively to fbo
This commit is contained in:
parent
bff4666b7b
commit
7e9690e531
@ -328,46 +328,37 @@ namespace MWRender
|
|||||||
{
|
{
|
||||||
osg::State* state = renderInfo.getState();
|
osg::State* state = renderInfo.getState();
|
||||||
|
|
||||||
PostProcessor* postProcessor = dynamic_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
|
PostProcessor* postProcessor = static_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
|
||||||
|
|
||||||
state->applyAttribute(mDepth);
|
state->applyAttribute(mDepth);
|
||||||
|
|
||||||
unsigned int frameId = state->getFrameStamp()->getFrameNumber() % 2;
|
unsigned int frameId = state->getFrameStamp()->getFrameNumber() % 2;
|
||||||
|
|
||||||
if (postProcessor && postProcessor->getFbo(PostProcessor::FBO_FirstPerson, frameId))
|
postProcessor->getFbo(PostProcessor::FBO_FirstPerson, frameId)->apply(*state);
|
||||||
|
if (mPassNormals)
|
||||||
{
|
{
|
||||||
postProcessor->getFbo(PostProcessor::FBO_FirstPerson, frameId)->apply(*state);
|
state->get<osg::GLExtensions>()->glColorMaski(1, true, true, true, true);
|
||||||
if (mPassNormals)
|
state->haveAppliedAttribute(osg::StateAttribute::COLORMASK);
|
||||||
{
|
|
||||||
state->get<osg::GLExtensions>()->glColorMaski(1, true, true, true, true);
|
|
||||||
state->haveAppliedAttribute(osg::StateAttribute::COLORMASK);
|
|
||||||
}
|
|
||||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
||||||
// color accumulation pass
|
|
||||||
bin->drawImplementation(renderInfo, previous);
|
|
||||||
|
|
||||||
auto primaryFBO = postProcessor->getPrimaryFbo(frameId);
|
|
||||||
|
|
||||||
if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId))
|
|
||||||
postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state);
|
|
||||||
else
|
|
||||||
primaryFBO->apply(*state);
|
|
||||||
|
|
||||||
// depth accumulation pass
|
|
||||||
osg::ref_ptr<osg::StateSet> restore = bin->getStateSet();
|
|
||||||
bin->setStateSet(mStateSet);
|
|
||||||
bin->drawImplementation(renderInfo, previous);
|
|
||||||
bin->setStateSet(restore);
|
|
||||||
|
|
||||||
if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId))
|
|
||||||
primaryFBO->apply(*state);
|
|
||||||
}
|
}
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
// color accumulation pass
|
||||||
|
bin->drawImplementation(renderInfo, previous);
|
||||||
|
|
||||||
|
auto primaryFBO = postProcessor->getPrimaryFbo(frameId);
|
||||||
|
|
||||||
|
if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId))
|
||||||
|
postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state);
|
||||||
else
|
else
|
||||||
{
|
primaryFBO->apply(*state);
|
||||||
// fallback to standard depth clear when we are not rendering our main scene via an intermediate FBO
|
|
||||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
// depth accumulation pass
|
||||||
bin->drawImplementation(renderInfo, previous);
|
osg::ref_ptr<osg::StateSet> restore = bin->getStateSet();
|
||||||
}
|
bin->setStateSet(mStateSet);
|
||||||
|
bin->drawImplementation(renderInfo, previous);
|
||||||
|
bin->setStateSet(restore);
|
||||||
|
|
||||||
|
if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId))
|
||||||
|
primaryFBO->apply(*state);
|
||||||
|
|
||||||
state->checkGLErrors("after DepthClearCallback::drawImplementation");
|
state->checkGLErrors("after DepthClearCallback::drawImplementation");
|
||||||
}
|
}
|
||||||
|
@ -43,19 +43,16 @@ namespace MWRender
|
|||||||
mMultiviewResolveStateSet->addUniform(new osg::Uniform("lastShader", 0));
|
mMultiviewResolveStateSet->addUniform(new osg::Uniform("lastShader", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PingPongCanvas::setCurrentFrameData(size_t frameId, fx::DispatchArray&& data)
|
void PingPongCanvas::setPasses(fx::DispatchArray&& passes)
|
||||||
{
|
{
|
||||||
mBufferData[frameId].data = std::move(data);
|
mPasses = std::move(passes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PingPongCanvas::setMask(size_t frameId, bool underwater, bool exterior)
|
void PingPongCanvas::setMask(bool underwater, bool exterior)
|
||||||
{
|
{
|
||||||
mBufferData[frameId].mask = 0;
|
mMask = 0;
|
||||||
|
mMask |= underwater ? fx::Technique::Flag_Disable_Underwater : fx::Technique::Flag_Disable_Abovewater;
|
||||||
mBufferData[frameId].mask
|
mMask |= exterior ? fx::Technique::Flag_Disable_Exteriors : fx::Technique::Flag_Disable_Interiors;
|
||||||
|= underwater ? fx::Technique::Flag_Disable_Underwater : fx::Technique::Flag_Disable_Abovewater;
|
|
||||||
mBufferData[frameId].mask
|
|
||||||
|= exterior ? fx::Technique::Flag_Disable_Exteriors : fx::Technique::Flag_Disable_Interiors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PingPongCanvas::drawGeometry(osg::RenderInfo& renderInfo) const
|
void PingPongCanvas::drawGeometry(osg::RenderInfo& renderInfo) const
|
||||||
@ -77,19 +74,15 @@ namespace MWRender
|
|||||||
|
|
||||||
size_t frameId = state.getFrameStamp()->getFrameNumber() % 2;
|
size_t frameId = state.getFrameStamp()->getFrameNumber() % 2;
|
||||||
|
|
||||||
auto& bufferData = mBufferData[frameId];
|
|
||||||
|
|
||||||
const auto& data = bufferData.data;
|
|
||||||
|
|
||||||
std::vector<size_t> filtered;
|
std::vector<size_t> filtered;
|
||||||
|
|
||||||
filtered.reserve(data.size());
|
filtered.reserve(mPasses.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < data.size(); ++i)
|
for (size_t i = 0; i < mPasses.size(); ++i)
|
||||||
{
|
{
|
||||||
const auto& node = data[i];
|
const auto& node = mPasses[i];
|
||||||
|
|
||||||
if (bufferData.mask & node.mFlags)
|
if (mMask & node.mFlags)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
filtered.push_back(i);
|
filtered.push_back(i);
|
||||||
@ -97,7 +90,7 @@ namespace MWRender
|
|||||||
|
|
||||||
auto* resolveViewport = state.getCurrentViewport();
|
auto* resolveViewport = state.getCurrentViewport();
|
||||||
|
|
||||||
if (filtered.empty() || !bufferData.postprocessing)
|
if (filtered.empty() || !mPostprocessing)
|
||||||
{
|
{
|
||||||
state.pushStateSet(mFallbackStateSet);
|
state.pushStateSet(mFallbackStateSet);
|
||||||
state.apply();
|
state.apply();
|
||||||
@ -108,7 +101,7 @@ namespace MWRender
|
|||||||
state.apply();
|
state.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
state.applyTextureAttribute(0, bufferData.sceneTex);
|
state.applyTextureAttribute(0, mTextureScene);
|
||||||
resolveViewport->apply(state);
|
resolveViewport->apply(state);
|
||||||
|
|
||||||
drawGeometry(renderInfo);
|
drawGeometry(renderInfo);
|
||||||
@ -124,13 +117,12 @@ namespace MWRender
|
|||||||
|
|
||||||
const unsigned int handle = mFbos[0] ? mFbos[0]->getHandle(state.getContextID()) : 0;
|
const unsigned int handle = mFbos[0] ? mFbos[0]->getHandle(state.getContextID()) : 0;
|
||||||
|
|
||||||
if (handle == 0 || bufferData.dirty)
|
if (handle == 0 || mDirty)
|
||||||
{
|
{
|
||||||
for (auto& fbo : mFbos)
|
for (auto& fbo : mFbos)
|
||||||
{
|
{
|
||||||
fbo = new osg::FrameBufferObject;
|
fbo = new osg::FrameBufferObject;
|
||||||
attachCloneOfTemplate(
|
attachCloneOfTemplate(fbo, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, mTextureScene);
|
||||||
fbo, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR);
|
|
||||||
fbo->apply(state);
|
fbo->apply(state);
|
||||||
glClearColor(0.5, 0.5, 0.5, 1);
|
glClearColor(0.5, 0.5, 0.5, 1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
@ -140,7 +132,7 @@ namespace MWRender
|
|||||||
{
|
{
|
||||||
mMultiviewResolveFramebuffer = new osg::FrameBufferObject();
|
mMultiviewResolveFramebuffer = new osg::FrameBufferObject();
|
||||||
attachCloneOfTemplate(mMultiviewResolveFramebuffer,
|
attachCloneOfTemplate(mMultiviewResolveFramebuffer,
|
||||||
osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR);
|
osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, mTextureScene);
|
||||||
mMultiviewResolveFramebuffer->apply(state);
|
mMultiviewResolveFramebuffer->apply(state);
|
||||||
glClearColor(0.5, 0.5, 0.5, 1);
|
glClearColor(0.5, 0.5, 0.5, 1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
@ -150,15 +142,15 @@ namespace MWRender
|
|||||||
.getTexture());
|
.getTexture());
|
||||||
}
|
}
|
||||||
|
|
||||||
mLuminanceCalculator.dirty(bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight());
|
mLuminanceCalculator.dirty(mTextureScene->getTextureWidth(), mTextureScene->getTextureHeight());
|
||||||
|
|
||||||
if (Stereo::getStereo())
|
if (Stereo::getStereo())
|
||||||
mRenderViewport = new osg::Viewport(
|
mRenderViewport
|
||||||
0, 0, bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight());
|
= new osg::Viewport(0, 0, mTextureScene->getTextureWidth(), mTextureScene->getTextureHeight());
|
||||||
else
|
else
|
||||||
mRenderViewport = nullptr;
|
mRenderViewport = nullptr;
|
||||||
|
|
||||||
bufferData.dirty = false;
|
mDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::array<std::array<int, 2>, 3> buffers
|
constexpr std::array<std::array<int, 2>, 3> buffers
|
||||||
@ -166,7 +158,7 @@ namespace MWRender
|
|||||||
{ GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT2_EXT },
|
{ GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT2_EXT },
|
||||||
{ GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT } } };
|
{ GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT } } };
|
||||||
|
|
||||||
(bufferData.hdr) ? mLuminanceCalculator.enable() : mLuminanceCalculator.disable();
|
(mAvgLum) ? mLuminanceCalculator.enable() : mLuminanceCalculator.disable();
|
||||||
|
|
||||||
// A histogram based approach is superior way to calculate scene luminance. Using mipmaps is more broadly
|
// A histogram based approach is superior way to calculate scene luminance. Using mipmaps is more broadly
|
||||||
// supported, so that's what we use for now.
|
// supported, so that's what we use for now.
|
||||||
@ -181,8 +173,7 @@ namespace MWRender
|
|||||||
|
|
||||||
const unsigned int cid = state.getContextID();
|
const unsigned int cid = state.getContextID();
|
||||||
|
|
||||||
const osg::ref_ptr<osg::FrameBufferObject>& destinationFbo
|
const osg::ref_ptr<osg::FrameBufferObject>& destinationFbo = mDestinationFBO ? mDestinationFBO : nullptr;
|
||||||
= bufferData.destination ? bufferData.destination : nullptr;
|
|
||||||
unsigned int destinationHandle = destinationFbo ? destinationFbo->getHandle(cid) : 0;
|
unsigned int destinationHandle = destinationFbo ? destinationFbo->getHandle(cid) : 0;
|
||||||
|
|
||||||
auto bindDestinationFbo = [&]() {
|
auto bindDestinationFbo = [&]() {
|
||||||
@ -206,17 +197,16 @@ namespace MWRender
|
|||||||
|
|
||||||
for (const size_t& index : filtered)
|
for (const size_t& index : filtered)
|
||||||
{
|
{
|
||||||
const auto& node = data[index];
|
const auto& node = mPasses[index];
|
||||||
|
|
||||||
node.mRootStateSet->setTextureAttribute(PostProcessor::Unit_Depth, bufferData.depthTex);
|
node.mRootStateSet->setTextureAttribute(PostProcessor::Unit_Depth, mTextureDepth);
|
||||||
|
|
||||||
if (bufferData.hdr)
|
if (mAvgLum)
|
||||||
node.mRootStateSet->setTextureAttribute(
|
node.mRootStateSet->setTextureAttribute(
|
||||||
PostProcessor::TextureUnits::Unit_EyeAdaptation, mLuminanceCalculator.getLuminanceTexture(frameId));
|
PostProcessor::TextureUnits::Unit_EyeAdaptation, mLuminanceCalculator.getLuminanceTexture(frameId));
|
||||||
|
|
||||||
if (bufferData.normalsTex)
|
if (mTextureNormals)
|
||||||
node.mRootStateSet->setTextureAttribute(
|
node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_Normals, mTextureNormals);
|
||||||
PostProcessor::TextureUnits::Unit_Normals, bufferData.normalsTex);
|
|
||||||
|
|
||||||
state.pushStateSet(node.mRootStateSet);
|
state.pushStateSet(node.mRootStateSet);
|
||||||
state.apply();
|
state.apply();
|
||||||
@ -231,7 +221,7 @@ namespace MWRender
|
|||||||
|
|
||||||
// VR-TODO: This won't actually work for tex2darrays
|
// VR-TODO: This won't actually work for tex2darrays
|
||||||
if (lastShader == 0)
|
if (lastShader == 0)
|
||||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, bufferData.sceneTex);
|
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, mTextureScene);
|
||||||
else
|
else
|
||||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader,
|
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader,
|
||||||
(osg::Texture*)mFbos[lastShader - GL_COLOR_ATTACHMENT0_EXT]
|
(osg::Texture*)mFbos[lastShader - GL_COLOR_ATTACHMENT0_EXT]
|
||||||
@ -239,7 +229,7 @@ namespace MWRender
|
|||||||
.getTexture());
|
.getTexture());
|
||||||
|
|
||||||
if (lastDraw == 0)
|
if (lastDraw == 0)
|
||||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, bufferData.sceneTex);
|
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, mTextureScene);
|
||||||
else
|
else
|
||||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass,
|
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass,
|
||||||
(osg::Texture*)mFbos[lastDraw - GL_COLOR_ATTACHMENT0_EXT]
|
(osg::Texture*)mFbos[lastDraw - GL_COLOR_ATTACHMENT0_EXT]
|
||||||
@ -260,7 +250,6 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
|
|
||||||
lastApplied = pass.mRenderTarget->getHandle(state.getContextID());
|
lastApplied = pass.mRenderTarget->getHandle(state.getContextID());
|
||||||
;
|
|
||||||
}
|
}
|
||||||
else if (pass.mResolve && index == filtered.back())
|
else if (pass.mResolve && index == filtered.back())
|
||||||
{
|
{
|
||||||
|
@ -24,76 +24,52 @@ namespace MWRender
|
|||||||
public:
|
public:
|
||||||
PingPongCanvas(Shader::ShaderManager& shaderManager);
|
PingPongCanvas(Shader::ShaderManager& shaderManager);
|
||||||
|
|
||||||
void drawImplementation(osg::RenderInfo& renderInfo) const override;
|
|
||||||
|
|
||||||
void dirty(size_t frameId) { mBufferData[frameId].dirty = true; }
|
|
||||||
|
|
||||||
const fx::DispatchArray& getCurrentFrameData(size_t frame) { return mBufferData[frame % 2].data; }
|
|
||||||
|
|
||||||
// Sets current frame pass data and stores copy of dispatch array to apply to next frame data
|
|
||||||
void setCurrentFrameData(size_t frameId, fx::DispatchArray&& data);
|
|
||||||
|
|
||||||
void setMask(size_t frameId, bool underwater, bool exterior);
|
|
||||||
|
|
||||||
void setSceneTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex) { mBufferData[frameId].sceneTex = 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::Texture> tex)
|
|
||||||
{
|
|
||||||
mBufferData[frameId].normalsTex = tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setHDR(size_t frameId, bool hdr) { mBufferData[frameId].hdr = hdr; }
|
|
||||||
|
|
||||||
void setPostProcessing(size_t frameId, bool postprocessing)
|
|
||||||
{
|
|
||||||
mBufferData[frameId].postprocessing = postprocessing;
|
|
||||||
}
|
|
||||||
|
|
||||||
const osg::ref_ptr<osg::Texture>& getSceneTexture(size_t frameId) const
|
|
||||||
{
|
|
||||||
return mBufferData[frameId].sceneTex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawGeometry(osg::RenderInfo& renderInfo) const;
|
void drawGeometry(osg::RenderInfo& renderInfo) const;
|
||||||
|
|
||||||
private:
|
void drawImplementation(osg::RenderInfo& renderInfo) const override;
|
||||||
void copyNewFrameData(size_t frameId) const;
|
|
||||||
|
|
||||||
mutable LuminanceCalculator mLuminanceCalculator;
|
void dirty() { mDirty = true; }
|
||||||
|
|
||||||
|
const fx::DispatchArray& getPasses() { return mPasses; }
|
||||||
|
|
||||||
|
void setPasses(fx::DispatchArray&& passes);
|
||||||
|
|
||||||
|
void setMask(bool underwater, bool exterior);
|
||||||
|
|
||||||
|
void setTextureScene(osg::ref_ptr<osg::Texture> tex) { mTextureScene = tex; }
|
||||||
|
|
||||||
|
void setTextureDepth(osg::ref_ptr<osg::Texture> tex) { mTextureDepth = tex; }
|
||||||
|
|
||||||
|
void setTextureNormals(osg::ref_ptr<osg::Texture> tex) { mTextureNormals = tex; }
|
||||||
|
|
||||||
|
void setCalculateAvgLum(bool enabled) { mAvgLum = enabled; }
|
||||||
|
|
||||||
|
void setPostProcessing(bool enabled) { mPostprocessing = enabled; }
|
||||||
|
|
||||||
|
const osg::ref_ptr<osg::Texture>& getSceneTexture(size_t frameId) const { return mTextureScene; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mAvgLum = false;
|
||||||
|
bool mPostprocessing = false;
|
||||||
|
|
||||||
|
fx::DispatchArray mPasses;
|
||||||
|
fx::FlagsType mMask;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Program> mFallbackProgram;
|
osg::ref_ptr<osg::Program> mFallbackProgram;
|
||||||
osg::ref_ptr<osg::Program> mMultiviewResolveProgram;
|
osg::ref_ptr<osg::Program> mMultiviewResolveProgram;
|
||||||
osg::ref_ptr<osg::StateSet> mFallbackStateSet;
|
osg::ref_ptr<osg::StateSet> mFallbackStateSet;
|
||||||
osg::ref_ptr<osg::StateSet> mMultiviewResolveStateSet;
|
osg::ref_ptr<osg::StateSet> mMultiviewResolveStateSet;
|
||||||
mutable osg::ref_ptr<osg::FrameBufferObject> mMultiviewResolveFramebuffer;
|
|
||||||
|
|
||||||
struct BufferData
|
osg::ref_ptr<osg::Texture> mTextureScene;
|
||||||
{
|
osg::ref_ptr<osg::Texture> mTextureDepth;
|
||||||
bool dirty = false;
|
osg::ref_ptr<osg::Texture> mTextureNormals;
|
||||||
bool hdr = false;
|
|
||||||
bool postprocessing = true;
|
|
||||||
|
|
||||||
fx::DispatchArray data;
|
mutable bool mDirty = false;
|
||||||
fx::FlagsType mask;
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::FrameBufferObject> destination;
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture> sceneTex;
|
|
||||||
osg::ref_ptr<osg::Texture> depthTex;
|
|
||||||
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 osg::ref_ptr<osg::Viewport> mRenderViewport;
|
||||||
|
mutable osg::ref_ptr<osg::FrameBufferObject> mMultiviewResolveFramebuffer;
|
||||||
|
mutable osg::ref_ptr<osg::FrameBufferObject> mDestinationFBO;
|
||||||
|
mutable std::array<osg::ref_ptr<osg::FrameBufferObject>, 3> mFbos;
|
||||||
|
mutable LuminanceCalculator mLuminanceCalculator;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ namespace MWRender
|
|||||||
if (Stereo::getStereo())
|
if (Stereo::getStereo())
|
||||||
{
|
{
|
||||||
mViewportStateset = new osg::StateSet();
|
mViewportStateset = new osg::StateSet();
|
||||||
mViewport = new osg::Viewport(0, 0, pp->renderWidth(), pp->renderHeight());
|
mViewport = new osg::Viewport;
|
||||||
mViewportStateset->setAttribute(mViewport);
|
mViewportStateset->setAttribute(mViewport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,41 +37,31 @@ namespace MWRender
|
|||||||
size_t frame = cv->getTraversalNumber();
|
size_t frame = cv->getTraversalNumber();
|
||||||
size_t frameId = frame % 2;
|
size_t frameId = frame % 2;
|
||||||
|
|
||||||
MWRender::PostProcessor* postProcessor
|
|
||||||
= dynamic_cast<MWRender::PostProcessor*>(cv->getCurrentCamera()->getUserData());
|
|
||||||
if (!postProcessor)
|
|
||||||
throw std::runtime_error("PingPongCull: failed to get a PostProcessor!");
|
|
||||||
|
|
||||||
if (Stereo::getStereo())
|
if (Stereo::getStereo())
|
||||||
{
|
{
|
||||||
auto& sm = Stereo::Manager::instance();
|
auto& sm = Stereo::Manager::instance();
|
||||||
auto view = sm.getEye(cv);
|
auto view = sm.getEye(cv);
|
||||||
int index = view == Stereo::Eye::Right ? 1 : 0;
|
int index = view == Stereo::Eye::Right ? 1 : 0;
|
||||||
auto projectionMatrix = sm.computeEyeProjection(index, true);
|
auto projectionMatrix = sm.computeEyeProjection(index, true);
|
||||||
postProcessor->getStateUpdater()->setProjectionMatrix(projectionMatrix);
|
mPostProcessor->getStateUpdater()->setProjectionMatrix(projectionMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
postProcessor->getStateUpdater()->setViewMatrix(cv->getCurrentCamera()->getViewMatrix());
|
mPostProcessor->getStateUpdater()->setViewMatrix(cv->getCurrentCamera()->getViewMatrix());
|
||||||
postProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix[0]);
|
mPostProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix[0]);
|
||||||
mLastViewMatrix[0] = cv->getCurrentCamera()->getViewMatrix();
|
mLastViewMatrix[0] = cv->getCurrentCamera()->getViewMatrix();
|
||||||
|
|
||||||
postProcessor->getStateUpdater()->setEyePos(cv->getEyePoint());
|
mPostProcessor->getStateUpdater()->setEyePos(cv->getEyePoint());
|
||||||
postProcessor->getStateUpdater()->setEyeVec(cv->getLookVectorLocal());
|
mPostProcessor->getStateUpdater()->setEyeVec(cv->getLookVectorLocal());
|
||||||
|
|
||||||
if (!postProcessor->getFbo(PostProcessor::FBO_Primary, frameId))
|
if (!mPostProcessor->getFbo(PostProcessor::FBO_Multisample, frameId))
|
||||||
{
|
{
|
||||||
renderStage->setMultisampleResolveFramebufferObject(nullptr);
|
renderStage->setFrameBufferObject(mPostProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
||||||
renderStage->setFrameBufferObject(nullptr);
|
|
||||||
}
|
|
||||||
else if (!postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId))
|
|
||||||
{
|
|
||||||
renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
renderStage->setMultisampleResolveFramebufferObject(
|
renderStage->setMultisampleResolveFramebufferObject(
|
||||||
postProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
mPostProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
||||||
renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId));
|
renderStage->setFrameBufferObject(mPostProcessor->getFbo(PostProcessor::FBO_Multisample, frameId));
|
||||||
|
|
||||||
// The MultiView patch has a bug where it does not update resolve layers if the resolve framebuffer is
|
// The MultiView patch has a bug where it does not update resolve layers if the resolve framebuffer is
|
||||||
// changed. So we do blit manually in this case
|
// changed. So we do blit manually in this case
|
||||||
|
@ -110,30 +110,45 @@ namespace MWRender
|
|||||||
PostProcessor::PostProcessor(
|
PostProcessor::PostProcessor(
|
||||||
RenderingManager& rendering, osgViewer::Viewer* viewer, osg::Group* rootNode, const VFS::Manager* vfs)
|
RenderingManager& rendering, osgViewer::Viewer* viewer, osg::Group* rootNode, const VFS::Manager* vfs)
|
||||||
: osg::Group()
|
: osg::Group()
|
||||||
, mEnableLiveReload(false)
|
|
||||||
, mRootNode(rootNode)
|
, mRootNode(rootNode)
|
||||||
, mSamples(Settings::video().mAntialiasing)
|
, mHUDCamera(new osg::Camera)
|
||||||
, mDirty(false)
|
|
||||||
, mDirtyFrameId(0)
|
|
||||||
, mRendering(rendering)
|
, mRendering(rendering)
|
||||||
, mViewer(viewer)
|
, mViewer(viewer)
|
||||||
, mVFS(vfs)
|
, mVFS(vfs)
|
||||||
, mTriggerShaderReload(false)
|
|
||||||
, mReload(false)
|
|
||||||
, mEnabled(false)
|
|
||||||
, mUsePostProcessing(Settings::postProcessing().mEnabled)
|
, mUsePostProcessing(Settings::postProcessing().mEnabled)
|
||||||
, mDisableDepthPasses(false)
|
, mSamples(Settings::video().mAntialiasing)
|
||||||
, mLastFrameNumber(0)
|
, mPingPongCull(new PingPongCull(this))
|
||||||
, mLastSimulationTime(0.f)
|
, mCanvases({ new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()),
|
||||||
, mExteriorFlag(false)
|
new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()) })
|
||||||
, mUnderwater(false)
|
|
||||||
, mHDR(false)
|
|
||||||
, mNormals(false)
|
|
||||||
, mPrevNormals(false)
|
|
||||||
, mNormalsSupported(false)
|
|
||||||
, mPassLights(false)
|
|
||||||
, mPrevPassLights(false)
|
|
||||||
{
|
{
|
||||||
|
mHUDCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
||||||
|
mHUDCamera->setRenderOrder(osg::Camera::POST_RENDER);
|
||||||
|
mHUDCamera->setClearColor(osg::Vec4(0.45, 0.45, 0.14, 1.0));
|
||||||
|
mHUDCamera->setClearMask(0);
|
||||||
|
mHUDCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1));
|
||||||
|
mHUDCamera->setAllowEventFocus(false);
|
||||||
|
mHUDCamera->setViewport(0, 0, mWidth, mHeight);
|
||||||
|
mHUDCamera->setNodeMask(Mask_RenderToTexture);
|
||||||
|
mHUDCamera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||||
|
mHUDCamera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||||
|
mHUDCamera->addChild(mCanvases[0]);
|
||||||
|
mHUDCamera->addChild(mCanvases[1]);
|
||||||
|
mHUDCamera->setCullCallback(new HUDCullCallback);
|
||||||
|
mViewer->getCamera()->addCullCallback(mPingPongCull);
|
||||||
|
|
||||||
|
if (Settings::shaders().mSoftParticles || Settings::postProcessing().mTransparentPostpass)
|
||||||
|
{
|
||||||
|
mTransparentDepthPostPass
|
||||||
|
= new TransparentDepthBinCallback(mRendering.getResourceSystem()->getSceneManager()->getShaderManager(),
|
||||||
|
Settings::postProcessing().mTransparentPostpass);
|
||||||
|
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass);
|
||||||
|
}
|
||||||
|
|
||||||
|
createObjectsForFrame(0);
|
||||||
|
createObjectsForFrame(1);
|
||||||
|
|
||||||
|
populateTechniqueFiles();
|
||||||
|
|
||||||
osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext();
|
osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext();
|
||||||
osg::GLExtensions* ext = gc->getState()->get<osg::GLExtensions>();
|
osg::GLExtensions* ext = gc->getState()->get<osg::GLExtensions>();
|
||||||
|
|
||||||
@ -169,11 +184,18 @@ namespace MWRender
|
|||||||
mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
|
mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
|
||||||
mStateUpdater = new fx::StateUpdater(mUBO);
|
mStateUpdater = new fx::StateUpdater(mUBO);
|
||||||
|
|
||||||
if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles
|
addChild(mHUDCamera);
|
||||||
&& !mUsePostProcessing)
|
addChild(mRootNode);
|
||||||
return;
|
|
||||||
|
|
||||||
enable(mUsePostProcessing);
|
mViewer->setSceneData(this);
|
||||||
|
mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
||||||
|
mViewer->getCamera()->getGraphicsContext()->setResizedCallback(new ResizedCallback(this));
|
||||||
|
mViewer->getCamera()->setUserData(this);
|
||||||
|
|
||||||
|
setCullCallback(mStateUpdater);
|
||||||
|
|
||||||
|
if (mUsePostProcessing)
|
||||||
|
enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
PostProcessor::~PostProcessor()
|
PostProcessor::~PostProcessor()
|
||||||
@ -202,7 +224,6 @@ namespace MWRender
|
|||||||
|
|
||||||
size_t frameId = frame() % 2;
|
size_t frameId = frame() % 2;
|
||||||
|
|
||||||
createTexturesAndCamera(frameId);
|
|
||||||
createObjectsForFrame(frameId);
|
createObjectsForFrame(frameId);
|
||||||
|
|
||||||
mRendering.updateProjectionMatrix();
|
mRendering.updateProjectionMatrix();
|
||||||
@ -210,8 +231,6 @@ namespace MWRender
|
|||||||
|
|
||||||
dirtyTechniques();
|
dirtyTechniques();
|
||||||
|
|
||||||
mPingPongCanvas->dirty(frameId);
|
|
||||||
|
|
||||||
mDirty = true;
|
mDirty = true;
|
||||||
mDirtyFrameId = !frameId;
|
mDirtyFrameId = !frameId;
|
||||||
}
|
}
|
||||||
@ -230,77 +249,20 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessor::enable(bool usePostProcessing)
|
void PostProcessor::enable()
|
||||||
{
|
{
|
||||||
mReload = true;
|
mReload = true;
|
||||||
mEnabled = true;
|
mUsePostProcessing = true;
|
||||||
const bool postPass = Settings::postProcessing().mTransparentPostpass;
|
|
||||||
mUsePostProcessing = usePostProcessing;
|
|
||||||
|
|
||||||
mDisableDepthPasses = !Settings::shaders().mSoftParticles && !postPass;
|
|
||||||
|
|
||||||
#ifdef ANDROID
|
|
||||||
mDisableDepthPasses = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!mDisableDepthPasses)
|
|
||||||
{
|
|
||||||
mTransparentDepthPostPass = new TransparentDepthBinCallback(
|
|
||||||
mRendering.getResourceSystem()->getSceneManager()->getShaderManager(), postPass);
|
|
||||||
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mUsePostProcessing && mTechniqueFileMap.empty())
|
|
||||||
{
|
|
||||||
populateTechniqueFiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
createTexturesAndCamera(frame() % 2);
|
|
||||||
|
|
||||||
removeChild(mHUDCamera);
|
|
||||||
removeChild(mRootNode);
|
|
||||||
|
|
||||||
addChild(mHUDCamera);
|
|
||||||
addChild(mRootNode);
|
|
||||||
|
|
||||||
mViewer->setSceneData(this);
|
|
||||||
mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
|
||||||
mViewer->getCamera()->getGraphicsContext()->setResizedCallback(new ResizedCallback(this));
|
|
||||||
mViewer->getCamera()->setUserData(this);
|
|
||||||
|
|
||||||
setCullCallback(mStateUpdater);
|
|
||||||
mHUDCamera->setCullCallback(new HUDCullCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessor::disable()
|
void PostProcessor::disable()
|
||||||
{
|
{
|
||||||
if (!Settings::shaders().mSoftParticles)
|
|
||||||
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(nullptr);
|
|
||||||
|
|
||||||
if (!SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles)
|
|
||||||
{
|
|
||||||
removeChild(mHUDCamera);
|
|
||||||
setCullCallback(nullptr);
|
|
||||||
|
|
||||||
mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER);
|
|
||||||
mViewer->getCamera()->getGraphicsContext()->setResizedCallback(nullptr);
|
|
||||||
mViewer->getCamera()->setUserData(nullptr);
|
|
||||||
|
|
||||||
mEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mUsePostProcessing = false;
|
mUsePostProcessing = false;
|
||||||
mRendering.getSkyManager()->setSunglare(true);
|
mRendering.getSkyManager()->setSunglare(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessor::traverse(osg::NodeVisitor& nv)
|
void PostProcessor::traverse(osg::NodeVisitor& nv)
|
||||||
{
|
{
|
||||||
if (!mEnabled)
|
|
||||||
{
|
|
||||||
osg::Group::traverse(nv);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t frameId = nv.getTraversalNumber() % 2;
|
size_t frameId = nv.getTraversalNumber() % 2;
|
||||||
|
|
||||||
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
||||||
@ -313,26 +275,23 @@ namespace MWRender
|
|||||||
|
|
||||||
void PostProcessor::cull(size_t frameId, osgUtil::CullVisitor* cv)
|
void PostProcessor::cull(size_t frameId, osgUtil::CullVisitor* cv)
|
||||||
{
|
{
|
||||||
const auto& fbo = getFbo(FBO_Intercept, frameId);
|
if (const auto& fbo = getFbo(FBO_Intercept, frameId))
|
||||||
if (fbo)
|
|
||||||
{
|
{
|
||||||
osgUtil::RenderStage* rs = cv->getRenderStage();
|
osgUtil::RenderStage* rs = cv->getRenderStage();
|
||||||
if (rs && rs->getMultisampleResolveFramebufferObject())
|
if (rs && rs->getMultisampleResolveFramebufferObject())
|
||||||
rs->setMultisampleResolveFramebufferObject(fbo);
|
rs->setMultisampleResolveFramebufferObject(fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
mPingPongCanvas->setPostProcessing(frameId, mUsePostProcessing);
|
mCanvases[frameId]->setPostProcessing(mUsePostProcessing);
|
||||||
mPingPongCanvas->setNormalsTexture(frameId, mNormals ? getTexture(Tex_Normal, frameId) : nullptr);
|
mCanvases[frameId]->setTextureNormals(mNormals ? getTexture(Tex_Normal, frameId) : nullptr);
|
||||||
mPingPongCanvas->setMask(frameId, mUnderwater, mExteriorFlag);
|
mCanvases[frameId]->setMask(mUnderwater, mExteriorFlag);
|
||||||
mPingPongCanvas->setHDR(frameId, getHDR());
|
mCanvases[frameId]->setCalculateAvgLum(mHDR);
|
||||||
|
|
||||||
mPingPongCanvas->setSceneTexture(frameId, getTexture(Tex_Scene, frameId));
|
mCanvases[frameId]->setTextureScene(getTexture(Tex_Scene, frameId));
|
||||||
if (mDisableDepthPasses)
|
if (mTransparentDepthPostPass)
|
||||||
mPingPongCanvas->setDepthTexture(frameId, getTexture(Tex_Depth, frameId));
|
mCanvases[frameId]->setTextureDepth(getTexture(Tex_OpaqueDepth, frameId));
|
||||||
else
|
else
|
||||||
mPingPongCanvas->setDepthTexture(frameId, getTexture(Tex_OpaqueDepth, frameId));
|
mCanvases[frameId]->setTextureDepth(getTexture(Tex_Depth, frameId));
|
||||||
|
|
||||||
mPingPongCanvas->setLDRSceneTexture(frameId, getTexture(Tex_Scene_LDR, frameId));
|
|
||||||
|
|
||||||
if (mTransparentDepthPostPass)
|
if (mTransparentDepthPostPass)
|
||||||
{
|
{
|
||||||
@ -355,7 +314,7 @@ namespace MWRender
|
|||||||
mStateUpdater->setDeltaSimulationTime(static_cast<float>(stamp->getSimulationTime() - mLastSimulationTime));
|
mStateUpdater->setDeltaSimulationTime(static_cast<float>(stamp->getSimulationTime() - mLastSimulationTime));
|
||||||
mLastSimulationTime = stamp->getSimulationTime();
|
mLastSimulationTime = stamp->getSimulationTime();
|
||||||
|
|
||||||
for (const auto& dispatchNode : mPingPongCanvas->getCurrentFrameData(frame))
|
for (const auto& dispatchNode : mCanvases[frameId]->getPasses())
|
||||||
{
|
{
|
||||||
for (auto& uniform : dispatchNode.mHandle->getUniformMap())
|
for (auto& uniform : dispatchNode.mHandle->getUniformMap())
|
||||||
{
|
{
|
||||||
@ -421,13 +380,15 @@ namespace MWRender
|
|||||||
|
|
||||||
reloadIfRequired();
|
reloadIfRequired();
|
||||||
|
|
||||||
|
mCanvases[frameId]->setNodeMask(~0u);
|
||||||
|
mCanvases[!frameId]->setNodeMask(0);
|
||||||
|
|
||||||
if (mDirty && mDirtyFrameId == frameId)
|
if (mDirty && mDirtyFrameId == frameId)
|
||||||
{
|
{
|
||||||
createTexturesAndCamera(frameId);
|
|
||||||
createObjectsForFrame(frameId);
|
createObjectsForFrame(frameId);
|
||||||
mDirty = false;
|
|
||||||
|
|
||||||
mPingPongCanvas->setCurrentFrameData(frameId, fx::DispatchArray(mTemplateData));
|
mDirty = false;
|
||||||
|
mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mNormalsSupported && mNormals != mPrevNormals) || (mPassLights != mPrevPassLights))
|
if ((mNormalsSupported && mNormals != mPrevNormals) || (mPassLights != mPrevPassLights))
|
||||||
@ -448,7 +409,6 @@ namespace MWRender
|
|||||||
|
|
||||||
mViewer->startThreading();
|
mViewer->startThreading();
|
||||||
|
|
||||||
createTexturesAndCamera(frameId);
|
|
||||||
createObjectsForFrame(frameId);
|
createObjectsForFrame(frameId);
|
||||||
|
|
||||||
mDirty = true;
|
mDirty = true;
|
||||||
@ -458,20 +418,56 @@ namespace MWRender
|
|||||||
|
|
||||||
void PostProcessor::createObjectsForFrame(size_t frameId)
|
void PostProcessor::createObjectsForFrame(size_t frameId)
|
||||||
{
|
{
|
||||||
auto& fbos = mFbos[frameId];
|
|
||||||
auto& textures = mTextures[frameId];
|
auto& textures = mTextures[frameId];
|
||||||
auto width = renderWidth();
|
|
||||||
auto height = renderHeight();
|
|
||||||
|
|
||||||
for (auto& tex : textures)
|
int width = renderWidth();
|
||||||
|
int height = renderHeight();
|
||||||
|
|
||||||
|
for (osg::ref_ptr<osg::Texture>& texture : textures)
|
||||||
{
|
{
|
||||||
if (!tex)
|
if (!texture)
|
||||||
continue;
|
{
|
||||||
|
if (Stereo::getMultiview())
|
||||||
Stereo::setMultiviewCompatibleTextureSize(tex, width, height);
|
texture = new osg::Texture2DArray;
|
||||||
tex->dirtyTextureObject();
|
else
|
||||||
|
texture = new osg::Texture2D;
|
||||||
|
}
|
||||||
|
Stereo::setMultiviewCompatibleTextureSize(texture, width, height);
|
||||||
|
texture->setSourceFormat(GL_RGBA);
|
||||||
|
texture->setSourceType(GL_UNSIGNED_BYTE);
|
||||||
|
texture->setInternalFormat(GL_RGBA);
|
||||||
|
texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR);
|
||||||
|
texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR);
|
||||||
|
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||||
|
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
||||||
|
texture->setResizeNonPowerOfTwoHint(false);
|
||||||
|
Stereo::setMultiviewCompatibleTextureSize(texture, width, height);
|
||||||
|
texture->dirtyTextureObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textures[Tex_Normal]->setSourceFormat(GL_RGB);
|
||||||
|
textures[Tex_Normal]->setInternalFormat(GL_RGB);
|
||||||
|
|
||||||
|
auto setupDepth = [](osg::Texture* tex) {
|
||||||
|
tex->setSourceFormat(GL_DEPTH_STENCIL_EXT);
|
||||||
|
tex->setSourceType(SceneUtil::AutoDepth::depthSourceType());
|
||||||
|
tex->setInternalFormat(SceneUtil::AutoDepth::depthInternalFormat());
|
||||||
|
};
|
||||||
|
|
||||||
|
setupDepth(textures[Tex_Depth]);
|
||||||
|
|
||||||
|
if (!mTransparentDepthPostPass)
|
||||||
|
{
|
||||||
|
textures[Tex_OpaqueDepth] = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setupDepth(textures[Tex_OpaqueDepth]);
|
||||||
|
textures[Tex_OpaqueDepth]->setName("opaqueTexMap");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& fbos = mFbos[frameId];
|
||||||
|
|
||||||
fbos[FBO_Primary] = new osg::FrameBufferObject;
|
fbos[FBO_Primary] = new osg::FrameBufferObject;
|
||||||
fbos[FBO_Primary]->setAttachment(
|
fbos[FBO_Primary]->setAttachment(
|
||||||
osg::Camera::COLOR_BUFFER0, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Scene]));
|
osg::Camera::COLOR_BUFFER0, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Scene]));
|
||||||
@ -534,13 +530,12 @@ namespace MWRender
|
|||||||
osg::FrameBufferAttachment(new osg::RenderBuffer(textures[Tex_OpaqueDepth]->getTextureWidth(),
|
osg::FrameBufferAttachment(new osg::RenderBuffer(textures[Tex_OpaqueDepth]->getTextureWidth(),
|
||||||
textures[Tex_OpaqueDepth]->getTextureHeight(), textures[Tex_Scene]->getInternalFormat())));
|
textures[Tex_OpaqueDepth]->getTextureHeight(), textures[Tex_Scene]->getInternalFormat())));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mCanvases[frameId]->dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessor::dirtyTechniques()
|
void PostProcessor::dirtyTechniques()
|
||||||
{
|
{
|
||||||
if (!isEnabled())
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t frameId = frame() % 2;
|
size_t frameId = frame() % 2;
|
||||||
|
|
||||||
mDirty = true;
|
mDirty = true;
|
||||||
@ -667,7 +662,7 @@ namespace MWRender
|
|||||||
mTemplateData.emplace_back(std::move(node));
|
mTemplateData.emplace_back(std::move(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
mPingPongCanvas->setCurrentFrameData(frameId, fx::DispatchArray(mTemplateData));
|
mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData));
|
||||||
|
|
||||||
if (auto hud = MWBase::Environment::get().getWindowManager()->getPostProcessorHud())
|
if (auto hud = MWBase::Environment::get().getWindowManager()->getPostProcessorHud())
|
||||||
hud->updateTechniques();
|
hud->updateTechniques();
|
||||||
@ -678,12 +673,6 @@ namespace MWRender
|
|||||||
PostProcessor::Status PostProcessor::enableTechnique(
|
PostProcessor::Status PostProcessor::enableTechnique(
|
||||||
std::shared_ptr<fx::Technique> technique, std::optional<int> location)
|
std::shared_ptr<fx::Technique> technique, std::optional<int> location)
|
||||||
{
|
{
|
||||||
if (!isEnabled())
|
|
||||||
{
|
|
||||||
Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << technique->getName() << "'";
|
|
||||||
return Status_Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!technique || technique->getLocked() || (location.has_value() && location.value() < 0))
|
if (!technique || technique->getLocked() || (location.has_value() && location.value() < 0))
|
||||||
return Status_Error;
|
return Status_Error;
|
||||||
|
|
||||||
@ -721,86 +710,8 @@ namespace MWRender
|
|||||||
return technique->isValid();
|
return technique->isValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessor::createTexturesAndCamera(size_t frameId)
|
|
||||||
{
|
|
||||||
auto& textures = mTextures[frameId];
|
|
||||||
|
|
||||||
auto width = renderWidth();
|
|
||||||
auto height = renderHeight();
|
|
||||||
|
|
||||||
for (auto& texture : textures)
|
|
||||||
{
|
|
||||||
if (!texture)
|
|
||||||
{
|
|
||||||
if (Stereo::getMultiview())
|
|
||||||
texture = new osg::Texture2DArray;
|
|
||||||
else
|
|
||||||
texture = new osg::Texture2D;
|
|
||||||
}
|
|
||||||
Stereo::setMultiviewCompatibleTextureSize(texture, width, height);
|
|
||||||
texture->setSourceFormat(GL_RGBA);
|
|
||||||
texture->setSourceType(GL_UNSIGNED_BYTE);
|
|
||||||
texture->setInternalFormat(GL_RGBA);
|
|
||||||
texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR);
|
|
||||||
texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR);
|
|
||||||
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
|
||||||
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
|
||||||
texture->setResizeNonPowerOfTwoHint(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
textures[Tex_Normal]->setSourceFormat(GL_RGB);
|
|
||||||
textures[Tex_Normal]->setInternalFormat(GL_RGB);
|
|
||||||
|
|
||||||
auto setupDepth = [](osg::Texture* tex) {
|
|
||||||
tex->setSourceFormat(GL_DEPTH_STENCIL_EXT);
|
|
||||||
tex->setSourceType(SceneUtil::AutoDepth::depthSourceType());
|
|
||||||
tex->setInternalFormat(SceneUtil::AutoDepth::depthInternalFormat());
|
|
||||||
};
|
|
||||||
|
|
||||||
setupDepth(textures[Tex_Depth]);
|
|
||||||
|
|
||||||
if (mDisableDepthPasses)
|
|
||||||
{
|
|
||||||
textures[Tex_OpaqueDepth] = nullptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setupDepth(textures[Tex_OpaqueDepth]);
|
|
||||||
textures[Tex_OpaqueDepth]->setName("opaqueTexMap");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mHUDCamera)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mHUDCamera = new osg::Camera;
|
|
||||||
mHUDCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
|
||||||
mHUDCamera->setRenderOrder(osg::Camera::POST_RENDER);
|
|
||||||
mHUDCamera->setClearColor(osg::Vec4(0.45, 0.45, 0.14, 1.0));
|
|
||||||
mHUDCamera->setClearMask(0);
|
|
||||||
mHUDCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1));
|
|
||||||
mHUDCamera->setAllowEventFocus(false);
|
|
||||||
mHUDCamera->setViewport(0, 0, mWidth, mHeight);
|
|
||||||
|
|
||||||
mViewer->getCamera()->removeCullCallback(mPingPongCull);
|
|
||||||
mPingPongCull = new PingPongCull(this);
|
|
||||||
mViewer->getCamera()->addCullCallback(mPingPongCull);
|
|
||||||
|
|
||||||
mPingPongCanvas = new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager());
|
|
||||||
mHUDCamera->addChild(mPingPongCanvas);
|
|
||||||
mHUDCamera->setNodeMask(Mask_RenderToTexture);
|
|
||||||
|
|
||||||
mHUDCamera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
|
||||||
mHUDCamera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame)
|
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame)
|
||||||
{
|
{
|
||||||
if (!isEnabled())
|
|
||||||
{
|
|
||||||
Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << name << "'";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& technique : mTemplates)
|
for (const auto& technique : mTemplates)
|
||||||
if (Misc::StringUtils::ciEqual(technique->getName(), name))
|
if (Misc::StringUtils::ciEqual(technique->getName(), name))
|
||||||
return technique;
|
return technique;
|
||||||
@ -831,9 +742,6 @@ namespace MWRender
|
|||||||
|
|
||||||
void PostProcessor::loadChain()
|
void PostProcessor::loadChain()
|
||||||
{
|
{
|
||||||
if (!isEnabled())
|
|
||||||
return;
|
|
||||||
|
|
||||||
mTechniques.clear();
|
mTechniques.clear();
|
||||||
|
|
||||||
for (const std::string& techniqueName : Settings::postProcessing().mChain.get())
|
for (const std::string& techniqueName : Settings::postProcessing().mChain.get())
|
||||||
|
@ -115,14 +115,14 @@ namespace MWRender
|
|||||||
return mFbos[frameId][FBO_Multisample] ? mFbos[frameId][FBO_Multisample] : mFbos[frameId][FBO_Primary];
|
return mFbos[frameId][FBO_Multisample] ? mFbos[frameId][FBO_Multisample] : mFbos[frameId][FBO_Primary];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Camera> getHUDCamera() { return mHUDCamera; }
|
||||||
|
|
||||||
osg::ref_ptr<fx::StateUpdater> getStateUpdater() { return mStateUpdater; }
|
osg::ref_ptr<fx::StateUpdater> getStateUpdater() { return mStateUpdater; }
|
||||||
|
|
||||||
const TechniqueList& getTechniques() { return mTechniques; }
|
const TechniqueList& getTechniques() { return mTechniques; }
|
||||||
|
|
||||||
const TechniqueList& getTemplates() const { return mTemplates; }
|
const TechniqueList& getTemplates() const { return mTemplates; }
|
||||||
|
|
||||||
osg::ref_ptr<PingPongCanvas> getCanvas() { return mPingPongCanvas; }
|
|
||||||
|
|
||||||
const auto& getTechniqueMap() const { return mTechniqueFileMap; }
|
const auto& getTechniqueMap() const { return mTechniqueFileMap; }
|
||||||
|
|
||||||
void resize();
|
void resize();
|
||||||
@ -173,13 +173,11 @@ namespace MWRender
|
|||||||
|
|
||||||
std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame = false);
|
std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame = false);
|
||||||
|
|
||||||
bool isEnabled() const { return mUsePostProcessing && mEnabled; }
|
bool isEnabled() const { return mUsePostProcessing; }
|
||||||
|
|
||||||
bool getHDR() const { return mHDR; }
|
|
||||||
|
|
||||||
void disable();
|
void disable();
|
||||||
|
|
||||||
void enable(bool usePostProcessing = true);
|
void enable();
|
||||||
|
|
||||||
void setRenderTargetSize(int width, int height)
|
void setRenderTargetSize(int width, int height)
|
||||||
{
|
{
|
||||||
@ -194,7 +192,7 @@ namespace MWRender
|
|||||||
|
|
||||||
void triggerShaderReload();
|
void triggerShaderReload();
|
||||||
|
|
||||||
bool mEnableLiveReload;
|
bool mEnableLiveReload = false;
|
||||||
|
|
||||||
void loadChain();
|
void loadChain();
|
||||||
void saveChain();
|
void saveChain();
|
||||||
@ -206,10 +204,6 @@ namespace MWRender
|
|||||||
|
|
||||||
void createObjectsForFrame(size_t frameId);
|
void createObjectsForFrame(size_t frameId);
|
||||||
|
|
||||||
void createTexturesAndCamera(size_t frameId);
|
|
||||||
|
|
||||||
void reloadMainPass(fx::Technique& technique);
|
|
||||||
|
|
||||||
void dirtyTechniques();
|
void dirtyTechniques();
|
||||||
|
|
||||||
void update(size_t frameId);
|
void update(size_t frameId);
|
||||||
@ -232,43 +226,39 @@ namespace MWRender
|
|||||||
|
|
||||||
std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap;
|
std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap;
|
||||||
|
|
||||||
int mSamples;
|
|
||||||
|
|
||||||
bool mDirty;
|
|
||||||
size_t mDirtyFrameId;
|
|
||||||
|
|
||||||
RenderingManager& mRendering;
|
RenderingManager& mRendering;
|
||||||
osgViewer::Viewer* mViewer;
|
osgViewer::Viewer* mViewer;
|
||||||
const VFS::Manager* mVFS;
|
const VFS::Manager* mVFS;
|
||||||
|
|
||||||
bool mTriggerShaderReload;
|
size_t mDirtyFrameId = 0;
|
||||||
bool mReload;
|
size_t mLastFrameNumber = 0;
|
||||||
bool mEnabled;
|
float mLastSimulationTime = 0.f;
|
||||||
bool mUsePostProcessing;
|
|
||||||
bool mDisableDepthPasses;
|
|
||||||
|
|
||||||
size_t mLastFrameNumber;
|
bool mDirty = false;
|
||||||
float mLastSimulationTime;
|
bool mReload = true;
|
||||||
|
bool mTriggerShaderReload = false;
|
||||||
|
bool mUsePostProcessing = false;
|
||||||
|
|
||||||
|
bool mUBO = false;
|
||||||
|
bool mHDR = false;
|
||||||
|
bool mNormals = false;
|
||||||
|
bool mUnderwater = false;
|
||||||
|
bool mPassLights = false;
|
||||||
|
bool mPrevNormals = false;
|
||||||
|
bool mExteriorFlag = false;
|
||||||
|
bool mNormalsSupported = false;
|
||||||
|
bool mPrevPassLights = false;
|
||||||
|
|
||||||
bool mExteriorFlag;
|
|
||||||
bool mUnderwater;
|
|
||||||
bool mHDR;
|
|
||||||
bool mNormals;
|
|
||||||
bool mPrevNormals;
|
|
||||||
bool mNormalsSupported;
|
|
||||||
bool mPassLights;
|
|
||||||
bool mPrevPassLights;
|
|
||||||
bool mUBO;
|
|
||||||
int mGLSLVersion;
|
int mGLSLVersion;
|
||||||
|
int mWidth;
|
||||||
|
int mHeight;
|
||||||
|
int mSamples;
|
||||||
|
|
||||||
osg::ref_ptr<fx::StateUpdater> mStateUpdater;
|
osg::ref_ptr<fx::StateUpdater> mStateUpdater;
|
||||||
osg::ref_ptr<PingPongCull> mPingPongCull;
|
osg::ref_ptr<PingPongCull> mPingPongCull;
|
||||||
osg::ref_ptr<PingPongCanvas> mPingPongCanvas;
|
std::array<osg::ref_ptr<PingPongCanvas>, 2> mCanvases;
|
||||||
osg::ref_ptr<TransparentDepthBinCallback> mTransparentDepthPostPass;
|
osg::ref_ptr<TransparentDepthBinCallback> mTransparentDepthPostPass;
|
||||||
|
|
||||||
int mWidth;
|
|
||||||
int mHeight;
|
|
||||||
|
|
||||||
fx::DispatchArray mTemplateData;
|
fx::DispatchArray mTemplateData;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1256,7 +1256,7 @@ namespace MWRender
|
|||||||
mSharedUniformStateUpdater->setScreenRes(res.x(), res.y());
|
mSharedUniformStateUpdater->setScreenRes(res.x(), res.y());
|
||||||
Stereo::Manager::instance().setMasterProjectionMatrix(mPerViewUniformStateUpdater->getProjectionMatrix());
|
Stereo::Manager::instance().setMasterProjectionMatrix(mPerViewUniformStateUpdater->getProjectionMatrix());
|
||||||
}
|
}
|
||||||
else if (!mPostProcessor->isEnabled())
|
else
|
||||||
{
|
{
|
||||||
mSharedUniformStateUpdater->setScreenRes(width, height);
|
mSharedUniformStateUpdater->setScreenRes(width, height);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
#include "postprocessor.hpp"
|
#include "postprocessor.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
@ -102,24 +103,6 @@ namespace MWRender
|
|||||||
int width = screenW - leftPadding * 2;
|
int width = screenW - leftPadding * 2;
|
||||||
int height = screenH - topPadding * 2;
|
int height = screenH - topPadding * 2;
|
||||||
|
|
||||||
// Ensure we are reading from the resolved framebuffer and not the multisampled render buffer. Also ensure
|
|
||||||
// that the readbuffer is set correctly with rendeirng to FBO. glReadPixel() cannot read from multisampled
|
|
||||||
// targets
|
|
||||||
PostProcessor* postProcessor = dynamic_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
|
|
||||||
osg::GLExtensions* ext = osg::GLExtensions::Get(renderInfo.getContextID(), false);
|
|
||||||
|
|
||||||
if (ext)
|
|
||||||
{
|
|
||||||
size_t frameId = renderInfo.getState()->getFrameStamp()->getFrameNumber() % 2;
|
|
||||||
osg::FrameBufferObject* fbo = nullptr;
|
|
||||||
|
|
||||||
if (postProcessor && postProcessor->getFbo(PostProcessor::FBO_Primary, frameId))
|
|
||||||
fbo = postProcessor->getFbo(PostProcessor::FBO_Primary, frameId);
|
|
||||||
|
|
||||||
if (fbo)
|
|
||||||
fbo->apply(*renderInfo.getState(), osg::FrameBufferObject::READ_FRAMEBUFFER);
|
|
||||||
}
|
|
||||||
|
|
||||||
mImage->readPixels(leftPadding, topPadding, width, height, GL_RGB, GL_UNSIGNED_BYTE);
|
mImage->readPixels(leftPadding, topPadding, width, height, GL_RGB, GL_UNSIGNED_BYTE);
|
||||||
mImage->scaleImage(mWidth, mHeight, 1);
|
mImage->scaleImage(mWidth, mHeight, 1);
|
||||||
}
|
}
|
||||||
@ -145,7 +128,7 @@ namespace MWRender
|
|||||||
|
|
||||||
void ScreenshotManager::screenshot(osg::Image* image, int w, int h)
|
void ScreenshotManager::screenshot(osg::Image* image, int w, int h)
|
||||||
{
|
{
|
||||||
osg::Camera* camera = mViewer->getCamera();
|
osg::Camera* camera = MWBase::Environment::get().getWorld()->getPostProcessor()->getHUDCamera();
|
||||||
osg::ref_ptr<osg::Drawable> tempDrw = new osg::Drawable;
|
osg::ref_ptr<osg::Drawable> tempDrw = new osg::Drawable;
|
||||||
tempDrw->setDrawCallback(new ReadImageFromFramebufferCallback(image, w, h));
|
tempDrw->setDrawCallback(new ReadImageFromFramebufferCallback(image, w, h));
|
||||||
tempDrw->setCullingActive(false);
|
tempDrw->setCullingActive(false);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user