support postprocess distortion

macos_ci_fix
Cody Glassman 6 months ago
parent 51cb3b08cb
commit 187f63d3d3

@ -24,7 +24,7 @@ add_openmw_dir (mwrender
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover
postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass precipitationocclusion ripples
actorutil
actorutil distortion
)
add_openmw_dir (mwinput

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

@ -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);
auto primaryFBO = postProcessor->getPrimaryFbo(frameId);
primaryFBO->apply(*state);
if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId))
postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state);
else
primaryFBO->apply(*state);
postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId)->apply(*state);
// depth accumulation pass
osg::ref_ptr<osg::StateSet> restore = bin->getStateSet();
@ -357,8 +355,7 @@ namespace MWRender
bin->drawImplementation(renderInfo, previous);
bin->setStateSet(restore);
if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId))
primaryFBO->apply(*state);
primaryFBO->apply(*state);
state->checkGLErrors("after DepthClearCallback::drawImplementation");
}

@ -242,6 +242,10 @@ namespace MWRender
if (mTextureNormals)
node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_Normals, mTextureNormals);
if (mTextureDistortion)
node.mRootStateSet->setTextureAttribute(
PostProcessor::TextureUnits::Unit_Distortion, mTextureDistortion);
state.pushStateSet(node.mRootStateSet);
state.apply();

@ -48,6 +48,8 @@ namespace MWRender
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 setPostProcessing(bool enabled) { mPostprocessing = enabled; }
@ -69,6 +71,7 @@ namespace MWRender
osg::ref_ptr<osg::Texture> mTextureScene;
osg::ref_ptr<osg::Texture> mTextureDepth;
osg::ref_ptr<osg::Texture> mTextureNormals;
osg::ref_ptr<osg::Texture> mTextureDistortion;
mutable bool mDirty = false;
mutable std::vector<fx::Types::RenderTarget> mDirtyAttachments;

@ -29,7 +29,9 @@
#include "../mwgui/postprocessorhud.hpp"
#include "distortion.hpp"
#include "pingpongcull.hpp"
#include "renderbin.hpp"
#include "renderingmanager.hpp"
#include "sky.hpp"
#include "transparentpass.hpp"
@ -103,6 +105,8 @@ namespace
return Stereo::createMultiviewCompatibleAttachment(texture);
}
constexpr float DistortionRatio = 0.25;
}
namespace MWRender
@ -118,6 +122,7 @@ namespace MWRender
, mUsePostProcessing(Settings::postProcessing().mEnabled)
, mSamples(Settings::video().mAntialiasing)
, mPingPongCull(new PingPongCull(this))
, mDistortionCallback(new DistortionCallback)
{
auto& shaderManager = mRendering.getResourceSystem()->getSceneManager()->getShaderManager();
@ -141,18 +146,45 @@ namespace MWRender
mHUDCamera->setCullCallback(new HUDCullCallback);
mViewer->getCamera()->addCullCallback(mPingPongCull);
if (Settings::shaders().mSoftParticles || Settings::postProcessing().mTransparentPostpass)
{
mTransparentDepthPostPass
= new TransparentDepthBinCallback(shaderManager, Settings::postProcessing().mTransparentPostpass);
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass);
}
// resolves the multisampled depth buffer and optionally draws an additional depth postpass
mTransparentDepthPostPass
= new TransparentDepthBinCallback(mRendering.getResourceSystem()->getSceneManager()->getShaderManager(),
Settings::postProcessing().mTransparentPostpass);
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(1);
populateTechniqueFiles();
auto distortion = loadTechnique("internal_distortion");
distortion->setInternal(true);
distortion->setLocked(true);
mInternalTechniques.push_back(distortion);
osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext();
osg::GLExtensions* ext = gc->getState()->get<osg::GLExtensions>();
@ -171,19 +203,6 @@ namespace MWRender
else
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;
mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
mStateUpdater = new fx::StateUpdater(mUBO);
@ -281,17 +300,15 @@ namespace MWRender
mCanvases[frameId]->setCalculateAvgLum(mHDR);
mCanvases[frameId]->setTextureScene(getTexture(Tex_Scene, frameId));
if (mTransparentDepthPostPass)
mCanvases[frameId]->setTextureDepth(getTexture(Tex_OpaqueDepth, frameId));
else
mCanvases[frameId]->setTextureDepth(getTexture(Tex_Depth, frameId));
mCanvases[frameId]->setTextureDepth(getTexture(Tex_OpaqueDepth, frameId));
mCanvases[frameId]->setTextureDistortion(getTexture(Tex_Distortion, frameId));
if (mTransparentDepthPostPass)
{
mTransparentDepthPostPass->mFbo[frameId] = mFbos[frameId][FBO_Primary];
mTransparentDepthPostPass->mMsaaFbo[frameId] = mFbos[frameId][FBO_Multisample];
mTransparentDepthPostPass->mOpaqueFbo[frameId] = mFbos[frameId][FBO_OpaqueDepth];
}
mTransparentDepthPostPass->mFbo[frameId] = mFbos[frameId][FBO_Primary];
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();
@ -441,6 +458,13 @@ namespace MWRender
textures[Tex_Normal]->setSourceFormat(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) {
tex->setSourceFormat(GL_DEPTH_STENCIL_EXT);
tex->setSourceType(SceneUtil::AutoDepth::depthSourceType());
@ -448,16 +472,8 @@ namespace MWRender
};
setupDepth(textures[Tex_Depth]);
if (!mTransparentDepthPostPass)
{
textures[Tex_OpaqueDepth] = nullptr;
}
else
{
setupDepth(textures[Tex_OpaqueDepth]);
textures[Tex_OpaqueDepth]->setName("opaqueTexMap");
}
setupDepth(textures[Tex_OpaqueDepth]);
textures[Tex_OpaqueDepth]->setName("opaqueTexMap");
auto& fbos = mFbos[frameId];
@ -487,6 +503,7 @@ namespace MWRender
auto normalRB = createFrameBufferAttachmentFromTemplate(
Usage::RENDER_BUFFER, width, height, textures[Tex_Normal], mSamples);
fbos[FBO_Multisample]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, normalRB);
fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, normalRB);
}
auto depthRB = createFrameBufferAttachmentFromTemplate(
Usage::RENDER_BUFFER, width, height, textures[Tex_Depth], mSamples);
@ -510,12 +527,13 @@ namespace MWRender
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,
Stereo::createMultiviewCompatibleAttachment(textures[Tex_OpaqueDepth]));
}
fbos[FBO_OpaqueDepth] = new osg::FrameBufferObject;
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__
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_SamplerLastPass", Unit_LastPass));
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerDepth", Unit_Depth));
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerDistortion", Unit_Distortion));
if (mNormals)
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerNormals", Unit_Normals));
@ -582,6 +601,8 @@ namespace MWRender
if (technique->getHDR())
node.mRootStateSet->addUniform(new osg::Uniform("omw_EyeAdaptation", Unit_EyeAdaptation));
node.mRootStateSet->addUniform(new osg::Uniform("omw_SamplerDistortion", Unit_Distortion));
int texUnit = Unit_NextFree;
// user-defined samplers
@ -681,7 +702,7 @@ namespace MWRender
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);
dirtyTechniques(Settings::ShaderManager::get().getMode() == Settings::ShaderManager::Mode::Debug);
@ -747,6 +768,11 @@ namespace MWRender
{
mTechniques.clear();
for (const auto& technique : mInternalTechniques)
{
mTechniques.push_back(technique);
}
for (const std::string& techniqueName : Settings::postProcessing().mChain.get())
{
if (techniqueName.empty())
@ -764,7 +790,7 @@ namespace MWRender
for (const auto& technique : mTechniques)
{
if (!technique || technique->getDynamic())
if (!technique || technique->getDynamic() || technique->getInternal())
continue;
chain.push_back(technique->getName());
}

@ -50,12 +50,13 @@ namespace MWRender
class PingPongCull;
class PingPongCanvas;
class TransparentDepthBinCallback;
class DistortionCallback;
class PostProcessor : public osg::Group
{
public:
using FBOArray = std::array<osg::ref_ptr<osg::FrameBufferObject>, 5>;
using TextureArray = std::array<osg::ref_ptr<osg::Texture>, 5>;
using FBOArray = std::array<osg::ref_ptr<osg::FrameBufferObject>, 6>;
using TextureArray = std::array<osg::ref_ptr<osg::Texture>, 6>;
using TechniqueList = std::vector<std::shared_ptr<fx::Technique>>;
enum TextureIndex
@ -64,7 +65,8 @@ namespace MWRender
Tex_Scene_LDR,
Tex_Depth,
Tex_OpaqueDepth,
Tex_Normal
Tex_Normal,
Tex_Distortion,
};
enum FBOIndex
@ -73,7 +75,8 @@ namespace MWRender
FBO_Multisample,
FBO_FirstPerson,
FBO_OpaqueDepth,
FBO_Intercept
FBO_Intercept,
FBO_Distortion,
};
enum TextureUnits
@ -83,6 +86,7 @@ namespace MWRender
Unit_Depth,
Unit_EyeAdaptation,
Unit_Normals,
Unit_Distortion,
Unit_NextFree
};
@ -223,6 +227,7 @@ namespace MWRender
TechniqueList mTechniques;
TechniqueList mTemplates;
TechniqueList mQueuedTemplates;
TechniqueList mInternalTechniques;
std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap;
@ -258,6 +263,7 @@ namespace MWRender
osg::ref_ptr<PingPongCull> mPingPongCull;
std::array<osg::ref_ptr<PingPongCanvas>, 2> mCanvases;
osg::ref_ptr<TransparentDepthBinCallback> mTransparentDepthPostPass;
osg::ref_ptr<DistortionCallback> mDistortionCallback;
fx::DispatchArray mTemplateData;
};

@ -13,7 +13,8 @@ namespace MWRender
RenderBin_DepthSorted = 10, // osg::StateSet::TRANSPARENT_BIN
RenderBin_OcclusionQuery = 11,
RenderBin_FirstPerson = 12,
RenderBin_SunGlare = 13
RenderBin_SunGlare = 13,
RenderBin_Distortion = 14,
};
}

@ -502,6 +502,7 @@ namespace MWRender
sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat);
sceneRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("emissiveMult", 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>();

@ -91,6 +91,7 @@ uniform @builtinSampler omw_SamplerLastShader;
uniform @builtinSampler omw_SamplerLastPass;
uniform @builtinSampler omw_SamplerDepth;
uniform @builtinSampler omw_SamplerNormals;
uniform @builtinSampler omw_SamplerDistortion;
uniform vec4 omw_PointLights[@pointLightCount];
uniform int omw_PointLightsCount;

@ -175,6 +175,9 @@ namespace fx
void setLocked(bool locked) { mLocked = locked; }
bool getLocked() const { return mLocked; }
void setInternal(bool internal) { mInternal = internal; }
bool getInternal() const { return mInternal; }
private:
[[noreturn]] void error(const std::string& msg);
@ -295,6 +298,7 @@ namespace fx
bool mDynamic = false;
bool mLocked = false;
bool mInternal = false;
};
template <>

@ -108,6 +108,8 @@ namespace Nif
enum BSShaderFlags1
{
BSSFlag1_Specular = 0x00000001,
BSSFlag1_Refraction = 0x00008000,
BSSFlag1_FireRefraction = 0x00010000,
BSSFlag1_Decal = 0x04000000,
BSSFlag1_DepthTest = 0x80000000,
};
@ -148,6 +150,8 @@ namespace Nif
bool decal() const { return mShaderFlags1 & BSSFlag1_Decal; }
bool depthTest() const { return mShaderFlags1 & BSSFlag1_DepthTest; }
bool depthWrite() const { return mShaderFlags2 & BSSFlag2_DepthWrite; }
bool refraction() const { return mShaderFlags1 & BSSFlag1_Refraction; }
bool fireRefraction() const { return mShaderFlags1 & BSSFlag1_FireRefraction; }
};
struct BSShaderLightingProperty : BSShaderProperty

@ -2381,6 +2381,8 @@ namespace NifOsg
textureSet, texprop->mClamp, node->getName(), stateset, imageManager, boundTextures);
}
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
if (texprop->refraction())
SceneUtil::setupDistortion(*node, texprop->mRefraction.mStrength);
break;
}
case Nif::RC_BSShaderNoLightingProperty:
@ -2438,6 +2440,8 @@ namespace NifOsg
if (texprop->treeAnim())
stateset->addUniform(new osg::Uniform("useTreeAnim", true));
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
if (texprop->refraction())
SceneUtil::setupDistortion(*node, texprop->mRefractionStrength);
break;
}
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("envMapColor", osg::Vec4f(1, 1, 1, 1)));
node->getOrCreateStateSet()->addUniform(new osg::Uniform("useFalloff", false));
node->getOrCreateStateSet()->addUniform(new osg::Uniform("distortionStrength", 0.f));
}
node->setUserValue(Misc::OsgUserValues::sFileHash,

@ -29,6 +29,19 @@ namespace SceneUtil
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)
{
if (!mSceneMgr->getSoftParticles())
@ -54,6 +67,12 @@ namespace SceneUtil
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{});

@ -16,6 +16,7 @@ namespace osg
namespace SceneUtil
{
void setupSoftEffect(osg::Node& node, float size, bool falloff, float falloffDepth);
void setupDistortion(osg::Node& node, float distortionStrength);
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/bloomlinear.omwfx
shaders/debug.omwfx
shaders/internal_distortion.omwfx
mygui/core.skin
mygui/core.xml

@ -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/util/quickstep.glsl
lib/util/coordinates.glsl
lib/util/distortion.glsl
lib/core/fragment.glsl
lib/core/fragment.h.glsl
lib/core/fragment_multiview.glsl

@ -1,5 +1,5 @@
#version 120
#pragma import_defines(FORCE_OPAQUE)
#pragma import_defines(FORCE_OPAQUE, DISTORTION)
#if @useUBO
#extension GL_ARB_uniform_buffer_object : require
@ -26,6 +26,8 @@ uniform sampler2D normalMap;
varying vec2 normalMapUV;
#endif
uniform sampler2D opaqueDepthTex;
varying float euclideanDepth;
varying float linearDepth;
@ -38,9 +40,11 @@ uniform float alphaRef;
uniform float emissiveMult;
uniform float specStrength;
uniform bool useTreeAnim;
uniform float distortionStrength;
#include "lib/light/lighting.glsl"
#include "lib/material/alpha.glsl"
#include "lib/util/distortion.glsl"
#include "compatibility/vertexcolors.glsl"
#include "compatibility/shadows_fragment.glsl"
@ -51,6 +55,15 @@ void main()
{
#if @diffuseMap
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);
#else
gl_FragData[0] = vec4(1.0);

@ -1,5 +1,5 @@
#version 120
#pragma import_defines(FORCE_OPAQUE)
#pragma import_defines(FORCE_OPAQUE, DISTORTION)
#if @useUBO
#extension GL_ARB_uniform_buffer_object : require
@ -66,6 +66,7 @@ uniform vec2 screenRes;
uniform float near;
uniform float far;
uniform float alphaRef;
uniform float distortionStrength;
#define PER_PIXEL_LIGHTING (@normalMap || @specularMap || @forcePPL)
@ -91,6 +92,7 @@ varying vec4 passTangent;
#include "lib/light/lighting.glsl"
#include "lib/material/parallax.glsl"
#include "lib/material/alpha.glsl"
#include "lib/util/distortion.glsl"
#include "fog.glsl"
#include "vertexcolors.glsl"
@ -100,7 +102,6 @@ varying vec4 passTangent;
#if @softParticles
#include "lib/particle/soft.glsl"
uniform sampler2D opaqueDepthTex;
uniform float particleSize;
uniform bool particleFade;
uniform float softFalloffDepth;
@ -112,6 +113,8 @@ uniform sampler2D orthoDepthMap;
varying vec3 orthoDepthMapCoord;
#endif
uniform sampler2D opaqueDepthTex;
void main()
{
#if @particleOcclusion
@ -133,8 +136,17 @@ void main()
offset = getParallaxOffset(transpose(normalToViewMatrix) * normalize(-passViewPos), height, flipY);
#endif
vec2 screenCoords = gl_FragCoord.xy / screenRes;
#if @diffuseMap
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
gl_FragData[0].a = 1.0;
#else
@ -234,7 +246,6 @@ void main()
gl_FragData[0] = applyFogAtPos(gl_FragData[0], passViewPos, far);
vec2 screenCoords = gl_FragCoord.xy / screenRes;
#if !defined(FORCE_OPAQUE) && @softParticles
gl_FragData[0].a *= calcSoftParticleFade(
viewVec,

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

Loading…
Cancel
Save