mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 13:15:34 +00:00
Merge branch 'fbos_for_all' into 'master'
[renderer] render scene exclusively to fbo Closes #7364 and #7354 See merge request OpenMW/openmw!3243
This commit is contained in:
commit
6f4e7ed5dc
8 changed files with 234 additions and 407 deletions
|
@ -328,46 +328,37 @@ namespace MWRender
|
|||
{
|
||||
osg::State* state = renderInfo.getState();
|
||||
|
||||
PostProcessor* postProcessor = dynamic_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
|
||||
PostProcessor* postProcessor = static_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
|
||||
|
||||
state->applyAttribute(mDepth);
|
||||
|
||||
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);
|
||||
if (mPassNormals)
|
||||
{
|
||||
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);
|
||||
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
|
||||
{
|
||||
// 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);
|
||||
bin->drawImplementation(renderInfo, previous);
|
||||
}
|
||||
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);
|
||||
|
||||
state->checkGLErrors("after DepthClearCallback::drawImplementation");
|
||||
}
|
||||
|
|
|
@ -43,19 +43,16 @@ namespace MWRender
|
|||
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;
|
||||
|
||||
mBufferData[frameId].mask
|
||||
|= 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;
|
||||
mMask = 0;
|
||||
mMask |= underwater ? fx::Technique::Flag_Disable_Underwater : fx::Technique::Flag_Disable_Abovewater;
|
||||
mMask |= exterior ? fx::Technique::Flag_Disable_Exteriors : fx::Technique::Flag_Disable_Interiors;
|
||||
}
|
||||
|
||||
void PingPongCanvas::drawGeometry(osg::RenderInfo& renderInfo) const
|
||||
|
@ -77,19 +74,15 @@ namespace MWRender
|
|||
|
||||
size_t frameId = state.getFrameStamp()->getFrameNumber() % 2;
|
||||
|
||||
auto& bufferData = mBufferData[frameId];
|
||||
|
||||
const auto& data = bufferData.data;
|
||||
|
||||
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;
|
||||
|
||||
filtered.push_back(i);
|
||||
|
@ -97,7 +90,7 @@ namespace MWRender
|
|||
|
||||
auto* resolveViewport = state.getCurrentViewport();
|
||||
|
||||
if (filtered.empty() || !bufferData.postprocessing)
|
||||
if (filtered.empty() || !mPostprocessing)
|
||||
{
|
||||
state.pushStateSet(mFallbackStateSet);
|
||||
state.apply();
|
||||
|
@ -108,7 +101,7 @@ namespace MWRender
|
|||
state.apply();
|
||||
}
|
||||
|
||||
state.applyTextureAttribute(0, bufferData.sceneTex);
|
||||
state.applyTextureAttribute(0, mTextureScene);
|
||||
resolveViewport->apply(state);
|
||||
|
||||
drawGeometry(renderInfo);
|
||||
|
@ -124,13 +117,12 @@ namespace MWRender
|
|||
|
||||
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)
|
||||
{
|
||||
fbo = new osg::FrameBufferObject;
|
||||
attachCloneOfTemplate(
|
||||
fbo, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR);
|
||||
attachCloneOfTemplate(fbo, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, mTextureScene);
|
||||
fbo->apply(state);
|
||||
glClearColor(0.5, 0.5, 0.5, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
@ -140,7 +132,7 @@ namespace MWRender
|
|||
{
|
||||
mMultiviewResolveFramebuffer = new osg::FrameBufferObject();
|
||||
attachCloneOfTemplate(mMultiviewResolveFramebuffer,
|
||||
osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR);
|
||||
osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, mTextureScene);
|
||||
mMultiviewResolveFramebuffer->apply(state);
|
||||
glClearColor(0.5, 0.5, 0.5, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
@ -150,15 +142,15 @@ namespace MWRender
|
|||
.getTexture());
|
||||
}
|
||||
|
||||
mLuminanceCalculator.dirty(bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight());
|
||||
mLuminanceCalculator.dirty(mTextureScene->getTextureWidth(), mTextureScene->getTextureHeight());
|
||||
|
||||
if (Stereo::getStereo())
|
||||
mRenderViewport = new osg::Viewport(
|
||||
0, 0, bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight());
|
||||
mRenderViewport
|
||||
= new osg::Viewport(0, 0, mTextureScene->getTextureWidth(), mTextureScene->getTextureHeight());
|
||||
else
|
||||
mRenderViewport = nullptr;
|
||||
|
||||
bufferData.dirty = false;
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
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_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
|
||||
// supported, so that's what we use for now.
|
||||
|
@ -181,8 +173,7 @@ namespace MWRender
|
|||
|
||||
const unsigned int cid = state.getContextID();
|
||||
|
||||
const osg::ref_ptr<osg::FrameBufferObject>& destinationFbo
|
||||
= bufferData.destination ? bufferData.destination : nullptr;
|
||||
const osg::ref_ptr<osg::FrameBufferObject>& destinationFbo = mDestinationFBO ? mDestinationFBO : nullptr;
|
||||
unsigned int destinationHandle = destinationFbo ? destinationFbo->getHandle(cid) : 0;
|
||||
|
||||
auto bindDestinationFbo = [&]() {
|
||||
|
@ -206,17 +197,16 @@ namespace MWRender
|
|||
|
||||
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(
|
||||
PostProcessor::TextureUnits::Unit_EyeAdaptation, mLuminanceCalculator.getLuminanceTexture(frameId));
|
||||
|
||||
if (bufferData.normalsTex)
|
||||
node.mRootStateSet->setTextureAttribute(
|
||||
PostProcessor::TextureUnits::Unit_Normals, bufferData.normalsTex);
|
||||
if (mTextureNormals)
|
||||
node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_Normals, mTextureNormals);
|
||||
|
||||
state.pushStateSet(node.mRootStateSet);
|
||||
state.apply();
|
||||
|
@ -231,7 +221,7 @@ namespace MWRender
|
|||
|
||||
// VR-TODO: This won't actually work for tex2darrays
|
||||
if (lastShader == 0)
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, bufferData.sceneTex);
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, mTextureScene);
|
||||
else
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader,
|
||||
(osg::Texture*)mFbos[lastShader - GL_COLOR_ATTACHMENT0_EXT]
|
||||
|
@ -239,7 +229,7 @@ namespace MWRender
|
|||
.getTexture());
|
||||
|
||||
if (lastDraw == 0)
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, bufferData.sceneTex);
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, mTextureScene);
|
||||
else
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass,
|
||||
(osg::Texture*)mFbos[lastDraw - GL_COLOR_ATTACHMENT0_EXT]
|
||||
|
@ -260,7 +250,6 @@ namespace MWRender
|
|||
}
|
||||
|
||||
lastApplied = pass.mRenderTarget->getHandle(state.getContextID());
|
||||
;
|
||||
}
|
||||
else if (pass.mResolve && index == filtered.back())
|
||||
{
|
||||
|
|
|
@ -24,76 +24,52 @@ namespace MWRender
|
|||
public:
|
||||
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;
|
||||
|
||||
private:
|
||||
void copyNewFrameData(size_t frameId) const;
|
||||
void drawImplementation(osg::RenderInfo& renderInfo) const override;
|
||||
|
||||
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> mMultiviewResolveProgram;
|
||||
osg::ref_ptr<osg::StateSet> mFallbackStateSet;
|
||||
osg::ref_ptr<osg::StateSet> mMultiviewResolveStateSet;
|
||||
mutable osg::ref_ptr<osg::FrameBufferObject> mMultiviewResolveFramebuffer;
|
||||
|
||||
struct BufferData
|
||||
{
|
||||
bool dirty = false;
|
||||
bool hdr = false;
|
||||
bool postprocessing = true;
|
||||
osg::ref_ptr<osg::Texture> mTextureScene;
|
||||
osg::ref_ptr<osg::Texture> mTextureDepth;
|
||||
osg::ref_ptr<osg::Texture> mTextureNormals;
|
||||
|
||||
fx::DispatchArray data;
|
||||
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 bool mDirty = false;
|
||||
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())
|
||||
{
|
||||
mViewportStateset = new osg::StateSet();
|
||||
mViewport = new osg::Viewport(0, 0, pp->renderWidth(), pp->renderHeight());
|
||||
mViewport = new osg::Viewport;
|
||||
mViewportStateset->setAttribute(mViewport);
|
||||
}
|
||||
}
|
||||
|
@ -37,41 +37,31 @@ namespace MWRender
|
|||
size_t frame = cv->getTraversalNumber();
|
||||
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())
|
||||
{
|
||||
auto& sm = Stereo::Manager::instance();
|
||||
auto view = sm.getEye(cv);
|
||||
int index = view == Stereo::Eye::Right ? 1 : 0;
|
||||
auto projectionMatrix = sm.computeEyeProjection(index, true);
|
||||
postProcessor->getStateUpdater()->setProjectionMatrix(projectionMatrix);
|
||||
mPostProcessor->getStateUpdater()->setProjectionMatrix(projectionMatrix);
|
||||
}
|
||||
|
||||
postProcessor->getStateUpdater()->setViewMatrix(cv->getCurrentCamera()->getViewMatrix());
|
||||
postProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix[0]);
|
||||
mPostProcessor->getStateUpdater()->setViewMatrix(cv->getCurrentCamera()->getViewMatrix());
|
||||
mPostProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix[0]);
|
||||
mLastViewMatrix[0] = cv->getCurrentCamera()->getViewMatrix();
|
||||
|
||||
postProcessor->getStateUpdater()->setEyePos(cv->getEyePoint());
|
||||
postProcessor->getStateUpdater()->setEyeVec(cv->getLookVectorLocal());
|
||||
mPostProcessor->getStateUpdater()->setEyePos(cv->getEyePoint());
|
||||
mPostProcessor->getStateUpdater()->setEyeVec(cv->getLookVectorLocal());
|
||||
|
||||
if (!postProcessor->getFbo(PostProcessor::FBO_Primary, frameId))
|
||||
if (!mPostProcessor->getFbo(PostProcessor::FBO_Multisample, frameId))
|
||||
{
|
||||
renderStage->setMultisampleResolveFramebufferObject(nullptr);
|
||||
renderStage->setFrameBufferObject(nullptr);
|
||||
}
|
||||
else if (!postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId))
|
||||
{
|
||||
renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
||||
renderStage->setFrameBufferObject(mPostProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
||||
}
|
||||
else
|
||||
{
|
||||
renderStage->setMultisampleResolveFramebufferObject(
|
||||
postProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
||||
renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId));
|
||||
mPostProcessor->getFbo(PostProcessor::FBO_Primary, 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
|
||||
// changed. So we do blit manually in this case
|
||||
|
|
|
@ -110,30 +110,45 @@ namespace MWRender
|
|||
PostProcessor::PostProcessor(
|
||||
RenderingManager& rendering, osgViewer::Viewer* viewer, osg::Group* rootNode, const VFS::Manager* vfs)
|
||||
: osg::Group()
|
||||
, mEnableLiveReload(false)
|
||||
, mRootNode(rootNode)
|
||||
, mSamples(Settings::video().mAntialiasing)
|
||||
, mDirty(false)
|
||||
, mDirtyFrameId(0)
|
||||
, mHUDCamera(new osg::Camera)
|
||||
, mRendering(rendering)
|
||||
, mViewer(viewer)
|
||||
, mVFS(vfs)
|
||||
, mTriggerShaderReload(false)
|
||||
, mReload(false)
|
||||
, mEnabled(false)
|
||||
, mUsePostProcessing(Settings::postProcessing().mEnabled)
|
||||
, mDisableDepthPasses(false)
|
||||
, mLastFrameNumber(0)
|
||||
, mLastSimulationTime(0.f)
|
||||
, mExteriorFlag(false)
|
||||
, mUnderwater(false)
|
||||
, mHDR(false)
|
||||
, mNormals(false)
|
||||
, mPrevNormals(false)
|
||||
, mNormalsSupported(false)
|
||||
, mPassLights(false)
|
||||
, mPrevPassLights(false)
|
||||
, mSamples(Settings::video().mAntialiasing)
|
||||
, mPingPongCull(new PingPongCull(this))
|
||||
, mCanvases({ new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()),
|
||||
new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()) })
|
||||
{
|
||||
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::GLExtensions* ext = gc->getState()->get<osg::GLExtensions>();
|
||||
|
||||
|
@ -169,11 +184,18 @@ namespace MWRender
|
|||
mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
|
||||
mStateUpdater = new fx::StateUpdater(mUBO);
|
||||
|
||||
if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles
|
||||
&& !mUsePostProcessing)
|
||||
return;
|
||||
addChild(mHUDCamera);
|
||||
addChild(mRootNode);
|
||||
|
||||
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()
|
||||
|
@ -202,7 +224,6 @@ namespace MWRender
|
|||
|
||||
size_t frameId = frame() % 2;
|
||||
|
||||
createTexturesAndCamera(frameId);
|
||||
createObjectsForFrame(frameId);
|
||||
|
||||
mRendering.updateProjectionMatrix();
|
||||
|
@ -210,8 +231,6 @@ namespace MWRender
|
|||
|
||||
dirtyTechniques();
|
||||
|
||||
mPingPongCanvas->dirty(frameId);
|
||||
|
||||
mDirty = true;
|
||||
mDirtyFrameId = !frameId;
|
||||
}
|
||||
|
@ -230,77 +249,20 @@ namespace MWRender
|
|||
}
|
||||
}
|
||||
|
||||
void PostProcessor::enable(bool usePostProcessing)
|
||||
void PostProcessor::enable()
|
||||
{
|
||||
mReload = true;
|
||||
mEnabled = 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);
|
||||
mUsePostProcessing = true;
|
||||
}
|
||||
|
||||
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;
|
||||
mRendering.getSkyManager()->setSunglare(true);
|
||||
}
|
||||
|
||||
void PostProcessor::traverse(osg::NodeVisitor& nv)
|
||||
{
|
||||
if (!mEnabled)
|
||||
{
|
||||
osg::Group::traverse(nv);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t frameId = nv.getTraversalNumber() % 2;
|
||||
|
||||
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
||||
|
@ -313,26 +275,23 @@ namespace MWRender
|
|||
|
||||
void PostProcessor::cull(size_t frameId, osgUtil::CullVisitor* cv)
|
||||
{
|
||||
const auto& fbo = getFbo(FBO_Intercept, frameId);
|
||||
if (fbo)
|
||||
if (const auto& fbo = getFbo(FBO_Intercept, frameId))
|
||||
{
|
||||
osgUtil::RenderStage* rs = cv->getRenderStage();
|
||||
if (rs && rs->getMultisampleResolveFramebufferObject())
|
||||
rs->setMultisampleResolveFramebufferObject(fbo);
|
||||
}
|
||||
|
||||
mPingPongCanvas->setPostProcessing(frameId, mUsePostProcessing);
|
||||
mPingPongCanvas->setNormalsTexture(frameId, mNormals ? getTexture(Tex_Normal, frameId) : nullptr);
|
||||
mPingPongCanvas->setMask(frameId, mUnderwater, mExteriorFlag);
|
||||
mPingPongCanvas->setHDR(frameId, getHDR());
|
||||
mCanvases[frameId]->setPostProcessing(mUsePostProcessing);
|
||||
mCanvases[frameId]->setTextureNormals(mNormals ? getTexture(Tex_Normal, frameId) : nullptr);
|
||||
mCanvases[frameId]->setMask(mUnderwater, mExteriorFlag);
|
||||
mCanvases[frameId]->setCalculateAvgLum(mHDR);
|
||||
|
||||
mPingPongCanvas->setSceneTexture(frameId, getTexture(Tex_Scene, frameId));
|
||||
if (mDisableDepthPasses)
|
||||
mPingPongCanvas->setDepthTexture(frameId, getTexture(Tex_Depth, frameId));
|
||||
mCanvases[frameId]->setTextureScene(getTexture(Tex_Scene, frameId));
|
||||
if (mTransparentDepthPostPass)
|
||||
mCanvases[frameId]->setTextureDepth(getTexture(Tex_OpaqueDepth, frameId));
|
||||
else
|
||||
mPingPongCanvas->setDepthTexture(frameId, getTexture(Tex_OpaqueDepth, frameId));
|
||||
|
||||
mPingPongCanvas->setLDRSceneTexture(frameId, getTexture(Tex_Scene_LDR, frameId));
|
||||
mCanvases[frameId]->setTextureDepth(getTexture(Tex_Depth, frameId));
|
||||
|
||||
if (mTransparentDepthPostPass)
|
||||
{
|
||||
|
@ -355,7 +314,7 @@ namespace MWRender
|
|||
mStateUpdater->setDeltaSimulationTime(static_cast<float>(stamp->getSimulationTime() - mLastSimulationTime));
|
||||
mLastSimulationTime = stamp->getSimulationTime();
|
||||
|
||||
for (const auto& dispatchNode : mPingPongCanvas->getCurrentFrameData(frame))
|
||||
for (const auto& dispatchNode : mCanvases[frameId]->getPasses())
|
||||
{
|
||||
for (auto& uniform : dispatchNode.mHandle->getUniformMap())
|
||||
{
|
||||
|
@ -421,13 +380,15 @@ namespace MWRender
|
|||
|
||||
reloadIfRequired();
|
||||
|
||||
mCanvases[frameId]->setNodeMask(~0u);
|
||||
mCanvases[!frameId]->setNodeMask(0);
|
||||
|
||||
if (mDirty && mDirtyFrameId == frameId)
|
||||
{
|
||||
createTexturesAndCamera(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))
|
||||
|
@ -448,7 +409,6 @@ namespace MWRender
|
|||
|
||||
mViewer->startThreading();
|
||||
|
||||
createTexturesAndCamera(frameId);
|
||||
createObjectsForFrame(frameId);
|
||||
|
||||
mDirty = true;
|
||||
|
@ -458,20 +418,56 @@ namespace MWRender
|
|||
|
||||
void PostProcessor::createObjectsForFrame(size_t frameId)
|
||||
{
|
||||
auto& fbos = mFbos[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)
|
||||
continue;
|
||||
|
||||
Stereo::setMultiviewCompatibleTextureSize(tex, width, height);
|
||||
tex->dirtyTextureObject();
|
||||
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);
|
||||
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]->setAttachment(
|
||||
osg::Camera::COLOR_BUFFER0, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Scene]));
|
||||
|
@ -534,13 +530,12 @@ namespace MWRender
|
|||
osg::FrameBufferAttachment(new osg::RenderBuffer(textures[Tex_OpaqueDepth]->getTextureWidth(),
|
||||
textures[Tex_OpaqueDepth]->getTextureHeight(), textures[Tex_Scene]->getInternalFormat())));
|
||||
#endif
|
||||
|
||||
mCanvases[frameId]->dirty();
|
||||
}
|
||||
|
||||
void PostProcessor::dirtyTechniques()
|
||||
{
|
||||
if (!isEnabled())
|
||||
return;
|
||||
|
||||
size_t frameId = frame() % 2;
|
||||
|
||||
mDirty = true;
|
||||
|
@ -667,7 +662,7 @@ namespace MWRender
|
|||
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())
|
||||
hud->updateTechniques();
|
||||
|
@ -678,12 +673,6 @@ namespace MWRender
|
|||
PostProcessor::Status PostProcessor::enableTechnique(
|
||||
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))
|
||||
return Status_Error;
|
||||
|
||||
|
@ -721,86 +710,8 @@ namespace MWRender
|
|||
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)
|
||||
{
|
||||
if (!isEnabled())
|
||||
{
|
||||
Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << name << "'";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (const auto& technique : mTemplates)
|
||||
if (Misc::StringUtils::ciEqual(technique->getName(), name))
|
||||
return technique;
|
||||
|
@ -831,9 +742,6 @@ namespace MWRender
|
|||
|
||||
void PostProcessor::loadChain()
|
||||
{
|
||||
if (!isEnabled())
|
||||
return;
|
||||
|
||||
mTechniques.clear();
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Camera> getHUDCamera() { return mHUDCamera; }
|
||||
|
||||
osg::ref_ptr<fx::StateUpdater> getStateUpdater() { return mStateUpdater; }
|
||||
|
||||
const TechniqueList& getTechniques() { return mTechniques; }
|
||||
|
||||
const TechniqueList& getTemplates() const { return mTemplates; }
|
||||
|
||||
osg::ref_ptr<PingPongCanvas> getCanvas() { return mPingPongCanvas; }
|
||||
|
||||
const auto& getTechniqueMap() const { return mTechniqueFileMap; }
|
||||
|
||||
void resize();
|
||||
|
@ -173,13 +173,11 @@ namespace MWRender
|
|||
|
||||
std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame = false);
|
||||
|
||||
bool isEnabled() const { return mUsePostProcessing && mEnabled; }
|
||||
|
||||
bool getHDR() const { return mHDR; }
|
||||
bool isEnabled() const { return mUsePostProcessing; }
|
||||
|
||||
void disable();
|
||||
|
||||
void enable(bool usePostProcessing = true);
|
||||
void enable();
|
||||
|
||||
void setRenderTargetSize(int width, int height)
|
||||
{
|
||||
|
@ -194,7 +192,7 @@ namespace MWRender
|
|||
|
||||
void triggerShaderReload();
|
||||
|
||||
bool mEnableLiveReload;
|
||||
bool mEnableLiveReload = false;
|
||||
|
||||
void loadChain();
|
||||
void saveChain();
|
||||
|
@ -206,10 +204,6 @@ namespace MWRender
|
|||
|
||||
void createObjectsForFrame(size_t frameId);
|
||||
|
||||
void createTexturesAndCamera(size_t frameId);
|
||||
|
||||
void reloadMainPass(fx::Technique& technique);
|
||||
|
||||
void dirtyTechniques();
|
||||
|
||||
void update(size_t frameId);
|
||||
|
@ -232,43 +226,39 @@ namespace MWRender
|
|||
|
||||
std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap;
|
||||
|
||||
int mSamples;
|
||||
|
||||
bool mDirty;
|
||||
size_t mDirtyFrameId;
|
||||
|
||||
RenderingManager& mRendering;
|
||||
osgViewer::Viewer* mViewer;
|
||||
const VFS::Manager* mVFS;
|
||||
|
||||
bool mTriggerShaderReload;
|
||||
bool mReload;
|
||||
bool mEnabled;
|
||||
bool mUsePostProcessing;
|
||||
bool mDisableDepthPasses;
|
||||
size_t mDirtyFrameId = 0;
|
||||
size_t mLastFrameNumber = 0;
|
||||
float mLastSimulationTime = 0.f;
|
||||
|
||||
size_t mLastFrameNumber;
|
||||
float mLastSimulationTime;
|
||||
bool mDirty = false;
|
||||
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 mWidth;
|
||||
int mHeight;
|
||||
int mSamples;
|
||||
|
||||
osg::ref_ptr<fx::StateUpdater> mStateUpdater;
|
||||
osg::ref_ptr<PingPongCull> mPingPongCull;
|
||||
osg::ref_ptr<PingPongCanvas> mPingPongCanvas;
|
||||
std::array<osg::ref_ptr<PingPongCanvas>, 2> mCanvases;
|
||||
osg::ref_ptr<TransparentDepthBinCallback> mTransparentDepthPostPass;
|
||||
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
||||
fx::DispatchArray mTemplateData;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1256,7 +1256,7 @@ namespace MWRender
|
|||
mSharedUniformStateUpdater->setScreenRes(res.x(), res.y());
|
||||
Stereo::Manager::instance().setMasterProjectionMatrix(mPerViewUniformStateUpdater->getProjectionMatrix());
|
||||
}
|
||||
else if (!mPostProcessor->isEnabled())
|
||||
else
|
||||
{
|
||||
mSharedUniformStateUpdater->setScreenRes(width, height);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "postprocessor.hpp"
|
||||
#include "util.hpp"
|
||||
|
@ -102,24 +103,6 @@ namespace MWRender
|
|||
int width = screenW - leftPadding * 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->scaleImage(mWidth, mHeight, 1);
|
||||
}
|
||||
|
@ -145,7 +128,7 @@ namespace MWRender
|
|||
|
||||
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;
|
||||
tempDrw->setDrawCallback(new ReadImageFromFramebufferCallback(image, w, h));
|
||||
tempDrw->setCullingActive(false);
|
||||
|
|
Loading…
Reference in a new issue