mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-09 09:39:53 +00:00
Replace deprecated alpha test in shader visitor
This commit is contained in:
parent
70bd9d395d
commit
ce2bcba5d4
@ -46,7 +46,7 @@ add_component_dir (resource
|
||||
)
|
||||
|
||||
add_component_dir (shader
|
||||
shadermanager shadervisitor
|
||||
shadermanager shadervisitor removedalphafunc
|
||||
)
|
||||
|
||||
add_component_dir (sceneutil
|
||||
|
@ -278,7 +278,7 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
static osg::ref_ptr<osg::StateSet> ss;
|
||||
if (!ss)
|
||||
{
|
||||
ShadowsBinAdder adder("ShadowsBin");
|
||||
ShadowsBinAdder adder("ShadowsBin", _vdsm->getCastingPrograms());
|
||||
ss = new osg::StateSet;
|
||||
ss->setRenderBinDetails(osg::StateSet::OPAQUE_BIN, "ShadowsBin", osg::StateSet::OVERRIDE_PROTECTED_RENDERBIN_DETAILS);
|
||||
}
|
||||
@ -882,11 +882,15 @@ void SceneUtil::MWShadowTechnique::disableFrontFaceCulling()
|
||||
void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & shaderManager)
|
||||
{
|
||||
// This can't be part of the constructor as OSG mandates that there be a trivial constructor available
|
||||
|
||||
_castingProgram = new osg::Program();
|
||||
|
||||
_castingProgram->addShader(shaderManager.getShader("shadowcasting_vertex.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::VERTEX));
|
||||
_castingProgram->addShader(shaderManager.getShader("shadowcasting_fragment.glsl", Shader::ShaderManager::DefineMap(), osg::Shader::FRAGMENT));
|
||||
osg::ref_ptr<osg::Shader> castingVertexShader = shaderManager.getShader("shadowcasting_vertex.glsl", {}, osg::Shader::VERTEX);
|
||||
for (int alphaFunc = GL_NEVER; alphaFunc <= GL_ALWAYS; ++alphaFunc)
|
||||
{
|
||||
auto& program = _castingPrograms[alphaFunc - GL_NEVER];
|
||||
program = new osg::Program();
|
||||
program->addShader(castingVertexShader);
|
||||
program->addShader(shaderManager.getShader("shadowcasting_fragment.glsl", { {"alphaFunc", std::to_string(alphaFunc)} }, osg::Shader::FRAGMENT));
|
||||
}
|
||||
}
|
||||
|
||||
MWShadowTechnique::ViewDependentData* MWShadowTechnique::createViewDependentData(osgUtil::CullVisitor* /*cv*/)
|
||||
@ -1604,10 +1608,11 @@ void MWShadowTechnique::createShaders()
|
||||
|
||||
}
|
||||
|
||||
if (!_castingProgram)
|
||||
if (!_castingPrograms[GL_ALWAYS - GL_NEVER])
|
||||
OSG_NOTICE << "Shadow casting shader has not been set up. Remember to call setupCastingShader(Shader::ShaderManager &)" << std::endl;
|
||||
|
||||
_shadowCastingStateSet->setAttributeAndModes(_castingProgram, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
// Always use the GL_ALWAYS shader as the shadows bin will change it if necessary
|
||||
_shadowCastingStateSet->setAttributeAndModes(_castingPrograms[GL_ALWAYS - GL_NEVER], osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
// The casting program uses a sampler, so to avoid undefined behaviour, we must bind a dummy texture in case no other is supplied
|
||||
_shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON);
|
||||
_shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true));
|
||||
|
@ -215,6 +215,8 @@ namespace SceneUtil {
|
||||
|
||||
virtual void createShaders();
|
||||
|
||||
virtual std::array<osg::ref_ptr<osg::Program>, GL_ALWAYS - GL_NEVER> getCastingPrograms() const { return _castingPrograms; }
|
||||
|
||||
virtual bool selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const;
|
||||
|
||||
virtual osg::Polytope computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight);
|
||||
@ -288,7 +290,7 @@ namespace SceneUtil {
|
||||
};
|
||||
|
||||
osg::ref_ptr<DebugHUD> _debugHud;
|
||||
osg::ref_ptr<osg::Program> _castingProgram;
|
||||
std::array<osg::ref_ptr<osg::Program>, GL_ALWAYS - GL_NEVER> _castingPrograms;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include "shadowsbin.hpp"
|
||||
#include <unordered_set>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/Material>
|
||||
#include <osg/Program>
|
||||
#include <osgUtil/StateGraph>
|
||||
|
||||
using namespace osgUtil;
|
||||
@ -40,6 +42,10 @@ namespace
|
||||
namespace SceneUtil
|
||||
{
|
||||
|
||||
std::array<osg::ref_ptr<osg::Program>, GL_ALWAYS - GL_NEVER> ShadowsBin::sCastingPrograms = {
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
|
||||
};
|
||||
|
||||
ShadowsBin::ShadowsBin()
|
||||
{
|
||||
mNoTestStateSet = new osg::StateSet;
|
||||
@ -49,6 +55,12 @@ ShadowsBin::ShadowsBin()
|
||||
mShaderAlphaTestStateSet = new osg::StateSet;
|
||||
mShaderAlphaTestStateSet->addUniform(new osg::Uniform("alphaTestShadows", true));
|
||||
mShaderAlphaTestStateSet->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
|
||||
|
||||
for (size_t i = 0; i < sCastingPrograms.size(); ++i)
|
||||
{
|
||||
mAlphaFuncShaders[i] = new osg::StateSet;
|
||||
mAlphaFuncShaders[i]->setAttribute(sCastingPrograms[i], osg::StateAttribute::ON | osg::StateAttribute::PROTECTED | osg::StateAttribute::OVERRIDE);
|
||||
}
|
||||
}
|
||||
|
||||
StateGraph* ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::unordered_set<StateGraph*>& uninterestingCache)
|
||||
@ -71,7 +83,6 @@ StateGraph* ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::un
|
||||
continue;
|
||||
|
||||
accumulateModeState(ss, state.mAlphaBlend, state.mAlphaBlendOverride, GL_BLEND);
|
||||
accumulateModeState(ss, state.mAlphaTest, state.mAlphaTestOverride, GL_ALPHA_TEST);
|
||||
|
||||
const osg::StateSet::AttributeList& attributes = ss->getAttributeList();
|
||||
osg::StateSet::AttributeList::const_iterator found = attributes.find(std::make_pair(osg::StateAttribute::MATERIAL, 0));
|
||||
@ -83,6 +94,14 @@ StateGraph* ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::un
|
||||
state.mMaterial = nullptr;
|
||||
}
|
||||
|
||||
found = attributes.find(std::make_pair(osg::StateAttribute::ALPHAFUNC, 0));
|
||||
if (found != attributes.end())
|
||||
{
|
||||
// As force shaders is on, we know this is really a RemovedAlphaFunc
|
||||
const osg::StateSet::RefAttributePair& rap = found->second;
|
||||
accumulateState(state.mAlphaFunc, static_cast<osg::AlphaFunc*>(rap.first.get()), state.mAlphaFuncOverride, rap.second);
|
||||
}
|
||||
|
||||
// osg::FrontFace specifies triangle winding, not front-face culling. We can't safely reparent anything under it.
|
||||
found = attributes.find(std::make_pair(osg::StateAttribute::FRONTFACE, 0));
|
||||
if (found != attributes.end())
|
||||
@ -113,16 +132,44 @@ StateGraph* ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::un
|
||||
leaf->_parent = sg_new;
|
||||
sg_new->_leaves.push_back(leaf);
|
||||
}
|
||||
return sg_new;
|
||||
sg = sg_new;
|
||||
}
|
||||
|
||||
// GL_ALWAYS is set by default by mwshadowtechnique
|
||||
if (state.mAlphaFunc && state.mAlphaFunc->getFunction() != GL_ALWAYS)
|
||||
{
|
||||
sg_new = sg->find_or_insert(mAlphaFuncShaders[state.mAlphaFunc->getFunction() - GL_NEVER]);
|
||||
for (RenderLeaf* leaf : sg->_leaves)
|
||||
{
|
||||
leaf->_parent = sg_new;
|
||||
sg_new->_leaves.push_back(leaf);
|
||||
}
|
||||
sg = sg_new;
|
||||
}
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
void ShadowsBin::addPrototype(const std::string & name, const std::array<osg::ref_ptr<osg::Program>, GL_ALWAYS - GL_NEVER>& castingPrograms)
|
||||
{
|
||||
sCastingPrograms = castingPrograms;
|
||||
osg::ref_ptr<osgUtil::RenderBin> bin(new ShadowsBin);
|
||||
osgUtil::RenderBin::addRenderBinPrototype(name, bin);
|
||||
}
|
||||
|
||||
inline bool ShadowsBin::State::needTexture() const
|
||||
{
|
||||
return mAlphaBlend || (mAlphaFunc && mAlphaFunc->getFunction() != GL_ALWAYS);
|
||||
}
|
||||
|
||||
bool ShadowsBin::State::needShadows() const
|
||||
{
|
||||
if (!mMaterial)
|
||||
return true;
|
||||
return materialNeedShadows(mMaterial);
|
||||
if (mAlphaFunc && mAlphaFunc->getFunction() == GL_NEVER)
|
||||
return false;
|
||||
// other alpha func + material combinations might be skippable
|
||||
if (mAlphaBlend && mMaterial)
|
||||
return materialNeedShadows(mMaterial);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShadowsBin::sortImplementation()
|
||||
|
@ -1,11 +1,13 @@
|
||||
#ifndef OPENMW_COMPONENTS_SCENEUTIL_SHADOWBIN_H
|
||||
#define OPENMW_COMPONENTS_SCENEUTIL_SHADOWBIN_H
|
||||
#include <array>
|
||||
#include <unordered_set>
|
||||
#include <osgUtil/RenderBin>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Material;
|
||||
class AlphaFunc;
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
@ -15,8 +17,12 @@ namespace SceneUtil
|
||||
class ShadowsBin : public osgUtil::RenderBin
|
||||
{
|
||||
private:
|
||||
static std::array<osg::ref_ptr<osg::Program>, GL_ALWAYS - GL_NEVER> sCastingPrograms;
|
||||
|
||||
osg::ref_ptr<osg::StateSet> mNoTestStateSet;
|
||||
osg::ref_ptr<osg::StateSet> mShaderAlphaTestStateSet;
|
||||
|
||||
std::array<osg::ref_ptr<osg::StateSet>, GL_ALWAYS - GL_NEVER> mAlphaFuncShaders;
|
||||
public:
|
||||
META_Object(SceneUtil, ShadowsBin)
|
||||
ShadowsBin();
|
||||
@ -24,6 +30,7 @@ namespace SceneUtil
|
||||
: osgUtil::RenderBin(rhs, copyop)
|
||||
, mNoTestStateSet(rhs.mNoTestStateSet)
|
||||
, mShaderAlphaTestStateSet(rhs.mShaderAlphaTestStateSet)
|
||||
, mAlphaFuncShaders(rhs.mAlphaFuncShaders)
|
||||
{}
|
||||
|
||||
void sortImplementation() override;
|
||||
@ -33,8 +40,8 @@ namespace SceneUtil
|
||||
State()
|
||||
: mAlphaBlend(false)
|
||||
, mAlphaBlendOverride(false)
|
||||
, mAlphaTest(false)
|
||||
, mAlphaTestOverride(false)
|
||||
, mAlphaFunc(nullptr)
|
||||
, mAlphaFuncOverride(false)
|
||||
, mMaterial(nullptr)
|
||||
, mMaterialOverride(false)
|
||||
, mImportantState(false)
|
||||
@ -42,33 +49,29 @@ namespace SceneUtil
|
||||
|
||||
bool mAlphaBlend;
|
||||
bool mAlphaBlendOverride;
|
||||
bool mAlphaTest;
|
||||
bool mAlphaTestOverride;
|
||||
osg::AlphaFunc* mAlphaFunc;
|
||||
bool mAlphaFuncOverride;
|
||||
osg::Material* mMaterial;
|
||||
bool mMaterialOverride;
|
||||
bool mImportantState;
|
||||
bool needTexture() const { return mAlphaBlend || mAlphaTest; }
|
||||
bool needTexture() const;
|
||||
bool needShadows() const;
|
||||
// A state is interesting if there's anything about it that might affect whether we can optimise child state
|
||||
bool interesting() const
|
||||
{
|
||||
return !needShadows() || needTexture() || mAlphaBlendOverride || mAlphaTestOverride || mMaterialOverride || mImportantState;
|
||||
return !needShadows() || needTexture() || mAlphaBlendOverride || mAlphaFuncOverride || mMaterialOverride || mImportantState;
|
||||
}
|
||||
};
|
||||
|
||||
osgUtil::StateGraph* cullStateGraph(osgUtil::StateGraph* sg, osgUtil::StateGraph* root, std::unordered_set<osgUtil::StateGraph*>& uninteresting);
|
||||
|
||||
static void addPrototype(const std::string& name)
|
||||
{
|
||||
osg::ref_ptr<osgUtil::RenderBin> bin (new ShadowsBin);
|
||||
osgUtil::RenderBin::addRenderBinPrototype(name, bin);
|
||||
}
|
||||
static void addPrototype(const std::string& name, const std::array<osg::ref_ptr<osg::Program>, GL_ALWAYS - GL_NEVER>& castingPrograms);
|
||||
};
|
||||
|
||||
class ShadowsBinAdder
|
||||
{
|
||||
public:
|
||||
ShadowsBinAdder(const std::string& name){ ShadowsBin::addPrototype(name); }
|
||||
ShadowsBinAdder(const std::string& name, const std::array<osg::ref_ptr<osg::Program>, GL_ALWAYS - GL_NEVER>& castingPrograms){ ShadowsBin::addPrototype(name, castingPrograms); }
|
||||
};
|
||||
|
||||
}
|
||||
|
27
components/shader/removedalphafunc.cpp
Normal file
27
components/shader/removedalphafunc.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "removedalphafunc.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <osg/State>
|
||||
|
||||
namespace Shader
|
||||
{
|
||||
std::array<osg::ref_ptr<RemovedAlphaFunc>, GL_ALWAYS - GL_NEVER> RemovedAlphaFunc::sInstances{
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
|
||||
};
|
||||
|
||||
osg::ref_ptr<RemovedAlphaFunc> RemovedAlphaFunc::getInstance(GLenum func)
|
||||
{
|
||||
assert(func >= GL_NEVER && func <= GL_ALWAYS);
|
||||
if (!sInstances[func - GL_NEVER])
|
||||
sInstances[func - GL_NEVER] = new RemovedAlphaFunc(static_cast<osg::AlphaFunc::ComparisonFunction>(func), 1.0);
|
||||
return sInstances[func - GL_NEVER];
|
||||
}
|
||||
|
||||
void RemovedAlphaFunc::apply(osg::State & state) const
|
||||
{
|
||||
// Hopefully, anything genuinely requiring the default alpha func of GL_ALWAYS explicitly sets it
|
||||
if (!state.getGlobalDefaultAttribute(ALPHAFUNC)->getType() != getType())
|
||||
state.setGlobalDefaultAttribute(static_cast<const osg::StateAttribute*>(cloneType()));
|
||||
}
|
||||
}
|
40
components/shader/removedalphafunc.hpp
Normal file
40
components/shader/removedalphafunc.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef OPENMW_COMPONENTS_REMOVEDALPHAFUNC_H
|
||||
#define OPENMW_COMPONENTS_REMOVEDALPHAFUNC_H
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <osg/AlphaFunc>
|
||||
|
||||
namespace Shader
|
||||
{
|
||||
// State attribute used when shader visitor replaces the deprecated alpha function with a shader
|
||||
// Prevents redundant glAlphaFunc calls and lets the shadowsbin know the stateset had alpha testing
|
||||
class RemovedAlphaFunc : public osg::AlphaFunc
|
||||
{
|
||||
public:
|
||||
// Get a singleton-like instance with the right func (but a default threshold)
|
||||
static osg::ref_ptr<RemovedAlphaFunc> getInstance(GLenum func);
|
||||
|
||||
RemovedAlphaFunc()
|
||||
: osg::AlphaFunc()
|
||||
{}
|
||||
|
||||
RemovedAlphaFunc(ComparisonFunction func, float ref)
|
||||
: osg::AlphaFunc(func, ref)
|
||||
{}
|
||||
|
||||
RemovedAlphaFunc(const RemovedAlphaFunc& raf, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY)
|
||||
: osg::AlphaFunc(raf, copyop)
|
||||
{}
|
||||
|
||||
META_StateAttribute(Shader, RemovedAlphaFunc, ALPHAFUNC);
|
||||
|
||||
void apply(osg::State& state) const override;
|
||||
|
||||
protected:
|
||||
virtual ~RemovedAlphaFunc() = default;
|
||||
|
||||
static std::array<osg::ref_ptr<RemovedAlphaFunc>, GL_ALWAYS - GL_NEVER> sInstances;
|
||||
};
|
||||
}
|
||||
#endif //OPENMW_COMPONENTS_REMOVEDALPHAFUNC_H
|
@ -1,5 +1,6 @@
|
||||
#include "shadervisitor.hpp"
|
||||
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Material>
|
||||
#include <osg/Texture>
|
||||
@ -13,6 +14,7 @@
|
||||
#include <components/sceneutil/riggeometry.hpp>
|
||||
#include <components/sceneutil/morphgeometry.hpp>
|
||||
|
||||
#include "removedalphafunc.hpp"
|
||||
#include "shadermanager.hpp"
|
||||
|
||||
namespace Shader
|
||||
@ -22,6 +24,9 @@ namespace Shader
|
||||
: mShaderRequired(false)
|
||||
, mColorMode(0)
|
||||
, mMaterialOverridden(false)
|
||||
, mAlphaTestOverridden(false)
|
||||
, mAlphaFunc(GL_ALWAYS)
|
||||
, mAlphaRef(1.0)
|
||||
, mNormalHeight(false)
|
||||
, mTexStageRequiringTangents(-1)
|
||||
, mNode(nullptr)
|
||||
@ -76,6 +81,34 @@ namespace Shader
|
||||
return newStateSet.get();
|
||||
}
|
||||
|
||||
osg::UserDataContainer* getWritableUserDataContainer(osg::Object& object)
|
||||
{
|
||||
if (!object.getUserDataContainer())
|
||||
return object.getOrCreateUserDataContainer();
|
||||
|
||||
osg::ref_ptr<osg::UserDataContainer> newUserData = static_cast<osg::UserDataContainer *>(object.getUserDataContainer()->clone(osg::CopyOp::SHALLOW_COPY));
|
||||
object.setUserDataContainer(newUserData);
|
||||
return newUserData.get();
|
||||
}
|
||||
|
||||
osg::StateSet* getRemovedState(osg::StateSet& stateSet)
|
||||
{
|
||||
if (!stateSet.getUserDataContainer())
|
||||
return nullptr;
|
||||
|
||||
return static_cast<osg::StateSet *>(stateSet.getUserDataContainer()->getUserObject("removedState"));
|
||||
}
|
||||
|
||||
void updateRemovedState(osg::UserDataContainer& userData, osg::StateSet* stateSet)
|
||||
{
|
||||
unsigned int index = userData.getUserObjectIndex("removedState");
|
||||
if (index < userData.getNumUserObjects())
|
||||
userData.setUserObject(index, stateSet);
|
||||
else
|
||||
userData.addUserObject(stateSet);
|
||||
stateSet->setName("removedState");
|
||||
}
|
||||
|
||||
const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap", "decalMap", "bumpMap" };
|
||||
bool isTextureNameRecognized(const std::string& name)
|
||||
{
|
||||
@ -234,49 +267,67 @@ namespace Shader
|
||||
}
|
||||
|
||||
const osg::StateSet::AttributeList& attributes = stateset->getAttributeList();
|
||||
for (osg::StateSet::AttributeList::const_iterator it = attributes.begin(); it != attributes.end(); ++it)
|
||||
osg::StateSet::AttributeList removedAttributes;
|
||||
osg::ref_ptr<osg::StateSet> removedState;
|
||||
if (removedState = getRemovedState(*stateset))
|
||||
removedAttributes = removedState->getAttributeList();
|
||||
for (const auto& attributeMap : { attributes, removedAttributes })
|
||||
{
|
||||
if (it->first.first == osg::StateAttribute::MATERIAL)
|
||||
for (osg::StateSet::AttributeList::const_iterator it = attributeMap.begin(); it != attributeMap.end(); ++it)
|
||||
{
|
||||
// This should probably be moved out of ShaderRequirements and be applied directly now it's a uniform instead of a define
|
||||
if (!mRequirements.back().mMaterialOverridden || it->second.second & osg::StateAttribute::PROTECTED)
|
||||
if (it->first.first == osg::StateAttribute::MATERIAL)
|
||||
{
|
||||
if (it->second.second & osg::StateAttribute::OVERRIDE)
|
||||
mRequirements.back().mMaterialOverridden = true;
|
||||
|
||||
const osg::Material* mat = static_cast<const osg::Material*>(it->second.first.get());
|
||||
|
||||
if (!writableStateSet)
|
||||
writableStateSet = getWritableStateSet(node);
|
||||
|
||||
int colorMode;
|
||||
switch (mat->getColorMode())
|
||||
// This should probably be moved out of ShaderRequirements and be applied directly now it's a uniform instead of a define
|
||||
if (!mRequirements.back().mMaterialOverridden || it->second.second & osg::StateAttribute::PROTECTED)
|
||||
{
|
||||
case osg::Material::OFF:
|
||||
colorMode = 0;
|
||||
break;
|
||||
case osg::Material::EMISSION:
|
||||
colorMode = 1;
|
||||
break;
|
||||
default:
|
||||
case osg::Material::AMBIENT_AND_DIFFUSE:
|
||||
colorMode = 2;
|
||||
break;
|
||||
case osg::Material::AMBIENT:
|
||||
colorMode = 3;
|
||||
break;
|
||||
case osg::Material::DIFFUSE:
|
||||
colorMode = 4;
|
||||
break;
|
||||
case osg::Material::SPECULAR:
|
||||
colorMode = 5;
|
||||
break;
|
||||
}
|
||||
if (it->second.second & osg::StateAttribute::OVERRIDE)
|
||||
mRequirements.back().mMaterialOverridden = true;
|
||||
|
||||
mRequirements.back().mColorMode = colorMode;
|
||||
const osg::Material* mat = static_cast<const osg::Material*>(it->second.first.get());
|
||||
|
||||
if (!writableStateSet)
|
||||
writableStateSet = getWritableStateSet(node);
|
||||
|
||||
int colorMode;
|
||||
switch (mat->getColorMode())
|
||||
{
|
||||
case osg::Material::OFF:
|
||||
colorMode = 0;
|
||||
break;
|
||||
case osg::Material::EMISSION:
|
||||
colorMode = 1;
|
||||
break;
|
||||
default:
|
||||
case osg::Material::AMBIENT_AND_DIFFUSE:
|
||||
colorMode = 2;
|
||||
break;
|
||||
case osg::Material::AMBIENT:
|
||||
colorMode = 3;
|
||||
break;
|
||||
case osg::Material::DIFFUSE:
|
||||
colorMode = 4;
|
||||
break;
|
||||
case osg::Material::SPECULAR:
|
||||
colorMode = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
mRequirements.back().mColorMode = colorMode;
|
||||
}
|
||||
}
|
||||
else if (it->first.first == osg::StateAttribute::ALPHAFUNC)
|
||||
{
|
||||
if (!mRequirements.back().mAlphaTestOverridden || it->second.second & osg::StateAttribute::PROTECTED)
|
||||
{
|
||||
if (it->second.second & osg::StateAttribute::OVERRIDE)
|
||||
mRequirements.back().mAlphaTestOverridden = true;
|
||||
|
||||
const osg::AlphaFunc* alpha = static_cast<const osg::AlphaFunc*>(it->second.first.get());
|
||||
mRequirements.back().mAlphaFunc = alpha->getFunction();
|
||||
mRequirements.back().mAlphaRef = alpha->getReferenceValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Eventually, move alpha testing to discard in shader adn remove deprecated state here
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,6 +373,42 @@ namespace Shader
|
||||
|
||||
writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode));
|
||||
|
||||
defineMap["alphaFunc"] = std::to_string(reqs.mAlphaFunc);
|
||||
if (reqs.mAlphaFunc != osg::AlphaFunc::ALWAYS)
|
||||
{
|
||||
writableStateSet->addUniform(new osg::Uniform("alphaRef", reqs.mAlphaRef));
|
||||
|
||||
// back up removed state in case recreateShaders gets rid of the shader later
|
||||
osg::ref_ptr<osg::StateSet> removedState;
|
||||
if ((removedState = getRemovedState(*writableStateSet)) && !mAllowedToModifyStateSets)
|
||||
removedState = new osg::StateSet(*removedState, osg::CopyOp::SHALLOW_COPY);
|
||||
if (!removedState)
|
||||
removedState = new osg::StateSet();
|
||||
|
||||
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT)
|
||||
removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST));
|
||||
// This disables the deprecated fixed-function alpha test
|
||||
writableStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
|
||||
|
||||
const auto* alphaFunc = writableStateSet->getAttributePair(osg::StateAttribute::ALPHAFUNC);
|
||||
if (alphaFunc)
|
||||
removedState->setAttribute(alphaFunc->first, alphaFunc->second);
|
||||
// This prevents redundant glAlphaFunc calls while letting the shadows bin still see the test
|
||||
writableStateSet->setAttribute(RemovedAlphaFunc::getInstance(reqs.mAlphaFunc), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||
|
||||
if (!removedState->getModeList().empty() || !removedState->getAttributeList().empty())
|
||||
{
|
||||
// user data is normally shallow copied so shared with the original stateset
|
||||
osg::ref_ptr<osg::UserDataContainer> writableUserData;
|
||||
if (mAllowedToModifyStateSets)
|
||||
writableUserData = writableStateSet->getOrCreateUserDataContainer();
|
||||
else
|
||||
writableUserData = getWritableUserDataContainer(*writableStateSet);
|
||||
|
||||
updateRemovedState(*writableUserData, removedState);
|
||||
}
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Shader> vertexShader (mShaderManager.getShader(mDefaultVsTemplate, defineMap, osg::Shader::VERTEX));
|
||||
osg::ref_ptr<osg::Shader> fragmentShader (mShaderManager.getShader(mDefaultFsTemplate, defineMap, osg::Shader::FRAGMENT));
|
||||
|
||||
@ -347,6 +434,25 @@ namespace Shader
|
||||
writableStateSet = getWritableStateSet(node);
|
||||
|
||||
writableStateSet->removeAttribute(osg::StateAttribute::PROGRAM);
|
||||
|
||||
osg::ref_ptr<osg::StateSet> removedState;
|
||||
if (removedState = getRemovedState(*writableStateSet))
|
||||
{
|
||||
// user data is normally shallow copied so shared with the original stateset
|
||||
osg::ref_ptr<osg::UserDataContainer> writableUserData;
|
||||
if (mAllowedToModifyStateSets)
|
||||
writableUserData = writableStateSet->getUserDataContainer();
|
||||
else
|
||||
writableUserData = getWritableUserDataContainer(*writableStateSet);
|
||||
unsigned int index = writableUserData->getUserObjectIndex("removedState");
|
||||
writableUserData->removeUserObject(index);
|
||||
|
||||
for (const auto& [mode, value] : removedState->getModeList())
|
||||
writableStateSet->setMode(mode, value);
|
||||
|
||||
for (const auto& attribute : removedState->getAttributeList())
|
||||
writableStateSet->setAttribute(attribute.second.first, attribute.second.second);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShaderVisitor::adjustGeometry(osg::Geometry& sourceGeometry, const ShaderRequirements& reqs)
|
||||
|
@ -79,6 +79,10 @@ namespace Shader
|
||||
int mColorMode;
|
||||
|
||||
bool mMaterialOverridden;
|
||||
bool mAlphaTestOverridden;
|
||||
|
||||
GLenum mAlphaFunc;
|
||||
float mAlphaRef;
|
||||
|
||||
bool mNormalHeight; // true if normal map has height info in alpha channel
|
||||
|
||||
|
@ -10,6 +10,7 @@ set(SHADER_FILES
|
||||
water_vertex.glsl
|
||||
water_fragment.glsl
|
||||
water_nm.png
|
||||
alpha.glsl
|
||||
objects_vertex.glsl
|
||||
objects_fragment.glsl
|
||||
terrain_vertex.glsl
|
||||
|
38
files/shaders/alpha.glsl
Normal file
38
files/shaders/alpha.glsl
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
#define FUNC_NEVER 0x0200
|
||||
#define FUNC_LESS 0x0201
|
||||
#define FUNC_EQUAL 0x0202
|
||||
#define FUNC_LEQUAL 0x0203
|
||||
#define FUNC_GREATER 0x0204
|
||||
#define FUNC_NOTEQUAL 0x0205
|
||||
#define FUNC_GEQUAL 0x0206
|
||||
#define FUNC_ALWAYS 0x0207
|
||||
|
||||
#if @alphaFunc != FUNC_ALWAYS && @alphaFunc != FUNC_NEVER
|
||||
uniform float alphaRef;
|
||||
#endif
|
||||
|
||||
void alphaTest()
|
||||
{
|
||||
#if @alphaFunc == FUNC_NEVER
|
||||
discard;
|
||||
#elif @alphaFunc == FUNC_LESS
|
||||
if (gl_FragData[0].a > alphaRef)
|
||||
discard;
|
||||
#elif @alphaFunc == FUNC_EQUAL
|
||||
if (gl_FragData[0].a != alphaRef)
|
||||
discard;
|
||||
#elif @alphaFunc == FUNC_LEQUAL
|
||||
if (gl_FragData[0].a >= alphaRef)
|
||||
discard;
|
||||
#elif @alphaFunc == FUNC_GREATER
|
||||
if (gl_FragData[0].a < alphaRef)
|
||||
discard;
|
||||
#elif @alphaFunc == FUNC_NOTEQUAL
|
||||
if (gl_FragData[0].a == alphaRef)
|
||||
discard;
|
||||
#elif @alphaFunc == FUNC_GEQUAL
|
||||
if (gl_FragData[0].a <= alphaRef)
|
||||
discard;
|
||||
#endif
|
||||
}
|
@ -67,6 +67,7 @@ varying vec3 passNormal;
|
||||
#include "shadows_fragment.glsl"
|
||||
#include "lighting.glsl"
|
||||
#include "parallax.glsl"
|
||||
#include "alpha.glsl"
|
||||
|
||||
void main()
|
||||
{
|
||||
@ -108,6 +109,7 @@ void main()
|
||||
|
||||
#if @diffuseMap
|
||||
gl_FragData[0] = texture2D(diffuseMap, adjustedDiffuseUV);
|
||||
alphaTest();
|
||||
#else
|
||||
gl_FragData[0] = vec4(1.0);
|
||||
#endif
|
||||
@ -164,6 +166,8 @@ void main()
|
||||
gl_FragData[0] *= doLighting(passViewPos, normalize(viewNormal), passColor, shadowing);
|
||||
#endif
|
||||
|
||||
alphaTest();
|
||||
|
||||
#if @envMap && !@preLightEnv
|
||||
gl_FragData[0].xyz += texture2D(envMap, envTexCoordGen).xyz * envMapColor.xyz * envLuma;
|
||||
#endif
|
||||
|
@ -8,6 +8,8 @@ varying float alphaPassthrough;
|
||||
uniform bool useDiffuseMapForShadowAlpha;
|
||||
uniform bool alphaTestShadows;
|
||||
|
||||
#include "alpha.glsl"
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragData[0].rgb = vec3(1.0);
|
||||
@ -16,7 +18,10 @@ void main()
|
||||
else
|
||||
gl_FragData[0].a = alphaPassthrough;
|
||||
|
||||
// Prevent translucent things casting shadow (including the player using an invisibility effect). For now, rely on the deprecated FF test for non-blended stuff.
|
||||
alphaTest();
|
||||
|
||||
// Prevent translucent things casting shadow (including the player using an invisibility effect).
|
||||
// This replaces alpha blending, which obviously doesn't work with depth buffers
|
||||
if (alphaTestShadows && gl_FragData[0].a <= 0.5)
|
||||
discard;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user