diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 0d4a5b33c6..da908f2eab 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -232,6 +232,7 @@ namespace Nif enum BSLightingShaderFlags1 { BSLSFlag1_Falloff = 0x00000040, + BSLSFlag1_SoftEffect = 0x40000000, }; enum BSLightingShaderFlags2 @@ -354,6 +355,7 @@ namespace Nif void read(NIFStream* nif) override; bool useFalloff() const { return mShaderFlags1 & BSLSFlag1_Falloff; } + bool softEffect() const { return mShaderFlags1 & BSLSFlag1_SoftEffect; } bool doubleSided() const { return mShaderFlags2 & BSLSFlag2_DoubleSided; } bool treeAnim() const { return mShaderFlags2 & BSLSFlag2_TreeAnim; } }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7a8fd6afb2..fbcd2f52bd 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -2561,6 +2562,8 @@ namespace NifOsg polygonOffset->setFactor(SceneUtil::AutoDepth::isReversed() ? 0.65f : -0.65f); stateset->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON); } + if (shaderprop->softEffect()) + SceneUtil::setupSoftEffect(*node, shaderprop->mFalloffDepth, true); break; } default: diff --git a/components/sceneutil/extradata.cpp b/components/sceneutil/extradata.cpp index e36efbad9c..d8d3e871dc 100644 --- a/components/sceneutil/extradata.cpp +++ b/components/sceneutil/extradata.cpp @@ -15,18 +15,12 @@ namespace SceneUtil { - void ProcessExtraDataVisitor::setupSoftEffect(osg::Node& node, float size, bool falloff) + void setupSoftEffect(osg::Node& node, float size, bool falloff) { - if (!mSceneMgr->getSoftParticles()) - return; - - const int unitSoftEffect - = mSceneMgr->getShaderManager().reserveGlobalTextureUnits(Shader::ShaderManager::Slot::OpaqueDepthTexture); static const osg::ref_ptr depth = new SceneUtil::AutoDepth(osg::Depth::LESS, 0, 1, false); osg::StateSet* stateset = node.getOrCreateStateSet(); - stateset->addUniform(new osg::Uniform("opaqueDepthTex", unitSoftEffect)); stateset->addUniform(new osg::Uniform("particleSize", size)); stateset->addUniform(new osg::Uniform("particleFade", falloff)); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); @@ -36,6 +30,9 @@ namespace SceneUtil void ProcessExtraDataVisitor::apply(osg::Node& node) { + if (!mSceneMgr->getSoftParticles()) + return; + std::string source; if (node.getUserValue(Misc::OsgUserValues::sExtraData, source) && !source.empty()) @@ -64,4 +61,4 @@ namespace SceneUtil traverse(node); } -} \ No newline at end of file +} diff --git a/components/sceneutil/extradata.hpp b/components/sceneutil/extradata.hpp index 4568a5289b..ddcb9b6c5c 100644 --- a/components/sceneutil/extradata.hpp +++ b/components/sceneutil/extradata.hpp @@ -15,6 +15,8 @@ namespace osg namespace SceneUtil { + void setupSoftEffect(osg::Node& node, float size, bool falloff); + class ProcessExtraDataVisitor : public osg::NodeVisitor { public: @@ -27,8 +29,6 @@ namespace SceneUtil void apply(osg::Node& node) override; private: - void setupSoftEffect(osg::Node& node, float size, bool falloff); - Resource::SceneManager* mSceneMgr; }; } diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 0112a3a699..1aa0f76e17 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -687,7 +687,17 @@ namespace Shader { if (reqs.mSoftParticles) defineMap["disableNormals"] = "1"; - writableStateSet->setAttribute(new osg::ColorMaski(1, false, false, false, false)); + auto colorMask = new osg::ColorMaski(1, false, false, false, false); + writableStateSet->setAttribute(colorMask); + addedState->setAttribute(colorMask); + } + + if (reqs.mSoftParticles) + { + const int unitSoftEffect + = mShaderManager.reserveGlobalTextureUnits(Shader::ShaderManager::Slot::OpaqueDepthTexture); + writableStateSet->addUniform(new osg::Uniform("opaqueDepthTex", unitSoftEffect)); + addedState->addUniform("opaqueDepthTex"); } if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT diff --git a/files/shaders/compatibility/bs/nolighting.frag b/files/shaders/compatibility/bs/nolighting.frag index 4a5c1c3b42..c5393d4732 100644 --- a/files/shaders/compatibility/bs/nolighting.frag +++ b/files/shaders/compatibility/bs/nolighting.frag @@ -14,6 +14,7 @@ uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; #endif +varying vec3 passViewPos; varying vec3 passNormal; varying float euclideanDepth; varying float linearDepth; @@ -22,6 +23,7 @@ varying float passFalloff; uniform vec2 screenRes; uniform bool useFalloff; uniform float far; +uniform float near; uniform float alphaRef; #include "lib/material/alpha.glsl" @@ -30,6 +32,14 @@ uniform float alphaRef; #include "compatibility/fog.glsl" #include "compatibility/shadows_fragment.glsl" +#if @softParticles +#include "lib/particle/soft.glsl" + +uniform sampler2D opaqueDepthTex; +uniform float particleSize; +uniform bool particleFade; +#endif + void main() { #if @diffuseMap @@ -48,6 +58,23 @@ void main() gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); +#if !defined(FORCE_OPAQUE) && @softParticles + vec2 screenCoords = gl_FragCoord.xy / screenRes; + vec3 viewVec = normalize(passViewPos.xyz); + vec3 viewNormal = normalize(gl_NormalMatrix * passNormal); + + gl_FragData[0].a *= calcSoftParticleFade( + viewVec, + passViewPos, + viewNormal, + near, + far, + texture2D(opaqueDepthTex, screenCoords).x, + particleSize, + particleFade + ); +#endif + #if defined(FORCE_OPAQUE) && FORCE_OPAQUE gl_FragData[0].a = 1.0; #endif diff --git a/files/shaders/compatibility/bs/nolighting.vert b/files/shaders/compatibility/bs/nolighting.vert index 27be3396ce..3b0fa7b626 100644 --- a/files/shaders/compatibility/bs/nolighting.vert +++ b/files/shaders/compatibility/bs/nolighting.vert @@ -15,6 +15,7 @@ varying vec2 diffuseMapUV; #endif varying vec3 passNormal; +varying vec3 passViewPos; varying float euclideanDepth; varying float linearDepth; varying float passFalloff; @@ -41,6 +42,7 @@ void main(void) #endif passColor = gl_Color; + passViewPos = viewPos.xyz; passNormal = gl_Normal.xyz; if (useFalloff)