mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-28 21:07:59 +03:00
Merge branch 'leaf_me_alone' into 'master'
Some checks failed
Build and test / Ubuntu (push) Has been cancelled
Build and test / MacOS (push) Has been cancelled
Build and test / Read .env file and expose it as output (push) Has been cancelled
Build and test / Windows (2019) (push) Has been cancelled
Build and test / Windows (2022) (push) Has been cancelled
Some checks failed
Build and test / Ubuntu (push) Has been cancelled
Build and test / MacOS (push) Has been cancelled
Build and test / Read .env file and expose it as output (push) Has been cancelled
Build and test / Windows (2019) (push) Has been cancelled
Build and test / Windows (2022) (push) Has been cancelled
tes5 - add leaf animations See merge request OpenMW/openmw!4550
This commit is contained in:
commit
aa2a473ae1
29 changed files with 354 additions and 82 deletions
|
@ -95,7 +95,7 @@ add_openmw_dir (mwphysics
|
||||||
add_openmw_dir (mwclass
|
add_openmw_dir (mwclass
|
||||||
classes activator creature npc weapon armor potion apparatus book clothing container door
|
classes activator creature npc weapon armor potion apparatus book clothing container door
|
||||||
ingredient creaturelevlist itemlevlist light lockpick misc probe repair static actor bodypart
|
ingredient creaturelevlist itemlevlist light lockpick misc probe repair static actor bodypart
|
||||||
esm4base esm4npc light4
|
esm4base esm4npc light4 tree4
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwmechanics
|
add_openmw_dir (mwmechanics
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "esm4base.hpp"
|
#include "esm4base.hpp"
|
||||||
#include "esm4npc.hpp"
|
#include "esm4npc.hpp"
|
||||||
#include "light4.hpp"
|
#include "light4.hpp"
|
||||||
|
#include "tree4.hpp"
|
||||||
|
|
||||||
namespace MWClass
|
namespace MWClass
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,15 +120,6 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ESM4Tree final : public MWWorld::RegisteredClass<ESM4Tree, ESM4Base<ESM4::Tree>>
|
|
||||||
{
|
|
||||||
friend MWWorld::RegisteredClass<ESM4Tree, ESM4Base<ESM4::Tree>>;
|
|
||||||
ESM4Tree()
|
|
||||||
: MWWorld::RegisteredClass<ESM4Tree, ESM4Base<ESM4::Tree>>(ESM4::Tree::sRecordId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// For records with `mFullName` that should be shown as a tooltip.
|
// For records with `mFullName` that should be shown as a tooltip.
|
||||||
// All objects with a tooltip can be activated (activation can be handled in Lua).
|
// All objects with a tooltip can be activated (activation can be handled in Lua).
|
||||||
template <typename Record>
|
template <typename Record>
|
||||||
|
|
27
apps/openmw/mwclass/tree4.cpp
Normal file
27
apps/openmw/mwclass/tree4.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "tree4.hpp"
|
||||||
|
|
||||||
|
#include <components/esm4/loadtree.hpp>
|
||||||
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
|
||||||
|
#include "../mwrender/objects.hpp"
|
||||||
|
#include "../mwrender/renderinginterface.hpp"
|
||||||
|
#include "../mwrender/vismask.hpp"
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
namespace MWClass
|
||||||
|
{
|
||||||
|
ESM4Tree::ESM4Tree()
|
||||||
|
: MWWorld::RegisteredClass<ESM4Tree, ESM4Base<ESM4::Tree>>(ESM4::Tree::sRecordId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESM4Tree ::insertObjectRendering(
|
||||||
|
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
|
||||||
|
{
|
||||||
|
if (!model.empty())
|
||||||
|
{
|
||||||
|
renderingInterface.getObjects().insertModel(ptr, model);
|
||||||
|
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
apps/openmw/mwclass/tree4.hpp
Normal file
22
apps/openmw/mwclass/tree4.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef OPENW_MWCLASS_TREE4
|
||||||
|
#define OPENW_MWCLASS_TREE4
|
||||||
|
|
||||||
|
#include "../mwworld/registeredclass.hpp"
|
||||||
|
|
||||||
|
#include "esm4base.hpp"
|
||||||
|
|
||||||
|
namespace MWClass
|
||||||
|
{
|
||||||
|
class ESM4Tree : public MWWorld::RegisteredClass<ESM4Tree, ESM4Base<ESM4::Tree>>
|
||||||
|
{
|
||||||
|
friend MWWorld::RegisteredClass<ESM4Tree, ESM4Base<ESM4::Tree>>;
|
||||||
|
|
||||||
|
ESM4Tree();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void insertObjectRendering(const MWWorld::Ptr& ptr, const std::string& model,
|
||||||
|
MWRender::RenderingInterface& renderingInterface) const override;
|
||||||
|
///< Add reference into a cell for rendering
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -28,6 +28,7 @@
|
||||||
#include <components/esm3/loadnpc.hpp>
|
#include <components/esm3/loadnpc.hpp>
|
||||||
#include <components/esm3/loadrace.hpp>
|
#include <components/esm3/loadrace.hpp>
|
||||||
#include <components/esm4/loadligh.hpp>
|
#include <components/esm4/loadligh.hpp>
|
||||||
|
#include <components/esm4/loadtree.hpp>
|
||||||
|
|
||||||
#include <components/misc/constants.hpp>
|
#include <components/misc/constants.hpp>
|
||||||
#include <components/misc/pathhelpers.hpp>
|
#include <components/misc/pathhelpers.hpp>
|
||||||
|
@ -67,6 +68,31 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
class LeafParamsAssigner : public osg::NodeVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LeafParamsAssigner(const MWWorld::LiveCellRef<ESM4::Tree>* treeRef)
|
||||||
|
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
||||||
|
, mTreeRef(treeRef)
|
||||||
|
, mVertexAttrib(new osg::Vec3Array(1))
|
||||||
|
, mTimeOffset(Misc::Rng::roll0to99())
|
||||||
|
{
|
||||||
|
mVertexAttrib->at(0) = osg::Vec3f(
|
||||||
|
mTreeRef->mBase->mParams.mLeafAmplitude, mTreeRef->mBase->mParams.mLeafFrequency, mTimeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply(osg::Geometry& geometry) override
|
||||||
|
{
|
||||||
|
geometry.setVertexAttribArray(7, mVertexAttrib, osg::Array::BIND_OVERALL);
|
||||||
|
|
||||||
|
traverse(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MWWorld::LiveCellRef<ESM4::Tree>* mTreeRef = nullptr;
|
||||||
|
osg::ref_ptr<osg::Vec3Array> mVertexAttrib = nullptr;
|
||||||
|
float mTimeOffset = 0.f;
|
||||||
|
};
|
||||||
|
|
||||||
class MarkDrawablesVisitor : public osg::NodeVisitor
|
class MarkDrawablesVisitor : public osg::NodeVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -2079,6 +2105,11 @@ namespace MWRender
|
||||||
addExtraLight(getOrCreateObjectRoot(), SceneUtil::LightCommon(*ptr.get<ESM::Light>()->mBase));
|
addExtraLight(getOrCreateObjectRoot(), SceneUtil::LightCommon(*ptr.get<ESM::Light>()->mBase));
|
||||||
if (ptr.getType() == ESM4::Light::sRecordId && allowLight)
|
if (ptr.getType() == ESM4::Light::sRecordId && allowLight)
|
||||||
addExtraLight(getOrCreateObjectRoot(), SceneUtil::LightCommon(*ptr.get<ESM4::Light>()->mBase));
|
addExtraLight(getOrCreateObjectRoot(), SceneUtil::LightCommon(*ptr.get<ESM4::Light>()->mBase));
|
||||||
|
if (ptr.getType() == ESM4::Tree::sRecordId)
|
||||||
|
{
|
||||||
|
LeafParamsAssigner nv{ ptr.get<ESM4::Tree>() };
|
||||||
|
ptr.getRefData().getBaseNode()->accept(nv);
|
||||||
|
}
|
||||||
|
|
||||||
if (!allowLight && mObjectRoot)
|
if (!allowLight && mObjectRoot)
|
||||||
{
|
{
|
||||||
|
|
|
@ -174,7 +174,6 @@ namespace MWRender
|
||||||
stateset->addUniform(new osg::Uniform("isReflection", false));
|
stateset->addUniform(new osg::Uniform("isReflection", false));
|
||||||
stateset->addUniform(new osg::Uniform("windSpeed", 0.0f));
|
stateset->addUniform(new osg::Uniform("windSpeed", 0.0f));
|
||||||
stateset->addUniform(new osg::Uniform("playerPos", osg::Vec3f(0.f, 0.f, 0.f)));
|
stateset->addUniform(new osg::Uniform("playerPos", osg::Vec3f(0.f, 0.f, 0.f)));
|
||||||
stateset->addUniform(new osg::Uniform("useTreeAnim", false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override
|
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override
|
||||||
|
@ -447,6 +446,8 @@ namespace MWRender
|
||||||
globalDefines["useOVR_multiview"] = "0";
|
globalDefines["useOVR_multiview"] = "0";
|
||||||
globalDefines["numViews"] = "1";
|
globalDefines["numViews"] = "1";
|
||||||
globalDefines["disableNormals"] = "1";
|
globalDefines["disableNormals"] = "1";
|
||||||
|
globalDefines["treeAnim"] = "0";
|
||||||
|
globalDefines["shadowCasting"] = "0";
|
||||||
|
|
||||||
for (auto itr = lightDefines.begin(); itr != lightDefines.end(); itr++)
|
for (auto itr = lightDefines.begin(); itr != lightDefines.end(); itr++)
|
||||||
globalDefines[itr->first] = itr->second;
|
globalDefines[itr->first] = itr->second;
|
||||||
|
|
|
@ -53,11 +53,23 @@ void ESM4::Tree::load(ESM4::Reader& reader)
|
||||||
case ESM::fourCC("MODB"):
|
case ESM::fourCC("MODB"):
|
||||||
reader.get(mBoundRadius);
|
reader.get(mBoundRadius);
|
||||||
break;
|
break;
|
||||||
|
case ESM::fourCC("CNAM"):
|
||||||
|
{
|
||||||
|
switch (subHdr.dataSize)
|
||||||
|
{
|
||||||
|
case 48: // TES5
|
||||||
|
reader.get(mParams);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reader.skipSubRecordData();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ESM::fourCC("MODT"): // Model data
|
case ESM::fourCC("MODT"): // Model data
|
||||||
case ESM::fourCC("MODC"):
|
case ESM::fourCC("MODC"):
|
||||||
case ESM::fourCC("MODS"):
|
case ESM::fourCC("MODS"):
|
||||||
case ESM::fourCC("MODF"): // Model data end
|
case ESM::fourCC("MODF"): // Model data end
|
||||||
case ESM::fourCC("CNAM"):
|
|
||||||
case ESM::fourCC("BNAM"):
|
case ESM::fourCC("BNAM"):
|
||||||
case ESM::fourCC("SNAM"):
|
case ESM::fourCC("SNAM"):
|
||||||
case ESM::fourCC("FULL"):
|
case ESM::fourCC("FULL"):
|
||||||
|
|
|
@ -50,6 +50,24 @@ namespace ESM4
|
||||||
|
|
||||||
std::string mLeafTexture;
|
std::string mLeafTexture;
|
||||||
|
|
||||||
|
struct Params
|
||||||
|
{
|
||||||
|
float mTrunkFlexibility;
|
||||||
|
float mBranchFlexibility;
|
||||||
|
float mTrunkAmplitude;
|
||||||
|
float mFrontAmplitude;
|
||||||
|
float mBackAmplitude;
|
||||||
|
float mSideAmplitude;
|
||||||
|
float mFrontFrequency;
|
||||||
|
float mBackFrequency;
|
||||||
|
float mSideFrequency;
|
||||||
|
float mLeafFlexibility;
|
||||||
|
float mLeafAmplitude;
|
||||||
|
float mLeafFrequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
Params mParams;
|
||||||
|
|
||||||
void load(ESM4::Reader& reader);
|
void load(ESM4::Reader& reader);
|
||||||
// void save(ESM4::Writer& writer) const;
|
// void save(ESM4::Writer& writer) const;
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,5 @@ namespace Misc
|
||||||
const std::string OsgUserValues::sFileHash = "fileHash";
|
const std::string OsgUserValues::sFileHash = "fileHash";
|
||||||
const std::string OsgUserValues::sExtraData = "xData";
|
const std::string OsgUserValues::sExtraData = "xData";
|
||||||
const std::string OsgUserValues::sXSoftEffect = "xSoftEffect";
|
const std::string OsgUserValues::sXSoftEffect = "xSoftEffect";
|
||||||
|
const std::string OsgUserValues::sTreeAnim = "treeAnim";
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace Misc
|
||||||
static const std::string sFileHash;
|
static const std::string sFileHash;
|
||||||
static const std::string sExtraData;
|
static const std::string sExtraData;
|
||||||
static const std::string sXSoftEffect;
|
static const std::string sXSoftEffect;
|
||||||
|
static const std::string sTreeAnim;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,12 +74,12 @@ namespace Nif
|
||||||
{ "BSDistantObjectInstancedNode",
|
{ "BSDistantObjectInstancedNode",
|
||||||
&construct<BSDistantObjectInstancedNode, RC_BSDistantObjectInstancedNode> },
|
&construct<BSDistantObjectInstancedNode, RC_BSDistantObjectInstancedNode> },
|
||||||
{ "BSFadeNode", &construct<NiNode, RC_NiNode> },
|
{ "BSFadeNode", &construct<NiNode, RC_NiNode> },
|
||||||
{ "BSLeafAnimNode", &construct<NiNode, RC_NiNode> },
|
{ "BSLeafAnimNode", &construct<NiNode, RC_BSLeafAnimNode> },
|
||||||
{ "BSMasterParticleSystem", &construct<BSMasterParticleSystem, RC_NiNode> },
|
{ "BSMasterParticleSystem", &construct<BSMasterParticleSystem, RC_NiNode> },
|
||||||
{ "BSMultiBoundNode", &construct<BSMultiBoundNode, RC_NiNode> },
|
{ "BSMultiBoundNode", &construct<BSMultiBoundNode, RC_NiNode> },
|
||||||
{ "BSOrderedNode", &construct<BSOrderedNode, RC_NiNode> },
|
{ "BSOrderedNode", &construct<BSOrderedNode, RC_NiNode> },
|
||||||
{ "BSRangeNode", &construct<BSRangeNode, RC_NiNode> },
|
{ "BSRangeNode", &construct<BSRangeNode, RC_NiNode> },
|
||||||
{ "BSTreeNode", &construct<BSTreeNode, RC_NiNode> },
|
{ "BSTreeNode", &construct<BSTreeNode, RC_BSTreeNode> },
|
||||||
{ "BSValueNode", &construct<BSValueNode, RC_NiNode> },
|
{ "BSValueNode", &construct<BSValueNode, RC_NiNode> },
|
||||||
|
|
||||||
// Switch nodes, 4.0.0.2
|
// Switch nodes, 4.0.0.2
|
||||||
|
|
|
@ -102,6 +102,7 @@ namespace Nif
|
||||||
RC_BSInvMarker,
|
RC_BSInvMarker,
|
||||||
RC_BSKeyframeController,
|
RC_BSKeyframeController,
|
||||||
RC_BSLagBoneController,
|
RC_BSLagBoneController,
|
||||||
|
RC_BSLeafAnimNode,
|
||||||
RC_BSLightingShaderProperty,
|
RC_BSLightingShaderProperty,
|
||||||
RC_BSLightingShaderPropertyColorController,
|
RC_BSLightingShaderPropertyColorController,
|
||||||
RC_BSLightingShaderPropertyFloatController,
|
RC_BSLightingShaderPropertyFloatController,
|
||||||
|
@ -145,6 +146,7 @@ namespace Nif
|
||||||
RC_BSSubIndexTriShape,
|
RC_BSSubIndexTriShape,
|
||||||
RC_BSTreadTransfInterpolator,
|
RC_BSTreadTransfInterpolator,
|
||||||
RC_BSTriShape,
|
RC_BSTriShape,
|
||||||
|
RC_BSTreeNode,
|
||||||
RC_BSWArray,
|
RC_BSWArray,
|
||||||
RC_BSWaterShaderProperty,
|
RC_BSWaterShaderProperty,
|
||||||
RC_BSWindModifier,
|
RC_BSWindModifier,
|
||||||
|
|
|
@ -258,6 +258,7 @@ namespace NifOsg
|
||||||
bool mHasNightDayLabel = false;
|
bool mHasNightDayLabel = false;
|
||||||
bool mHasHerbalismLabel = false;
|
bool mHasHerbalismLabel = false;
|
||||||
bool mHasStencilProperty = false;
|
bool mHasStencilProperty = false;
|
||||||
|
bool mHasTreeRoot = false;
|
||||||
|
|
||||||
const Nif::NiSortAdjustNode* mPushedSorter = nullptr;
|
const Nif::NiSortAdjustNode* mPushedSorter = nullptr;
|
||||||
const Nif::NiSortAdjustNode* mLastAppliedNoInheritSorter = nullptr;
|
const Nif::NiSortAdjustNode* mLastAppliedNoInheritSorter = nullptr;
|
||||||
|
@ -747,6 +748,12 @@ namespace NifOsg
|
||||||
node->setDataVariance(osg::Object::DYNAMIC);
|
node->setDataVariance(osg::Object::DYNAMIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Root node must be a BSTreeNode or BSLeafAnimNode for tree/leaf related shader flags to apply
|
||||||
|
if (!parent && (nifNode->recType == Nif::RC_BSLeafAnimNode || nifNode->recType == Nif::RC_BSTreeNode))
|
||||||
|
{
|
||||||
|
mHasTreeRoot = true;
|
||||||
|
}
|
||||||
|
|
||||||
osg::ref_ptr<SceneUtil::CompositeStateSetUpdater> composite = new SceneUtil::CompositeStateSetUpdater;
|
osg::ref_ptr<SceneUtil::CompositeStateSetUpdater> composite = new SceneUtil::CompositeStateSetUpdater;
|
||||||
|
|
||||||
applyNodeProperties(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags);
|
applyNodeProperties(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||||
|
@ -2183,8 +2190,8 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleShaderMaterialNodeProperties(
|
void handleShaderMaterialNodeProperties(osg::Node* node, const Bgsm::MaterialFile* material,
|
||||||
const Bgsm::MaterialFile* material, osg::StateSet* stateset, std::vector<unsigned int>& boundTextures) const
|
osg::StateSet* stateset, std::vector<unsigned int>& boundTextures) const
|
||||||
{
|
{
|
||||||
const unsigned int uvSet = 0;
|
const unsigned int uvSet = 0;
|
||||||
const bool wrapS = material->wrapS();
|
const bool wrapS = material->wrapS();
|
||||||
|
@ -2203,8 +2210,8 @@ namespace NifOsg
|
||||||
if (bgsm->mGlowMapEnabled && !bgsm->mGlowMap.empty())
|
if (bgsm->mGlowMapEnabled && !bgsm->mGlowMap.empty())
|
||||||
attachExternalTexture("emissiveMap", bgsm->mGlowMap, wrapS, wrapT, uvSet, stateset, boundTextures);
|
attachExternalTexture("emissiveMap", bgsm->mGlowMap, wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
|
|
||||||
if (bgsm->mTree)
|
if (bgsm->mTree && mHasTreeRoot)
|
||||||
stateset->addUniform(new osg::Uniform("useTreeAnim", true));
|
node->setUserValue(Misc::OsgUserValues::sTreeAnim, true);
|
||||||
}
|
}
|
||||||
else if (material->mShaderType == Bgsm::ShaderType::Effect)
|
else if (material->mShaderType == Bgsm::ShaderType::Effect)
|
||||||
{
|
{
|
||||||
|
@ -2540,7 +2547,7 @@ namespace NifOsg
|
||||||
clearBoundTextures(stateset, boundTextures);
|
clearBoundTextures(stateset, boundTextures);
|
||||||
if (Bgsm::MaterialFilePtr material = getShaderMaterial(texprop->mName, mMaterialManager))
|
if (Bgsm::MaterialFilePtr material = getShaderMaterial(texprop->mName, mMaterialManager))
|
||||||
{
|
{
|
||||||
handleShaderMaterialNodeProperties(material.get(), stateset, boundTextures);
|
handleShaderMaterialNodeProperties(node, material.get(), stateset, boundTextures);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!texprop->mTextureSet.empty())
|
if (!texprop->mTextureSet.empty())
|
||||||
|
@ -2549,8 +2556,8 @@ namespace NifOsg
|
||||||
handleTextureControllers(texprop, composite, stateset, animflags);
|
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||||
if (texprop->doubleSided())
|
if (texprop->doubleSided())
|
||||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||||
if (texprop->treeAnim())
|
if (texprop->treeAnim() && mHasTreeRoot)
|
||||||
stateset->addUniform(new osg::Uniform("useTreeAnim", true));
|
node->setUserValue(Misc::OsgUserValues::sTreeAnim, true);
|
||||||
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
||||||
if (texprop->refraction())
|
if (texprop->refraction())
|
||||||
SceneUtil::setupDistortion(*node, texprop->mRefractionStrength);
|
SceneUtil::setupDistortion(*node, texprop->mRefractionStrength);
|
||||||
|
@ -2567,7 +2574,7 @@ namespace NifOsg
|
||||||
clearBoundTextures(stateset, boundTextures);
|
clearBoundTextures(stateset, boundTextures);
|
||||||
if (Bgsm::MaterialFilePtr material = getShaderMaterial(texprop->mName, mMaterialManager))
|
if (Bgsm::MaterialFilePtr material = getShaderMaterial(texprop->mName, mMaterialManager))
|
||||||
{
|
{
|
||||||
handleShaderMaterialNodeProperties(material.get(), stateset, boundTextures);
|
handleShaderMaterialNodeProperties(node, material.get(), stateset, boundTextures);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!texprop->mSourceTexture.empty())
|
if (!texprop->mSourceTexture.empty())
|
||||||
|
|
|
@ -922,14 +922,12 @@ void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & sh
|
||||||
std::string useGPUShader4 = SceneUtil::getGLExtensions().isGpuShader4Supported ? "1" : "0";
|
std::string useGPUShader4 = SceneUtil::getGLExtensions().isGpuShader4Supported ? "1" : "0";
|
||||||
for (int alphaFunc = GL_NEVER; alphaFunc <= GL_ALWAYS; ++alphaFunc)
|
for (int alphaFunc = GL_NEVER; alphaFunc <= GL_ALWAYS; ++alphaFunc)
|
||||||
{
|
{
|
||||||
auto& program = _castingPrograms[alphaFunc - GL_NEVER];
|
osg::ref_ptr<osg::Shader> castingFragmentShader = shaderManager.getShader("shadowcasting.frag", { {"alphaFunc", std::to_string(alphaFunc)},
|
||||||
program = new osg::Program();
|
|
||||||
program->addShader(castingVertexShader);
|
|
||||||
program->addShader(shaderManager.getShader("shadowcasting.frag", { {"alphaFunc", std::to_string(alphaFunc)},
|
|
||||||
{"alphaToCoverage", "0"},
|
{"alphaToCoverage", "0"},
|
||||||
{"adjustCoverage", "1"},
|
{"adjustCoverage", "1"},
|
||||||
{"useGPUShader4", useGPUShader4}
|
{"useGPUShader4", useGPUShader4}});
|
||||||
}));
|
auto& program = _castingPrograms[alphaFunc - GL_NEVER];
|
||||||
|
program = shaderManager.createProgram(castingVertexShader, castingFragmentShader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#include "shadowsbin.hpp"
|
#include "shadowsbin.hpp"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <osg/AlphaFunc>
|
#include <osg/AlphaFunc>
|
||||||
#include <osg/Material>
|
#include <osg/Material>
|
||||||
#include <osg/Program>
|
#include <osg/Program>
|
||||||
#include <osg/StateSet>
|
#include <osg/StateSet>
|
||||||
#include <osgUtil/StateGraph>
|
#include <osgUtil/StateGraph>
|
||||||
#include <unordered_set>
|
|
||||||
|
#include <components/shader/shadermanager.hpp>
|
||||||
|
|
||||||
using namespace osgUtil;
|
using namespace osgUtil;
|
||||||
|
|
||||||
|
@ -115,6 +119,14 @@ namespace SceneUtil
|
||||||
state.mImportantState = true;
|
state.mImportantState = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto dedicatedCastingStateSet
|
||||||
|
= dynamic_cast<const Shader::ShaderManager::ShadowCastingStateSet*>(ss->getUserData());
|
||||||
|
|
||||||
|
if (dedicatedCastingStateSet)
|
||||||
|
{
|
||||||
|
state.mShadowCastingStateSet = dedicatedCastingStateSet->mStateSet;
|
||||||
|
}
|
||||||
|
|
||||||
if ((*itr) != sg && !state.interesting())
|
if ((*itr) != sg && !state.interesting())
|
||||||
uninterestingCache.insert(*itr);
|
uninterestingCache.insert(*itr);
|
||||||
}
|
}
|
||||||
|
@ -132,24 +144,22 @@ namespace SceneUtil
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.mAlphaBlend)
|
auto find_or_insert = [&sg, &sg_new](const osg::StateSet* ss) {
|
||||||
{
|
sg_new = sg->find_or_insert(ss);
|
||||||
sg_new = sg->find_or_insert(mShaderAlphaTestStateSet);
|
|
||||||
sg_new->_leaves = std::move(sg->_leaves);
|
sg_new->_leaves = std::move(sg->_leaves);
|
||||||
for (RenderLeaf* leaf : sg_new->_leaves)
|
for (RenderLeaf* leaf : sg_new->_leaves)
|
||||||
leaf->_parent = sg_new;
|
leaf->_parent = sg_new;
|
||||||
sg = sg_new;
|
sg = sg_new;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
if (state.mAlphaBlend)
|
||||||
|
find_or_insert(mShaderAlphaTestStateSet);
|
||||||
|
|
||||||
|
if (state.mShadowCastingStateSet)
|
||||||
|
find_or_insert(state.mShadowCastingStateSet);
|
||||||
// GL_ALWAYS is set by default by mwshadowtechnique
|
// GL_ALWAYS is set by default by mwshadowtechnique
|
||||||
if (state.mAlphaFunc && state.mAlphaFunc->getFunction() != GL_ALWAYS)
|
else if (state.mAlphaFunc && state.mAlphaFunc->getFunction() != GL_ALWAYS)
|
||||||
{
|
find_or_insert(mAlphaFuncShaders[state.mAlphaFunc->getFunction() - GL_NEVER]);
|
||||||
sg_new = sg->find_or_insert(mAlphaFuncShaders[state.mAlphaFunc->getFunction() - GL_NEVER]);
|
|
||||||
sg_new->_leaves = std::move(sg->_leaves);
|
|
||||||
for (RenderLeaf* leaf : sg_new->_leaves)
|
|
||||||
leaf->_parent = sg_new;
|
|
||||||
sg = sg_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sg;
|
return sg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,24 +35,14 @@ namespace SceneUtil
|
||||||
|
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
State()
|
bool mAlphaBlend = false;
|
||||||
: mAlphaBlend(false)
|
bool mAlphaBlendOverride = false;
|
||||||
, mAlphaBlendOverride(false)
|
osg::AlphaFunc* mAlphaFunc = nullptr;
|
||||||
, mAlphaFunc(nullptr)
|
bool mAlphaFuncOverride = false;
|
||||||
, mAlphaFuncOverride(false)
|
osg::Material* mMaterial = nullptr;
|
||||||
, mMaterial(nullptr)
|
bool mMaterialOverride = false;
|
||||||
, mMaterialOverride(false)
|
bool mImportantState = false;
|
||||||
, mImportantState(false)
|
osg::StateSet* mShadowCastingStateSet = nullptr;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mAlphaBlend;
|
|
||||||
bool mAlphaBlendOverride;
|
|
||||||
osg::AlphaFunc* mAlphaFunc;
|
|
||||||
bool mAlphaFuncOverride;
|
|
||||||
osg::Material* mMaterial;
|
|
||||||
bool mMaterialOverride;
|
|
||||||
bool mImportantState;
|
|
||||||
bool needTexture() const;
|
bool needTexture() const;
|
||||||
bool needShadows() const;
|
bool needShadows() const;
|
||||||
// A state is interesting if there's anything about it that might affect whether we can optimise child state
|
// A state is interesting if there's anything about it that might affect whether we can optimise child state
|
||||||
|
|
|
@ -609,18 +609,26 @@ namespace Shader
|
||||||
{
|
{
|
||||||
if (!programTemplate)
|
if (!programTemplate)
|
||||||
programTemplate = mProgramTemplate;
|
programTemplate = mProgramTemplate;
|
||||||
osg::ref_ptr<osg::Program> program
|
found = mPrograms
|
||||||
= programTemplate ? cloneProgram(programTemplate) : osg::ref_ptr<osg::Program>(new osg::Program);
|
.insert(std::make_pair(std::make_pair(vertexShader, fragmentShader),
|
||||||
program->addShader(vertexShader);
|
createProgram(vertexShader, fragmentShader, programTemplate)))
|
||||||
program->addShader(fragmentShader);
|
.first;
|
||||||
addLinkedShaders(vertexShader, program);
|
|
||||||
addLinkedShaders(fragmentShader, program);
|
|
||||||
|
|
||||||
found = mPrograms.insert(std::make_pair(std::make_pair(vertexShader, fragmentShader), program)).first;
|
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Program> ShaderManager::createProgram(osg::ref_ptr<osg::Shader> vertexShader,
|
||||||
|
osg::ref_ptr<osg::Shader> fragmentShader, const osg::Program* programTemplate)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Program> program
|
||||||
|
= programTemplate ? cloneProgram(programTemplate) : osg::ref_ptr<osg::Program>(new osg::Program);
|
||||||
|
program->addShader(vertexShader);
|
||||||
|
program->addShader(fragmentShader);
|
||||||
|
addLinkedShaders(vertexShader, program);
|
||||||
|
addLinkedShaders(fragmentShader, program);
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Program> ShaderManager::cloneProgram(const osg::Program* src)
|
osg::ref_ptr<osg::Program> ShaderManager::cloneProgram(const osg::Program* src)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Program> program = static_cast<osg::Program*>(src->clone(osg::CopyOp::SHALLOW_COPY));
|
osg::ref_ptr<osg::Program> program = static_cast<osg::Program*>(src->clone(osg::CopyOp::SHALLOW_COPY));
|
||||||
|
|
|
@ -36,6 +36,17 @@ namespace Shader
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> DefineMap;
|
typedef std::map<std::string, std::string> DefineMap;
|
||||||
|
|
||||||
|
class ShadowCastingStateSet : public osg::Referenced
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShadowCastingStateSet(osg::ref_ptr<osg::StateSet>&& stateSet)
|
||||||
|
: mStateSet(std::move(stateSet))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::StateSet> mStateSet = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
/// Create or retrieve a shader instance.
|
/// Create or retrieve a shader instance.
|
||||||
/// @param templateName The path of the shader template.
|
/// @param templateName The path of the shader template.
|
||||||
/// @param defines Define values that can be retrieved by the shader template.
|
/// @param defines Define values that can be retrieved by the shader template.
|
||||||
|
@ -51,6 +62,9 @@ namespace Shader
|
||||||
osg::ref_ptr<osg::Program> getProgram(osg::ref_ptr<osg::Shader> vertexShader,
|
osg::ref_ptr<osg::Program> getProgram(osg::ref_ptr<osg::Shader> vertexShader,
|
||||||
osg::ref_ptr<osg::Shader> fragmentShader, const osg::Program* programTemplate = nullptr);
|
osg::ref_ptr<osg::Shader> fragmentShader, const osg::Program* programTemplate = nullptr);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Program> createProgram(osg::ref_ptr<osg::Shader> vertexShader,
|
||||||
|
osg::ref_ptr<osg::Shader> fragmentShader, const osg::Program* programTemplate = nullptr);
|
||||||
|
|
||||||
const osg::Program* getProgramTemplate() const { return mProgramTemplate; }
|
const osg::Program* getProgramTemplate() const { return mProgramTemplate; }
|
||||||
void setProgramTemplate(const osg::Program* program) { mProgramTemplate = program; }
|
void setProgramTemplate(const osg::Program* program) { mProgramTemplate = program; }
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,7 @@ namespace Shader
|
||||||
, mReconstructNormalZ(false)
|
, mReconstructNormalZ(false)
|
||||||
, mTexStageRequiringTangents(-1)
|
, mTexStageRequiringTangents(-1)
|
||||||
, mSoftParticles(false)
|
, mSoftParticles(false)
|
||||||
|
, mTreeAnim(false)
|
||||||
, mNode(nullptr)
|
, mNode(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -308,6 +309,10 @@ namespace Shader
|
||||||
if (node.getUserValue(Misc::OsgUserValues::sXSoftEffect, softEffect) && softEffect)
|
if (node.getUserValue(Misc::OsgUserValues::sXSoftEffect, softEffect) && softEffect)
|
||||||
mRequirements.back().mSoftParticles = true;
|
mRequirements.back().mSoftParticles = true;
|
||||||
|
|
||||||
|
bool treeAnim = false;
|
||||||
|
if (node.getUserValue(Misc::OsgUserValues::sTreeAnim, treeAnim) && treeAnim)
|
||||||
|
mRequirements.back().mTreeAnim = true;
|
||||||
|
|
||||||
// Make sure to disregard any state that came from a previous call to createProgram
|
// Make sure to disregard any state that came from a previous call to createProgram
|
||||||
osg::ref_ptr<AddedState> addedState = getAddedState(*stateset);
|
osg::ref_ptr<AddedState> addedState = getAddedState(*stateset);
|
||||||
|
|
||||||
|
@ -736,6 +741,11 @@ namespace Shader
|
||||||
addedState->addUniform("opaqueDepthTex");
|
addedState->addUniform("opaqueDepthTex");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reqs.mTreeAnim)
|
||||||
|
{
|
||||||
|
defineMap["treeAnim"] = "1";
|
||||||
|
}
|
||||||
|
|
||||||
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT
|
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT
|
||||||
&& !previousAddedState->hasMode(GL_ALPHA_TEST))
|
&& !previousAddedState->hasMode(GL_ALPHA_TEST))
|
||||||
removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST));
|
removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST));
|
||||||
|
@ -764,6 +774,16 @@ namespace Shader
|
||||||
shaderPrefix = mDefaultShaderPrefix;
|
shaderPrefix = mDefaultShaderPrefix;
|
||||||
|
|
||||||
auto program = mShaderManager.getProgram(shaderPrefix, defineMap, mProgramTemplate);
|
auto program = mShaderManager.getProgram(shaderPrefix, defineMap, mProgramTemplate);
|
||||||
|
if (reqs.mTreeAnim)
|
||||||
|
{
|
||||||
|
program->addBindAttribLocation("aLeafParams", 7);
|
||||||
|
defineMap["shadowCasting"] = "1";
|
||||||
|
osg::ref_ptr<osg::StateSet> shadowCastingStateSet = new osg::StateSet;
|
||||||
|
auto shadowCastingProgram = mShaderManager.getProgram(shaderPrefix, defineMap, mProgramTemplate);
|
||||||
|
shadowCastingStateSet->setAttribute(shadowCastingProgram,
|
||||||
|
osg::StateAttribute::ON | osg::StateAttribute::PROTECTED | osg::StateAttribute::OVERRIDE);
|
||||||
|
writableStateSet->setUserData(new ShaderManager::ShadowCastingStateSet(std::move(shadowCastingStateSet)));
|
||||||
|
}
|
||||||
writableStateSet->setAttributeAndModes(program, osg::StateAttribute::ON);
|
writableStateSet->setAttributeAndModes(program, osg::StateAttribute::ON);
|
||||||
addedState->setAttributeAndModes(std::move(program));
|
addedState->setAttributeAndModes(std::move(program));
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,8 @@ namespace Shader
|
||||||
|
|
||||||
bool mSoftParticles;
|
bool mSoftParticles;
|
||||||
|
|
||||||
|
bool mTreeAnim;
|
||||||
|
|
||||||
// the Node that requested these requirements
|
// the Node that requested these requirements
|
||||||
osg::Node* mNode;
|
osg::Node* mNode;
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,8 @@ set(SHADER_FILES
|
||||||
lib/water/fresnel.glsl
|
lib/water/fresnel.glsl
|
||||||
lib/water/rain_ripples.glsl
|
lib/water/rain_ripples.glsl
|
||||||
lib/water/ripples.glsl
|
lib/water/ripples.glsl
|
||||||
|
lib/nature/leaves.glsl
|
||||||
|
lib/nature/leaves.h.glsl
|
||||||
lib/view/depth.glsl
|
lib/view/depth.glsl
|
||||||
lib/luminance/constants.glsl
|
lib/luminance/constants.glsl
|
||||||
lib/particle/soft.glsl
|
lib/particle/soft.glsl
|
||||||
|
|
|
@ -37,7 +37,6 @@ uniform float far;
|
||||||
uniform float alphaRef;
|
uniform float alphaRef;
|
||||||
uniform float emissiveMult;
|
uniform float emissiveMult;
|
||||||
uniform float specStrength;
|
uniform float specStrength;
|
||||||
uniform bool useTreeAnim;
|
|
||||||
uniform float distortionStrength;
|
uniform float distortionStrength;
|
||||||
|
|
||||||
#include "lib/core/fragment.h.glsl"
|
#include "lib/core/fragment.h.glsl"
|
||||||
|
@ -52,6 +51,18 @@ uniform float distortionStrength;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
#if @shadowCasting
|
||||||
|
#if @diffuseMap
|
||||||
|
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef);
|
||||||
|
if (gl_FragData[0].a <= 0.5)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if @diffuseMap
|
#if @diffuseMap
|
||||||
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV);
|
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV);
|
||||||
|
|
||||||
|
@ -69,8 +80,9 @@ void main()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vec4 diffuseColor = getDiffuseColor();
|
vec4 diffuseColor = getDiffuseColor();
|
||||||
if (!useTreeAnim)
|
#if !@treeAnim
|
||||||
gl_FragData[0].a *= diffuseColor.a;
|
gl_FragData[0].a *= diffuseColor.a;
|
||||||
|
#endif
|
||||||
gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef);
|
gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef);
|
||||||
|
|
||||||
vec3 specularColor = getSpecularColor().xyz;
|
vec3 specularColor = getSpecularColor().xyz;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define PER_PIXEL_LIGHTING 1
|
#define PER_PIXEL_LIGHTING 1
|
||||||
|
|
||||||
#include "lib/core/vertex.h.glsl"
|
#include "lib/core/vertex.h.glsl"
|
||||||
|
#include "lib/nature/leaves.h.glsl"
|
||||||
|
|
||||||
#if @diffuseMap
|
#if @diffuseMap
|
||||||
varying vec2 diffuseMapUV;
|
varying vec2 diffuseMapUV;
|
||||||
|
@ -31,6 +32,10 @@ varying float linearDepth;
|
||||||
varying vec3 passViewPos;
|
varying vec3 passViewPos;
|
||||||
varying vec3 passNormal;
|
varying vec3 passNormal;
|
||||||
|
|
||||||
|
#if @treeAnim
|
||||||
|
attribute vec3 aLeafParams;
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "lib/light/lighting.glsl"
|
#include "lib/light/lighting.glsl"
|
||||||
#include "lib/view/depth.glsl"
|
#include "lib/view/depth.glsl"
|
||||||
|
|
||||||
|
@ -40,9 +45,29 @@ varying vec3 passNormal;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
gl_Position = modelToClip(gl_Vertex);
|
vec4 vertex = gl_Vertex;
|
||||||
|
|
||||||
vec4 viewPos = modelToView(gl_Vertex);
|
#if @treeAnim
|
||||||
|
vertex = transformLeafVertex(LeafParams(
|
||||||
|
aLeafParams.x,
|
||||||
|
aLeafParams.y,
|
||||||
|
aLeafParams.z
|
||||||
|
), gl_Vertex, gl_Color, gl_Normal.xyz);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if @diffuseMap
|
||||||
|
diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if @shadowCasting
|
||||||
|
gl_Position = gl_ModelViewProjectionMatrix * vertex;
|
||||||
|
gl_ClipVertex = (gl_ModelViewMatrix * vertex);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gl_Position = modelToClip(vertex);
|
||||||
|
|
||||||
|
vec4 viewPos = modelToView(vertex);
|
||||||
gl_ClipVertex = viewPos;
|
gl_ClipVertex = viewPos;
|
||||||
euclideanDepth = length(viewPos.xyz);
|
euclideanDepth = length(viewPos.xyz);
|
||||||
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
||||||
|
@ -55,10 +80,6 @@ void main(void)
|
||||||
normalToViewMatrix *= generateTangentSpace(gl_MultiTexCoord7.xyzw, passNormal);
|
normalToViewMatrix *= generateTangentSpace(gl_MultiTexCoord7.xyzw, passNormal);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if @diffuseMap
|
|
||||||
diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if @emissiveMap
|
#if @emissiveMap
|
||||||
emissiveMapUV = (gl_TextureMatrix[@emissiveMapUV] * gl_MultiTexCoord@emissiveMapUV).xy;
|
emissiveMapUV = (gl_TextureMatrix[@emissiveMapUV] * gl_MultiTexCoord@emissiveMapUV).xy;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,6 +43,18 @@ uniform float softFalloffDepth;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
#if @shadowCasting
|
||||||
|
#if @diffuseMap
|
||||||
|
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef);
|
||||||
|
if (gl_FragData[0].a <= 0.5)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if @diffuseMap
|
#if @diffuseMap
|
||||||
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV);
|
gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV);
|
||||||
gl_FragData[0].a *= coveragePreservingAlphaScale(diffuseMap, diffuseMapUV);
|
gl_FragData[0].a *= coveragePreservingAlphaScale(diffuseMap, diffuseMapUV);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "lib/core/vertex.h.glsl"
|
#include "lib/core/vertex.h.glsl"
|
||||||
|
#include "lib/nature/leaves.h.glsl"
|
||||||
|
|
||||||
#if @diffuseMap
|
#if @diffuseMap
|
||||||
varying vec2 diffuseMapUV;
|
varying vec2 diffuseMapUV;
|
||||||
|
@ -23,6 +24,10 @@ varying float passFalloff;
|
||||||
uniform bool useFalloff;
|
uniform bool useFalloff;
|
||||||
uniform vec4 falloffParams;
|
uniform vec4 falloffParams;
|
||||||
|
|
||||||
|
#if @treeAnim
|
||||||
|
attribute vec3 aLeafParams;
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "lib/view/depth.glsl"
|
#include "lib/view/depth.glsl"
|
||||||
|
|
||||||
#include "compatibility/vertexcolors.glsl"
|
#include "compatibility/vertexcolors.glsl"
|
||||||
|
@ -30,17 +35,31 @@ uniform vec4 falloffParams;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
gl_Position = modelToClip(gl_Vertex);
|
vec4 vertex = gl_Vertex;
|
||||||
|
|
||||||
vec4 viewPos = modelToView(gl_Vertex);
|
#if @treeAnim
|
||||||
gl_ClipVertex = viewPos;
|
vertex = transformLeafVertex(LeafParams(
|
||||||
euclideanDepth = length(viewPos.xyz);
|
aLeafParams.x,
|
||||||
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
aLeafParams.y,
|
||||||
|
aLeafParams.z
|
||||||
|
), gl_Vertex, gl_Color, gl_Normal.xyz);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if @diffuseMap
|
#if @diffuseMap
|
||||||
diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy;
|
diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if @shadowCasting
|
||||||
|
gl_Position = gl_ModelViewProjectionMatrix * vertex;
|
||||||
|
gl_ClipVertex = (gl_ModelViewMatrix * vertex);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec4 viewPos = modelToView(vertex);
|
||||||
|
gl_ClipVertex = viewPos;
|
||||||
|
euclideanDepth = length(viewPos.xyz);
|
||||||
|
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
||||||
|
|
||||||
passColor = gl_Color;
|
passColor = gl_Color;
|
||||||
passViewPos = viewPos.xyz;
|
passViewPos = viewPos.xyz;
|
||||||
passNormal = gl_Normal.xyz;
|
passNormal = gl_Normal.xyz;
|
||||||
|
|
|
@ -5,7 +5,6 @@ varying vec2 diffuseMapUV;
|
||||||
varying float alphaPassthrough;
|
varying float alphaPassthrough;
|
||||||
|
|
||||||
uniform int colorMode;
|
uniform int colorMode;
|
||||||
uniform bool useTreeAnim;
|
|
||||||
uniform bool useDiffuseMapForShadowAlpha = true;
|
uniform bool useDiffuseMapForShadowAlpha = true;
|
||||||
uniform bool alphaTestShadows = true;
|
uniform bool alphaTestShadows = true;
|
||||||
|
|
||||||
|
@ -21,7 +20,7 @@ void main(void)
|
||||||
else
|
else
|
||||||
diffuseMapUV = vec2(0.0); // Avoid undefined behaviour if running on hardware predating the concept of dynamically uniform expressions
|
diffuseMapUV = vec2(0.0); // Avoid undefined behaviour if running on hardware predating the concept of dynamically uniform expressions
|
||||||
if (colorMode == 2)
|
if (colorMode == 2)
|
||||||
alphaPassthrough = useTreeAnim ? 1.0 : gl_Color.a;
|
alphaPassthrough = gl_Color.a;
|
||||||
else
|
else
|
||||||
// This is uniform, so if it's too low, we might be able to put the position/clip vertex outside the view frustum and skip the fragment shader and rasteriser
|
// This is uniform, so if it's too low, we might be able to put the position/clip vertex outside the view frustum and skip the fragment shader and rasteriser
|
||||||
alphaPassthrough = gl_FrontMaterial.diffuse.a;
|
alphaPassthrough = gl_FrontMaterial.diffuse.a;
|
||||||
|
|
36
files/shaders/lib/nature/leaves.glsl
Normal file
36
files/shaders/lib/nature/leaves.glsl
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
#include "lib/nature/leaves.h.glsl"
|
||||||
|
|
||||||
|
uniform float osg_SimulationTime;
|
||||||
|
uniform float windSpeed;
|
||||||
|
|
||||||
|
vec4 transformLeafVertex(LeafParams params, vec4 position, vec4 color, vec3 normal)
|
||||||
|
{
|
||||||
|
// Default constants for leaf/tree animation fading from the Skyrim.ini
|
||||||
|
const float fLeafAnimDampenDistEnd = 4600.0;
|
||||||
|
const float fLeafAnimDampenDistStart = 3600.0;
|
||||||
|
|
||||||
|
float distance = length(gl_ModelViewMatrix * position);
|
||||||
|
|
||||||
|
float fade = 1.0
|
||||||
|
- clamp((distance - fLeafAnimDampenDistStart) / (fLeafAnimDampenDistEnd - fLeafAnimDampenDistStart), 0.0, 1.0);
|
||||||
|
|
||||||
|
float amplitude = color.a * params.mLeafAmplitude * fade;
|
||||||
|
|
||||||
|
if (amplitude <= 0.f)
|
||||||
|
return position;
|
||||||
|
|
||||||
|
float offset = params.mTimeOffset + position.x * 0.1 + position.y * 0.1;
|
||||||
|
float period = 0.5 * sin(0.15 * osg_SimulationTime * 6.136 + params.mTimeOffset) + 0.5;
|
||||||
|
float wind = sin(osg_SimulationTime * params.mLeafFrequency + offset) * params.mLeafAmplitude * windSpeed * period;
|
||||||
|
float spatialOffset = dot(position.xyz, vec3(1.0));
|
||||||
|
|
||||||
|
const vec2 axisFrequencyFactor = vec2(0.1, 0.25);
|
||||||
|
vec2 phase = fract(axisFrequencyFactor * (wind * params.mLeafFrequency * 10) + spatialOffset + 0.5);
|
||||||
|
vec2 leafMotion = smoothstep(0.0, 1.0, abs(2.0 * phase - 1.0));
|
||||||
|
float normalMultiplier = (leafMotion.x + 0.1 * leafMotion.y) * amplitude;
|
||||||
|
position.xyz += normal.xyz * normalMultiplier;
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
15
files/shaders/lib/nature/leaves.h.glsl
Normal file
15
files/shaders/lib/nature/leaves.h.glsl
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef OPENMW_LIB_NATURE_LEAVES_H_GLSL
|
||||||
|
#define OPENMW_LIB_NATURE_LEAVES_H_GLSL
|
||||||
|
|
||||||
|
@link "lib/nature/leaves.glsl"
|
||||||
|
|
||||||
|
struct LeafParams
|
||||||
|
{
|
||||||
|
float mLeafAmplitude;
|
||||||
|
float mLeafFrequency;
|
||||||
|
float mTimeOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec4 transformLeafVertex(LeafParams params, vec4 position, vec4 color, vec3 normal);
|
||||||
|
|
||||||
|
#endif // OPENMW_LIB_NATURE_LEAVES_H_GLSL
|
Loading…
Add table
Add a link
Reference in a new issue