mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 13:15:34 +00:00
support postprocess distortion
This commit is contained in:
parent
51cb3b08cb
commit
187f63d3d3
25 changed files with 311 additions and 65 deletions
|
@ -24,7 +24,7 @@ add_openmw_dir (mwrender
|
||||||
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
|
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
|
||||||
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover
|
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover
|
||||||
postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass precipitationocclusion ripples
|
postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass precipitationocclusion ripples
|
||||||
actorutil
|
actorutil distortion
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
|
28
apps/openmw/mwrender/distortion.cpp
Normal file
28
apps/openmw/mwrender/distortion.cpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#include "distortion.hpp"
|
||||||
|
|
||||||
|
#include <osg/FrameBufferObject>
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
void DistortionCallback::drawImplementation(
|
||||||
|
osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous)
|
||||||
|
{
|
||||||
|
osg::State* state = renderInfo.getState();
|
||||||
|
size_t frameId = state->getFrameStamp()->getFrameNumber() % 2;
|
||||||
|
|
||||||
|
mFBO[frameId]->apply(*state);
|
||||||
|
|
||||||
|
const osg::Texture* tex
|
||||||
|
= mFBO[frameId]->getAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0).getTexture();
|
||||||
|
|
||||||
|
glViewport(0, 0, tex->getTextureWidth(), tex->getTextureHeight());
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
bin->drawImplementation(renderInfo, previous);
|
||||||
|
|
||||||
|
tex = mOriginalFBO[frameId]->getAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0).getTexture();
|
||||||
|
glViewport(0, 0, tex->getTextureWidth(), tex->getTextureHeight());
|
||||||
|
mOriginalFBO[frameId]->apply(*state);
|
||||||
|
}
|
||||||
|
}
|
28
apps/openmw/mwrender/distortion.hpp
Normal file
28
apps/openmw/mwrender/distortion.hpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <osgUtil/RenderBin>
|
||||||
|
|
||||||
|
namespace osg
|
||||||
|
{
|
||||||
|
class FrameBufferObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
class DistortionCallback : public osgUtil::RenderBin::DrawCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void drawImplementation(
|
||||||
|
osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) override;
|
||||||
|
|
||||||
|
void setFBO(const osg::ref_ptr<osg::FrameBufferObject>& fbo, size_t frameId) { mFBO[frameId] = fbo; }
|
||||||
|
void setOriginalFBO(const osg::ref_ptr<osg::FrameBufferObject>& fbo, size_t frameId)
|
||||||
|
{
|
||||||
|
mOriginalFBO[frameId] = fbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mFBO;
|
||||||
|
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mOriginalFBO;
|
||||||
|
};
|
||||||
|
}
|
|
@ -345,11 +345,9 @@ namespace MWRender
|
||||||
bin->drawImplementation(renderInfo, previous);
|
bin->drawImplementation(renderInfo, previous);
|
||||||
|
|
||||||
auto primaryFBO = postProcessor->getPrimaryFbo(frameId);
|
auto primaryFBO = postProcessor->getPrimaryFbo(frameId);
|
||||||
|
primaryFBO->apply(*state);
|
||||||
|
|
||||||
if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId))
|
postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state);
|
||||||
postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state);
|
|
||||||
else
|
|
||||||
primaryFBO->apply(*state);
|
|
||||||
|
|
||||||
// depth accumulation pass
|
// depth accumulation pass
|
||||||
osg::ref_ptr<osg::StateSet> restore = bin->getStateSet();
|
osg::ref_ptr<osg::StateSet> restore = bin->getStateSet();
|
||||||
|
@ -357,8 +355,7 @@ namespace MWRender
|
||||||
bin->drawImplementation(renderInfo, previous);
|
bin->drawImplementation(renderInfo, previous);
|
||||||
bin->setStateSet(restore);
|
bin->setStateSet(restore);
|
||||||
|
|
||||||
if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId))
|
primaryFBO->apply(*state);
|
||||||
primaryFBO->apply(*state);
|
|
||||||
|
|
||||||
state->checkGLErrors("after DepthClearCallback::drawImplementation");
|
state->checkGLErrors("after DepthClearCallback::drawImplementation");
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,6 +242,10 @@ namespace MWRender
|
||||||
if (mTextureNormals)
|
if (mTextureNormals)
|
||||||
node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_Normals, mTextureNormals);
|
node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_Normals, mTextureNormals);
|
||||||
|
|
||||||
|
if (mTextureDistortion)
|
||||||
|
node.mRootStateSet->setTextureAttribute(
|
||||||
|
PostProcessor::TextureUnits::Unit_Distortion, mTextureDistortion);
|
||||||
|
|
||||||
state.pushStateSet(node.mRootStateSet);
|
state.pushStateSet(node.mRootStateSet);
|
||||||
state.apply();
|
state.apply();
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@ namespace MWRender
|
||||||
|
|
||||||
void setTextureNormals(osg::ref_ptr<osg::Texture> tex) { mTextureNormals = tex; }
|
void setTextureNormals(osg::ref_ptr<osg::Texture> tex) { mTextureNormals = tex; }
|
||||||
|
|
||||||
|
void setTextureDistortion(osg::ref_ptr<osg::Texture> tex) { mTextureDistortion = tex; }
|
||||||
|
|
||||||
void setCalculateAvgLum(bool enabled) { mAvgLum = enabled; }
|
void setCalculateAvgLum(bool enabled) { mAvgLum = enabled; }
|
||||||
|
|
||||||
void setPostProcessing(bool enabled) { mPostprocessing = enabled; }
|
void setPostProcessing(bool enabled) { mPostprocessing = enabled; }
|
||||||
|
@ -69,6 +71,7 @@ namespace MWRender
|
||||||
osg::ref_ptr<osg::Texture> mTextureScene;
|
osg::ref_ptr<osg::Texture> mTextureScene;
|
||||||
osg::ref_ptr<osg::Texture> mTextureDepth;
|
osg::ref_ptr<osg::Texture> mTextureDepth;
|
||||||
osg::ref_ptr<osg::Texture> mTextureNormals;
|
osg::ref_ptr<osg::Texture> mTextureNormals;
|
||||||
|
osg::ref_ptr<osg::Texture> mTextureDistortion;
|
||||||
|
|
||||||
mutable bool mDirty = false;
|
mutable bool mDirty = false;
|
||||||
mutable std::vector<fx::Types::RenderTarget> mDirtyAttachments;
|
mutable std::vector<fx::Types::RenderTarget> mDirtyAttachments;
|
||||||
|
|
|
@ -29,7 +29,9 @@
|
||||||
|
|
||||||
#include "../mwgui/postprocessorhud.hpp"
|
#include "../mwgui/postprocessorhud.hpp"
|
||||||
|
|
||||||
|
#include "distortion.hpp"
|
||||||
#include "pingpongcull.hpp"
|
#include "pingpongcull.hpp"
|
||||||
|
#include "renderbin.hpp"
|
||||||
#include "renderingmanager.hpp"
|
#include "renderingmanager.hpp"
|
||||||
#include "sky.hpp"
|
#include "sky.hpp"
|
||||||
#include "transparentpass.hpp"
|
#include "transparentpass.hpp"
|
||||||
|
@ -103,6 +105,8 @@ namespace
|
||||||
|
|
||||||
return Stereo::createMultiviewCompatibleAttachment(texture);
|
return Stereo::createMultiviewCompatibleAttachment(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr float DistortionRatio = 0.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -118,6 +122,7 @@ namespace MWRender
|
||||||
, mUsePostProcessing(Settings::postProcessing().mEnabled)
|
, mUsePostProcessing(Settings::postProcessing().mEnabled)
|
||||||
, mSamples(Settings::video().mAntialiasing)
|
, mSamples(Settings::video().mAntialiasing)
|
||||||
, mPingPongCull(new PingPongCull(this))
|
, mPingPongCull(new PingPongCull(this))
|
||||||
|
, mDistortionCallback(new DistortionCallback)
|
||||||
{
|
{
|
||||||
auto& shaderManager = mRendering.getResourceSystem()->getSceneManager()->getShaderManager();
|
auto& shaderManager = mRendering.getResourceSystem()->getSceneManager()->getShaderManager();
|
||||||
|
|
||||||
|
@ -141,18 +146,45 @@ namespace MWRender
|
||||||
mHUDCamera->setCullCallback(new HUDCullCallback);
|
mHUDCamera->setCullCallback(new HUDCullCallback);
|
||||||
mViewer->getCamera()->addCullCallback(mPingPongCull);
|
mViewer->getCamera()->addCullCallback(mPingPongCull);
|
||||||
|
|
||||||
if (Settings::shaders().mSoftParticles || Settings::postProcessing().mTransparentPostpass)
|
// resolves the multisampled depth buffer and optionally draws an additional depth postpass
|
||||||
{
|
mTransparentDepthPostPass
|
||||||
mTransparentDepthPostPass
|
= new TransparentDepthBinCallback(mRendering.getResourceSystem()->getSceneManager()->getShaderManager(),
|
||||||
= new TransparentDepthBinCallback(shaderManager, Settings::postProcessing().mTransparentPostpass);
|
Settings::postProcessing().mTransparentPostpass);
|
||||||
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass);
|
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass);
|
||||||
}
|
|
||||||
|
osg::ref_ptr<osgUtil::RenderBin> distortionRenderBin
|
||||||
|
= new osgUtil::RenderBin(osgUtil::RenderBin::SORT_BACK_TO_FRONT);
|
||||||
|
// This is silly to have to do, but if nothing is drawn then the drawcallback is never called and the distortion
|
||||||
|
// texture will never be cleared
|
||||||
|
osg::ref_ptr<osg::Node> dummyNodeToClear = new osg::Node;
|
||||||
|
dummyNodeToClear->setCullingActive(false);
|
||||||
|
dummyNodeToClear->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Distortion, "Distortion");
|
||||||
|
rootNode->addChild(dummyNodeToClear);
|
||||||
|
distortionRenderBin->setDrawCallback(mDistortionCallback);
|
||||||
|
distortionRenderBin->getStateSet()->setDefine("DISTORTION", "1", osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
// Give the renderbin access to the opaque depth sampler so it can write its occlusion
|
||||||
|
// Distorted geometry is drawn with ALWAYS depth function and depths writes disbled.
|
||||||
|
const int unitSoftEffect
|
||||||
|
= shaderManager.reserveGlobalTextureUnits(Shader::ShaderManager::Slot::OpaqueDepthTexture);
|
||||||
|
distortionRenderBin->getStateSet()->addUniform(new osg::Uniform("opaqueDepthTex", unitSoftEffect));
|
||||||
|
|
||||||
|
osgUtil::RenderBin::addRenderBinPrototype("Distortion", distortionRenderBin);
|
||||||
|
|
||||||
|
auto defines = shaderManager.getGlobalDefines();
|
||||||
|
defines["distorionRTRatio"] = std::to_string(DistortionRatio);
|
||||||
|
shaderManager.setGlobalDefines(defines);
|
||||||
|
|
||||||
createObjectsForFrame(0);
|
createObjectsForFrame(0);
|
||||||
createObjectsForFrame(1);
|
createObjectsForFrame(1);
|
||||||
|
|
||||||
populateTechniqueFiles();
|
populateTechniqueFiles();
|
||||||
|
|
||||||
|
auto distortion = loadTechnique("internal_distortion");
|
||||||
|
distortion->setInternal(true);
|
||||||
|
distortion->setLocked(true);
|
||||||
|
mInternalTechniques.push_back(distortion);
|
||||||
|
|
||||||
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>();
|
||||||
|
|
||||||
|
@ -171,19 +203,6 @@ namespace MWRender
|
||||||
else
|
else
|
||||||
Log(Debug::Error) << "'glDisablei' unsupported, pass normals will not be available to shaders.";
|
Log(Debug::Error) << "'glDisablei' unsupported, pass normals will not be available to shaders.";
|
||||||
|
|
||||||
if (Settings::shaders().mSoftParticles)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 2; ++i)
|
|
||||||
{
|
|
||||||
if (Stereo::getMultiview())
|
|
||||||
mTextures[i][Tex_OpaqueDepth] = new osg::Texture2DArray;
|
|
||||||
else
|
|
||||||
mTextures[i][Tex_OpaqueDepth] = new osg::Texture2D;
|
|
||||||
mTextures[i][Tex_OpaqueDepth]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
|
||||||
mTextures[i][Tex_OpaqueDepth]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mGLSLVersion = ext->glslLanguageVersion * 100;
|
mGLSLVersion = ext->glslLanguageVersion * 100;
|
||||||
mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
|
mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
|
||||||
mStateUpdater = new fx::StateUpdater(mUBO);
|
mStateUpdater = new fx::StateUpdater(mUBO);
|
||||||
|
@ -281,17 +300,15 @@ namespace MWRender
|
||||||
mCanvases[frameId]->setCalculateAvgLum(mHDR);
|
mCanvases[frameId]->setCalculateAvgLum(mHDR);
|
||||||
|
|
||||||
mCanvases[frameId]->setTextureScene(getTexture(Tex_Scene, frameId));
|
mCanvases[frameId]->setTextureScene(getTexture(Tex_Scene, frameId));
|
||||||
if (mTransparentDepthPostPass)
|
mCanvases[frameId]->setTextureDepth(getTexture(Tex_OpaqueDepth, frameId));
|
||||||
mCanvases[frameId]->setTextureDepth(getTexture(Tex_OpaqueDepth, frameId));
|
mCanvases[frameId]->setTextureDistortion(getTexture(Tex_Distortion, frameId));
|
||||||
else
|
|
||||||
mCanvases[frameId]->setTextureDepth(getTexture(Tex_Depth, frameId));
|
|
||||||
|
|
||||||
if (mTransparentDepthPostPass)
|
mTransparentDepthPostPass->mFbo[frameId] = mFbos[frameId][FBO_Primary];
|
||||||
{
|
mTransparentDepthPostPass->mMsaaFbo[frameId] = mFbos[frameId][FBO_Multisample];
|
||||||
mTransparentDepthPostPass->mFbo[frameId] = mFbos[frameId][FBO_Primary];
|
mTransparentDepthPostPass->mOpaqueFbo[frameId] = mFbos[frameId][FBO_OpaqueDepth];
|
||||||
mTransparentDepthPostPass->mMsaaFbo[frameId] = mFbos[frameId][FBO_Multisample];
|
|
||||||
mTransparentDepthPostPass->mOpaqueFbo[frameId] = mFbos[frameId][FBO_OpaqueDepth];
|
mDistortionCallback->setFBO(mFbos[frameId][FBO_Distortion], frameId);
|
||||||
}
|
mDistortionCallback->setOriginalFBO(mFbos[frameId][FBO_Primary], frameId);
|
||||||
|
|
||||||
size_t frame = cv->getTraversalNumber();
|
size_t frame = cv->getTraversalNumber();
|
||||||
|
|
||||||
|
@ -441,6 +458,13 @@ namespace MWRender
|
||||||
textures[Tex_Normal]->setSourceFormat(GL_RGB);
|
textures[Tex_Normal]->setSourceFormat(GL_RGB);
|
||||||
textures[Tex_Normal]->setInternalFormat(GL_RGB);
|
textures[Tex_Normal]->setInternalFormat(GL_RGB);
|
||||||
|
|
||||||
|
textures[Tex_Distortion]->setSourceFormat(GL_RGB);
|
||||||
|
textures[Tex_Distortion]->setInternalFormat(GL_RGB);
|
||||||
|
|
||||||
|
Stereo::setMultiviewCompatibleTextureSize(
|
||||||
|
textures[Tex_Distortion], width * DistortionRatio, height * DistortionRatio);
|
||||||
|
textures[Tex_Distortion]->dirtyTextureObject();
|
||||||
|
|
||||||
auto setupDepth = [](osg::Texture* tex) {
|
auto setupDepth = [](osg::Texture* tex) {
|
||||||
tex->setSourceFormat(GL_DEPTH_STENCIL_EXT);
|
tex->setSourceFormat(GL_DEPTH_STENCIL_EXT);
|
||||||
tex->setSourceType(SceneUtil::AutoDepth::depthSourceType());
|
tex->setSourceType(SceneUtil::AutoDepth::depthSourceType());
|
||||||
|
@ -448,16 +472,8 @@ namespace MWRender
|
||||||
};
|
};
|
||||||
|
|
||||||
setupDepth(textures[Tex_Depth]);
|
setupDepth(textures[Tex_Depth]);
|
||||||
|
setupDepth(textures[Tex_OpaqueDepth]);
|
||||||
if (!mTransparentDepthPostPass)
|
textures[Tex_OpaqueDepth]->setName("opaqueTexMap");
|
||||||
{
|
|
||||||
textures[Tex_OpaqueDepth] = nullptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setupDepth(textures[Tex_OpaqueDepth]);
|
|
||||||
textures[Tex_OpaqueDepth]->setName("opaqueTexMap");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& fbos = mFbos[frameId];
|
auto& fbos = mFbos[frameId];
|
||||||
|
|
||||||
|
@ -487,6 +503,7 @@ namespace MWRender
|
||||||
auto normalRB = createFrameBufferAttachmentFromTemplate(
|
auto normalRB = createFrameBufferAttachmentFromTemplate(
|
||||||
Usage::RENDER_BUFFER, width, height, textures[Tex_Normal], mSamples);
|
Usage::RENDER_BUFFER, width, height, textures[Tex_Normal], mSamples);
|
||||||
fbos[FBO_Multisample]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, normalRB);
|
fbos[FBO_Multisample]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, normalRB);
|
||||||
|
fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, normalRB);
|
||||||
}
|
}
|
||||||
auto depthRB = createFrameBufferAttachmentFromTemplate(
|
auto depthRB = createFrameBufferAttachmentFromTemplate(
|
||||||
Usage::RENDER_BUFFER, width, height, textures[Tex_Depth], mSamples);
|
Usage::RENDER_BUFFER, width, height, textures[Tex_Depth], mSamples);
|
||||||
|
@ -510,12 +527,13 @@ namespace MWRender
|
||||||
Stereo::createMultiviewCompatibleAttachment(textures[Tex_Normal]));
|
Stereo::createMultiviewCompatibleAttachment(textures[Tex_Normal]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textures[Tex_OpaqueDepth])
|
fbos[FBO_OpaqueDepth] = new osg::FrameBufferObject;
|
||||||
{
|
fbos[FBO_OpaqueDepth]->setAttachment(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER,
|
||||||
fbos[FBO_OpaqueDepth] = new osg::FrameBufferObject;
|
Stereo::createMultiviewCompatibleAttachment(textures[Tex_OpaqueDepth]));
|
||||||
fbos[FBO_OpaqueDepth]->setAttachment(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER,
|
|
||||||
Stereo::createMultiviewCompatibleAttachment(textures[Tex_OpaqueDepth]));
|
fbos[FBO_Distortion] = new osg::FrameBufferObject;
|
||||||
}
|
fbos[FBO_Distortion]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0,
|
||||||
|
Stereo::createMultiviewCompatibleAttachment(textures[Tex_Distortion]));
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (textures[Tex_OpaqueDepth])
|
if (textures[Tex_OpaqueDepth])
|
||||||
|
@ -575,6 +593,7 @@ namespace MWRender
|
||||||
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerLastShader", Unit_LastShader));
|
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerLastShader", Unit_LastShader));
|
||||||
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerLastPass", Unit_LastPass));
|
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerLastPass", Unit_LastPass));
|
||||||
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerDepth", Unit_Depth));
|
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerDepth", Unit_Depth));
|
||||||
|
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerDistortion", Unit_Distortion));
|
||||||
|
|
||||||
if (mNormals)
|
if (mNormals)
|
||||||
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerNormals", Unit_Normals));
|
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerNormals", Unit_Normals));
|
||||||
|
@ -582,6 +601,8 @@ namespace MWRender
|
||||||
if (technique->getHDR())
|
if (technique->getHDR())
|
||||||
node.mRootStateSet->addUniform(new osg::Uniform("omw_EyeAdaptation", Unit_EyeAdaptation));
|
node.mRootStateSet->addUniform(new osg::Uniform("omw_EyeAdaptation", Unit_EyeAdaptation));
|
||||||
|
|
||||||
|
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerDistortion", Unit_Distortion));
|
||||||
|
|
||||||
int texUnit = Unit_NextFree;
|
int texUnit = Unit_NextFree;
|
||||||
|
|
||||||
// user-defined samplers
|
// user-defined samplers
|
||||||
|
@ -681,7 +702,7 @@ namespace MWRender
|
||||||
|
|
||||||
disableTechnique(technique, false);
|
disableTechnique(technique, false);
|
||||||
|
|
||||||
int pos = std::min<int>(location.value_or(mTechniques.size()), mTechniques.size());
|
int pos = std::min<int>(location.value_or(mTechniques.size()) + mInternalTechniques.size(), mTechniques.size());
|
||||||
|
|
||||||
mTechniques.insert(mTechniques.begin() + pos, technique);
|
mTechniques.insert(mTechniques.begin() + pos, technique);
|
||||||
dirtyTechniques(Settings::ShaderManager::get().getMode() == Settings::ShaderManager::Mode::Debug);
|
dirtyTechniques(Settings::ShaderManager::get().getMode() == Settings::ShaderManager::Mode::Debug);
|
||||||
|
@ -747,6 +768,11 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
mTechniques.clear();
|
mTechniques.clear();
|
||||||
|
|
||||||
|
for (const auto& technique : mInternalTechniques)
|
||||||
|
{
|
||||||
|
mTechniques.push_back(technique);
|
||||||
|
}
|
||||||
|
|
||||||
for (const std::string& techniqueName : Settings::postProcessing().mChain.get())
|
for (const std::string& techniqueName : Settings::postProcessing().mChain.get())
|
||||||
{
|
{
|
||||||
if (techniqueName.empty())
|
if (techniqueName.empty())
|
||||||
|
@ -764,7 +790,7 @@ namespace MWRender
|
||||||
|
|
||||||
for (const auto& technique : mTechniques)
|
for (const auto& technique : mTechniques)
|
||||||
{
|
{
|
||||||
if (!technique || technique->getDynamic())
|
if (!technique || technique->getDynamic() || technique->getInternal())
|
||||||
continue;
|
continue;
|
||||||
chain.push_back(technique->getName());
|
chain.push_back(technique->getName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,12 +50,13 @@ namespace MWRender
|
||||||
class PingPongCull;
|
class PingPongCull;
|
||||||
class PingPongCanvas;
|
class PingPongCanvas;
|
||||||
class TransparentDepthBinCallback;
|
class TransparentDepthBinCallback;
|
||||||
|
class DistortionCallback;
|
||||||
|
|
||||||
class PostProcessor : public osg::Group
|
class PostProcessor : public osg::Group
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using FBOArray = std::array<osg::ref_ptr<osg::FrameBufferObject>, 5>;
|
using FBOArray = std::array<osg::ref_ptr<osg::FrameBufferObject>, 6>;
|
||||||
using TextureArray = std::array<osg::ref_ptr<osg::Texture>, 5>;
|
using TextureArray = std::array<osg::ref_ptr<osg::Texture>, 6>;
|
||||||
using TechniqueList = std::vector<std::shared_ptr<fx::Technique>>;
|
using TechniqueList = std::vector<std::shared_ptr<fx::Technique>>;
|
||||||
|
|
||||||
enum TextureIndex
|
enum TextureIndex
|
||||||
|
@ -64,7 +65,8 @@ namespace MWRender
|
||||||
Tex_Scene_LDR,
|
Tex_Scene_LDR,
|
||||||
Tex_Depth,
|
Tex_Depth,
|
||||||
Tex_OpaqueDepth,
|
Tex_OpaqueDepth,
|
||||||
Tex_Normal
|
Tex_Normal,
|
||||||
|
Tex_Distortion,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FBOIndex
|
enum FBOIndex
|
||||||
|
@ -73,7 +75,8 @@ namespace MWRender
|
||||||
FBO_Multisample,
|
FBO_Multisample,
|
||||||
FBO_FirstPerson,
|
FBO_FirstPerson,
|
||||||
FBO_OpaqueDepth,
|
FBO_OpaqueDepth,
|
||||||
FBO_Intercept
|
FBO_Intercept,
|
||||||
|
FBO_Distortion,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TextureUnits
|
enum TextureUnits
|
||||||
|
@ -83,6 +86,7 @@ namespace MWRender
|
||||||
Unit_Depth,
|
Unit_Depth,
|
||||||
Unit_EyeAdaptation,
|
Unit_EyeAdaptation,
|
||||||
Unit_Normals,
|
Unit_Normals,
|
||||||
|
Unit_Distortion,
|
||||||
Unit_NextFree
|
Unit_NextFree
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -223,6 +227,7 @@ namespace MWRender
|
||||||
TechniqueList mTechniques;
|
TechniqueList mTechniques;
|
||||||
TechniqueList mTemplates;
|
TechniqueList mTemplates;
|
||||||
TechniqueList mQueuedTemplates;
|
TechniqueList mQueuedTemplates;
|
||||||
|
TechniqueList mInternalTechniques;
|
||||||
|
|
||||||
std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap;
|
std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap;
|
||||||
|
|
||||||
|
@ -258,6 +263,7 @@ namespace MWRender
|
||||||
osg::ref_ptr<PingPongCull> mPingPongCull;
|
osg::ref_ptr<PingPongCull> mPingPongCull;
|
||||||
std::array<osg::ref_ptr<PingPongCanvas>, 2> mCanvases;
|
std::array<osg::ref_ptr<PingPongCanvas>, 2> mCanvases;
|
||||||
osg::ref_ptr<TransparentDepthBinCallback> mTransparentDepthPostPass;
|
osg::ref_ptr<TransparentDepthBinCallback> mTransparentDepthPostPass;
|
||||||
|
osg::ref_ptr<DistortionCallback> mDistortionCallback;
|
||||||
|
|
||||||
fx::DispatchArray mTemplateData;
|
fx::DispatchArray mTemplateData;
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace MWRender
|
||||||
RenderBin_DepthSorted = 10, // osg::StateSet::TRANSPARENT_BIN
|
RenderBin_DepthSorted = 10, // osg::StateSet::TRANSPARENT_BIN
|
||||||
RenderBin_OcclusionQuery = 11,
|
RenderBin_OcclusionQuery = 11,
|
||||||
RenderBin_FirstPerson = 12,
|
RenderBin_FirstPerson = 12,
|
||||||
RenderBin_SunGlare = 13
|
RenderBin_SunGlare = 13,
|
||||||
|
RenderBin_Distortion = 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -502,6 +502,7 @@ namespace MWRender
|
||||||
sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat);
|
sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat);
|
||||||
sceneRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("emissiveMult", 1.f));
|
sceneRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("emissiveMult", 1.f));
|
||||||
sceneRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("specStrength", 1.f));
|
sceneRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("specStrength", 1.f));
|
||||||
|
sceneRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("distortionStrength", 0.f));
|
||||||
|
|
||||||
mFog = std::make_unique<FogManager>();
|
mFog = std::make_unique<FogManager>();
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,7 @@ uniform @builtinSampler omw_SamplerLastShader;
|
||||||
uniform @builtinSampler omw_SamplerLastPass;
|
uniform @builtinSampler omw_SamplerLastPass;
|
||||||
uniform @builtinSampler omw_SamplerDepth;
|
uniform @builtinSampler omw_SamplerDepth;
|
||||||
uniform @builtinSampler omw_SamplerNormals;
|
uniform @builtinSampler omw_SamplerNormals;
|
||||||
|
uniform @builtinSampler omw_SamplerDistortion;
|
||||||
|
|
||||||
uniform vec4 omw_PointLights[@pointLightCount];
|
uniform vec4 omw_PointLights[@pointLightCount];
|
||||||
uniform int omw_PointLightsCount;
|
uniform int omw_PointLightsCount;
|
||||||
|
|
|
@ -175,6 +175,9 @@ namespace fx
|
||||||
void setLocked(bool locked) { mLocked = locked; }
|
void setLocked(bool locked) { mLocked = locked; }
|
||||||
bool getLocked() const { return mLocked; }
|
bool getLocked() const { return mLocked; }
|
||||||
|
|
||||||
|
void setInternal(bool internal) { mInternal = internal; }
|
||||||
|
bool getInternal() const { return mInternal; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[noreturn]] void error(const std::string& msg);
|
[[noreturn]] void error(const std::string& msg);
|
||||||
|
|
||||||
|
@ -295,6 +298,7 @@ namespace fx
|
||||||
|
|
||||||
bool mDynamic = false;
|
bool mDynamic = false;
|
||||||
bool mLocked = false;
|
bool mLocked = false;
|
||||||
|
bool mInternal = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
|
@ -108,6 +108,8 @@ namespace Nif
|
||||||
enum BSShaderFlags1
|
enum BSShaderFlags1
|
||||||
{
|
{
|
||||||
BSSFlag1_Specular = 0x00000001,
|
BSSFlag1_Specular = 0x00000001,
|
||||||
|
BSSFlag1_Refraction = 0x00008000,
|
||||||
|
BSSFlag1_FireRefraction = 0x00010000,
|
||||||
BSSFlag1_Decal = 0x04000000,
|
BSSFlag1_Decal = 0x04000000,
|
||||||
BSSFlag1_DepthTest = 0x80000000,
|
BSSFlag1_DepthTest = 0x80000000,
|
||||||
};
|
};
|
||||||
|
@ -148,6 +150,8 @@ namespace Nif
|
||||||
bool decal() const { return mShaderFlags1 & BSSFlag1_Decal; }
|
bool decal() const { return mShaderFlags1 & BSSFlag1_Decal; }
|
||||||
bool depthTest() const { return mShaderFlags1 & BSSFlag1_DepthTest; }
|
bool depthTest() const { return mShaderFlags1 & BSSFlag1_DepthTest; }
|
||||||
bool depthWrite() const { return mShaderFlags2 & BSSFlag2_DepthWrite; }
|
bool depthWrite() const { return mShaderFlags2 & BSSFlag2_DepthWrite; }
|
||||||
|
bool refraction() const { return mShaderFlags1 & BSSFlag1_Refraction; }
|
||||||
|
bool fireRefraction() const { return mShaderFlags1 & BSSFlag1_FireRefraction; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BSShaderLightingProperty : BSShaderProperty
|
struct BSShaderLightingProperty : BSShaderProperty
|
||||||
|
|
|
@ -2381,6 +2381,8 @@ namespace NifOsg
|
||||||
textureSet, texprop->mClamp, node->getName(), stateset, imageManager, boundTextures);
|
textureSet, texprop->mClamp, node->getName(), stateset, imageManager, boundTextures);
|
||||||
}
|
}
|
||||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
||||||
|
if (texprop->refraction())
|
||||||
|
SceneUtil::setupDistortion(*node, texprop->mRefraction.mStrength);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Nif::RC_BSShaderNoLightingProperty:
|
case Nif::RC_BSShaderNoLightingProperty:
|
||||||
|
@ -2438,6 +2440,8 @@ namespace NifOsg
|
||||||
if (texprop->treeAnim())
|
if (texprop->treeAnim())
|
||||||
stateset->addUniform(new osg::Uniform("useTreeAnim", true));
|
stateset->addUniform(new osg::Uniform("useTreeAnim", true));
|
||||||
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
||||||
|
if (texprop->refraction())
|
||||||
|
SceneUtil::setupDistortion(*node, texprop->mRefractionStrength);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Nif::RC_BSEffectShaderProperty:
|
case Nif::RC_BSEffectShaderProperty:
|
||||||
|
|
|
@ -649,6 +649,7 @@ namespace Resource
|
||||||
node->getOrCreateStateSet()->addUniform(new osg::Uniform("specStrength", 1.f));
|
node->getOrCreateStateSet()->addUniform(new osg::Uniform("specStrength", 1.f));
|
||||||
node->getOrCreateStateSet()->addUniform(new osg::Uniform("envMapColor", osg::Vec4f(1, 1, 1, 1)));
|
node->getOrCreateStateSet()->addUniform(new osg::Uniform("envMapColor", osg::Vec4f(1, 1, 1, 1)));
|
||||||
node->getOrCreateStateSet()->addUniform(new osg::Uniform("useFalloff", false));
|
node->getOrCreateStateSet()->addUniform(new osg::Uniform("useFalloff", false));
|
||||||
|
node->getOrCreateStateSet()->addUniform(new osg::Uniform("distortionStrength", 0.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
node->setUserValue(Misc::OsgUserValues::sFileHash,
|
node->setUserValue(Misc::OsgUserValues::sFileHash,
|
||||||
|
|
|
@ -29,6 +29,19 @@ namespace SceneUtil
|
||||||
node.setUserValue(Misc::OsgUserValues::sXSoftEffect, true);
|
node.setUserValue(Misc::OsgUserValues::sXSoftEffect, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setupDistortion(osg::Node& node, float distortionStrength)
|
||||||
|
{
|
||||||
|
static const osg::ref_ptr<SceneUtil::AutoDepth> depth
|
||||||
|
= new SceneUtil::AutoDepth(osg::Depth::ALWAYS, 0, 1, false);
|
||||||
|
|
||||||
|
osg::StateSet* stateset = node.getOrCreateStateSet();
|
||||||
|
|
||||||
|
stateset->setRenderBinDetails(14, "Distortion", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
|
||||||
|
stateset->addUniform(new osg::Uniform("distortionStrength", distortionStrength));
|
||||||
|
|
||||||
|
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessExtraDataVisitor::apply(osg::Node& node)
|
void ProcessExtraDataVisitor::apply(osg::Node& node)
|
||||||
{
|
{
|
||||||
if (!mSceneMgr->getSoftParticles())
|
if (!mSceneMgr->getSoftParticles())
|
||||||
|
@ -54,6 +67,12 @@ namespace SceneUtil
|
||||||
|
|
||||||
setupSoftEffect(node, size, falloff, falloffDepth);
|
setupSoftEffect(node, size, falloff, falloffDepth);
|
||||||
}
|
}
|
||||||
|
else if (key == "distortion")
|
||||||
|
{
|
||||||
|
auto strength = it.second["strength"].as<float>(0.1f);
|
||||||
|
|
||||||
|
setupDistortion(node, strength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.setUserValue(Misc::OsgUserValues::sExtraData, std::string{});
|
node.setUserValue(Misc::OsgUserValues::sExtraData, std::string{});
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace osg
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
void setupSoftEffect(osg::Node& node, float size, bool falloff, float falloffDepth);
|
void setupSoftEffect(osg::Node& node, float size, bool falloff, float falloffDepth);
|
||||||
|
void setupDistortion(osg::Node& node, float distortionStrength);
|
||||||
|
|
||||||
class ProcessExtraDataVisitor : public osg::NodeVisitor
|
class ProcessExtraDataVisitor : public osg::NodeVisitor
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,3 +54,38 @@ Example usage.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Distortion
|
||||||
|
----------
|
||||||
|
|
||||||
|
This effect is used to imitate effects such as refraction and heat distortion. A common use case is to assign a normal map to the
|
||||||
|
diffuse slot to a material and add uv scrolling. The red and green channels of the texture are used to offset the final scene texture.
|
||||||
|
Blue and alpha channels are ignored.
|
||||||
|
|
||||||
|
To use this feature the :ref:`post processing` setting must be enabled.
|
||||||
|
This setting can either be activated in the OpenMW launcher, in-game, or changed in `settings.cfg`:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
[Post Processing]
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
Variables.
|
||||||
|
|
||||||
|
+---------+--------------------------------------------------------------------------------------------------------+---------+---------+
|
||||||
|
| Name | Description | Type | Default |
|
||||||
|
+---------+--------------------------------------------------------------------------------------------------------+---------+---------+
|
||||||
|
| strength| The strength of the distortion effect. Scales linearly. | float | 0.1 |
|
||||||
|
+---------+--------------------------------------------------------------------------------------------------------+---------+---------+
|
||||||
|
|
||||||
|
Example usage.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
omw:data {
|
||||||
|
"shader" : {
|
||||||
|
"distortion" : {
|
||||||
|
"strength": 0.12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -96,6 +96,7 @@ set(BUILTIN_DATA_FILES
|
||||||
shaders/adjustments.omwfx
|
shaders/adjustments.omwfx
|
||||||
shaders/bloomlinear.omwfx
|
shaders/bloomlinear.omwfx
|
||||||
shaders/debug.omwfx
|
shaders/debug.omwfx
|
||||||
|
shaders/internal_distortion.omwfx
|
||||||
|
|
||||||
mygui/core.skin
|
mygui/core.skin
|
||||||
mygui/core.xml
|
mygui/core.xml
|
||||||
|
|
25
files/data/shaders/internal_distortion.omwfx
Normal file
25
files/data/shaders/internal_distortion.omwfx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
fragment main {
|
||||||
|
|
||||||
|
omw_In vec2 omw_TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
const float multiplier = 0.14;
|
||||||
|
|
||||||
|
vec2 offset = omw_Texture2D(omw_SamplerDistortion, omw_TexCoord).rg;
|
||||||
|
offset *= multiplier;
|
||||||
|
offset = clamp(offset, vec2(-1.0), vec2(1.0));
|
||||||
|
|
||||||
|
float occlusionFactor = omw_Texture2D(omw_SamplerDistortion, omw_TexCoord+offset).b;
|
||||||
|
|
||||||
|
omw_FragColor = mix(omw_GetLastShader(omw_TexCoord + offset), omw_GetLastShader(omw_TexCoord), occlusionFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
technique {
|
||||||
|
description = "Internal refraction shader for OpenMW";
|
||||||
|
version = "1.0";
|
||||||
|
author = "OpenMW";
|
||||||
|
passes = main;
|
||||||
|
flags = hidden;
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ set(SHADER_FILES
|
||||||
lib/particle/occlusion.glsl
|
lib/particle/occlusion.glsl
|
||||||
lib/util/quickstep.glsl
|
lib/util/quickstep.glsl
|
||||||
lib/util/coordinates.glsl
|
lib/util/coordinates.glsl
|
||||||
|
lib/util/distortion.glsl
|
||||||
lib/core/fragment.glsl
|
lib/core/fragment.glsl
|
||||||
lib/core/fragment.h.glsl
|
lib/core/fragment.h.glsl
|
||||||
lib/core/fragment_multiview.glsl
|
lib/core/fragment_multiview.glsl
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#version 120
|
#version 120
|
||||||
#pragma import_defines(FORCE_OPAQUE)
|
#pragma import_defines(FORCE_OPAQUE, DISTORTION)
|
||||||
|
|
||||||
#if @useUBO
|
#if @useUBO
|
||||||
#extension GL_ARB_uniform_buffer_object : require
|
#extension GL_ARB_uniform_buffer_object : require
|
||||||
|
@ -26,6 +26,8 @@ uniform sampler2D normalMap;
|
||||||
varying vec2 normalMapUV;
|
varying vec2 normalMapUV;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
uniform sampler2D opaqueDepthTex;
|
||||||
|
|
||||||
varying float euclideanDepth;
|
varying float euclideanDepth;
|
||||||
varying float linearDepth;
|
varying float linearDepth;
|
||||||
|
|
||||||
|
@ -38,9 +40,11 @@ uniform float alphaRef;
|
||||||
uniform float emissiveMult;
|
uniform float emissiveMult;
|
||||||
uniform float specStrength;
|
uniform float specStrength;
|
||||||
uniform bool useTreeAnim;
|
uniform bool useTreeAnim;
|
||||||
|
uniform float distortionStrength;
|
||||||
|
|
||||||
#include "lib/light/lighting.glsl"
|
#include "lib/light/lighting.glsl"
|
||||||
#include "lib/material/alpha.glsl"
|
#include "lib/material/alpha.glsl"
|
||||||
|
#include "lib/util/distortion.glsl"
|
||||||
|
|
||||||
#include "compatibility/vertexcolors.glsl"
|
#include "compatibility/vertexcolors.glsl"
|
||||||
#include "compatibility/shadows_fragment.glsl"
|
#include "compatibility/shadows_fragment.glsl"
|
||||||
|
@ -51,6 +55,15 @@ void main()
|
||||||
{
|
{
|
||||||
#if @diffuseMap
|
#if @diffuseMap
|
||||||
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV);
|
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV);
|
||||||
|
|
||||||
|
#if defined(DISTORTION) && DISTORTION
|
||||||
|
vec2 screenCoords = gl_FragCoord.xy / (screenRes * @distorionRTRatio);
|
||||||
|
gl_FragData[0].a = getDiffuseColor().a;
|
||||||
|
gl_FragData[0] = applyDistortion(gl_FragData[0], distortionStrength, gl_FragCoord.z, texture2D(opaqueDepthTex, screenCoords).x);
|
||||||
|
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
gl_FragData[0].a *= coveragePreservingAlphaScale(diffuseMap, diffuseMapUV);
|
gl_FragData[0].a *= coveragePreservingAlphaScale(diffuseMap, diffuseMapUV);
|
||||||
#else
|
#else
|
||||||
gl_FragData[0] = vec4(1.0);
|
gl_FragData[0] = vec4(1.0);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#version 120
|
#version 120
|
||||||
#pragma import_defines(FORCE_OPAQUE)
|
#pragma import_defines(FORCE_OPAQUE, DISTORTION)
|
||||||
|
|
||||||
#if @useUBO
|
#if @useUBO
|
||||||
#extension GL_ARB_uniform_buffer_object : require
|
#extension GL_ARB_uniform_buffer_object : require
|
||||||
|
@ -66,6 +66,7 @@ uniform vec2 screenRes;
|
||||||
uniform float near;
|
uniform float near;
|
||||||
uniform float far;
|
uniform float far;
|
||||||
uniform float alphaRef;
|
uniform float alphaRef;
|
||||||
|
uniform float distortionStrength;
|
||||||
|
|
||||||
#define PER_PIXEL_LIGHTING (@normalMap || @specularMap || @forcePPL)
|
#define PER_PIXEL_LIGHTING (@normalMap || @specularMap || @forcePPL)
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ varying vec4 passTangent;
|
||||||
#include "lib/light/lighting.glsl"
|
#include "lib/light/lighting.glsl"
|
||||||
#include "lib/material/parallax.glsl"
|
#include "lib/material/parallax.glsl"
|
||||||
#include "lib/material/alpha.glsl"
|
#include "lib/material/alpha.glsl"
|
||||||
|
#include "lib/util/distortion.glsl"
|
||||||
|
|
||||||
#include "fog.glsl"
|
#include "fog.glsl"
|
||||||
#include "vertexcolors.glsl"
|
#include "vertexcolors.glsl"
|
||||||
|
@ -100,7 +102,6 @@ varying vec4 passTangent;
|
||||||
#if @softParticles
|
#if @softParticles
|
||||||
#include "lib/particle/soft.glsl"
|
#include "lib/particle/soft.glsl"
|
||||||
|
|
||||||
uniform sampler2D opaqueDepthTex;
|
|
||||||
uniform float particleSize;
|
uniform float particleSize;
|
||||||
uniform bool particleFade;
|
uniform bool particleFade;
|
||||||
uniform float softFalloffDepth;
|
uniform float softFalloffDepth;
|
||||||
|
@ -112,6 +113,8 @@ uniform sampler2D orthoDepthMap;
|
||||||
varying vec3 orthoDepthMapCoord;
|
varying vec3 orthoDepthMapCoord;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
uniform sampler2D opaqueDepthTex;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
#if @particleOcclusion
|
#if @particleOcclusion
|
||||||
|
@ -133,8 +136,17 @@ void main()
|
||||||
offset = getParallaxOffset(transpose(normalToViewMatrix) * normalize(-passViewPos), height, flipY);
|
offset = getParallaxOffset(transpose(normalToViewMatrix) * normalize(-passViewPos), height, flipY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
vec2 screenCoords = gl_FragCoord.xy / screenRes;
|
||||||
|
|
||||||
#if @diffuseMap
|
#if @diffuseMap
|
||||||
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV + offset);
|
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV + offset);
|
||||||
|
|
||||||
|
#if defined(DISTORTION) && DISTORTION
|
||||||
|
gl_FragData[0].a = getDiffuseColor().a;
|
||||||
|
gl_FragData[0] = applyDistortion(gl_FragData[0], distortionStrength, gl_FragCoord.z, texture2D(opaqueDepthTex, screenCoords / @distorionRTRatio).x);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if @diffuseParallax
|
#if @diffuseParallax
|
||||||
gl_FragData[0].a = 1.0;
|
gl_FragData[0].a = 1.0;
|
||||||
#else
|
#else
|
||||||
|
@ -234,7 +246,6 @@ void main()
|
||||||
|
|
||||||
gl_FragData[0] = applyFogAtPos(gl_FragData[0], passViewPos, far);
|
gl_FragData[0] = applyFogAtPos(gl_FragData[0], passViewPos, far);
|
||||||
|
|
||||||
vec2 screenCoords = gl_FragCoord.xy / screenRes;
|
|
||||||
#if !defined(FORCE_OPAQUE) && @softParticles
|
#if !defined(FORCE_OPAQUE) && @softParticles
|
||||||
gl_FragData[0].a *= calcSoftParticleFade(
|
gl_FragData[0].a *= calcSoftParticleFade(
|
||||||
viewVec,
|
viewVec,
|
||||||
|
|
32
files/shaders/lib/util/distortion.glsl
Normal file
32
files/shaders/lib/util/distortion.glsl
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef LIB_UTIL_DISTORTION
|
||||||
|
#define LIB_UTIL_DISTORTION
|
||||||
|
|
||||||
|
vec4 applyDistortion(in vec4 color, in float strength, in float pixelDepth, in float sceneDepth)
|
||||||
|
{
|
||||||
|
vec4 distortion = color;
|
||||||
|
float invOcclusion = 1.0;
|
||||||
|
|
||||||
|
// TODO: Investigate me. Alpha-clipping is enabled for refraction for what seems an arbitrary threshold, even when
|
||||||
|
// there are no associated NIF properties.
|
||||||
|
if (distortion.a < 0.1)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
distortion.b = 0.0;
|
||||||
|
|
||||||
|
#if @reverseZ
|
||||||
|
if (pixelDepth < sceneDepth)
|
||||||
|
#else
|
||||||
|
if (pixelDepth > sceneDepth)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
invOcclusion = 0.0;
|
||||||
|
distortion.b = 1.0;
|
||||||
|
}
|
||||||
|
distortion.rg = color.rg * 2.0 - 1.0;
|
||||||
|
|
||||||
|
distortion.rg *= invOcclusion * strength;
|
||||||
|
|
||||||
|
return distortion;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,8 +4,8 @@
|
||||||
float quickstep(float x)
|
float quickstep(float x)
|
||||||
{
|
{
|
||||||
x = clamp(x, 0.0, 1.0);
|
x = clamp(x, 0.0, 1.0);
|
||||||
x = 1.0 - x*x;
|
x = 1.0 - x * x;
|
||||||
x = 1.0 - x*x;
|
x = 1.0 - x * x;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue