initial commit

pull/593/head
glassmancody.info 4 years ago
parent 2b144ff3dd
commit dda735c54a

@ -72,7 +72,6 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f)
mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager;
lightMgr->setStartLight(1);
lightMgr->setLightingMask(Mask_Lighting);
mRootNode = lightMgr;

@ -31,6 +31,7 @@
#include <components/compiler/extensions0.hpp>
#include <components/sceneutil/workqueue.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/files/configurationmanager.hpp>

@ -152,7 +152,7 @@ namespace MWRender
mCamera->setNodeMask(Mask_RenderToTexture);
osg::ref_ptr<SceneUtil::LightManager> lightManager = new SceneUtil::LightManager;
osg::ref_ptr<SceneUtil::LightManager> lightManager = new SceneUtil::LightManager(mResourceSystem->getSceneManager()->getFFPLighting());
lightManager->setStartLight(1);
osg::ref_ptr<osg::StateSet> stateset = lightManager->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
@ -215,6 +215,7 @@ namespace MWRender
light->setConstantAttenuation(1.f);
light->setLinearAttenuation(0.f);
light->setQuadraticAttenuation(0.f);
lightManager->setSunlight(light);
osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource;
lightSource->setLight(light);

@ -18,7 +18,10 @@
#include <components/settings/settings.hpp>
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/files/memorystream.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/resource/resourcesystem.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -219,6 +222,14 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f
SceneUtil::ShadowManager::disableShadowsForStateSet(stateset);
// override sun for local map
if (!MWBase::Environment::get().getResourceSystem()->getSceneManager()->getFFPLighting())
{
osg::ref_ptr<SceneUtil::SunlightStateAttribute> sun = new SceneUtil::SunlightStateAttribute;
sun->setFromLight(light);
sun->setStateSet(stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
}
camera->addChild(lightSource);
camera->setStateSet(stateset);
camera->setViewport(0, 0, mMapResolution, mMapResolution);

@ -203,17 +203,19 @@ namespace MWRender
resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders");
// Shadows and radial fog have problems with fixed-function mode
bool forceShaders = Settings::Manager::getBool("radial fog", "Shaders") || Settings::Manager::getBool("force shaders", "Shaders") || Settings::Manager::getBool("enable shadows", "Shadows");
bool clampLighting = Settings::Manager::getBool("clamp lighting", "Shaders");
resourceSystem->getSceneManager()->setForceShaders(forceShaders);
// FIXME: calling dummy method because terrain needs to know whether lighting is clamped
resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders"));
resourceSystem->getSceneManager()->setClampLighting(clampLighting);
resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders"));
resourceSystem->getSceneManager()->setNormalMapPattern(Settings::Manager::getString("normal map pattern", "Shaders"));
resourceSystem->getSceneManager()->setNormalHeightMapPattern(Settings::Manager::getString("normal height map pattern", "Shaders"));
resourceSystem->getSceneManager()->setAutoUseSpecularMaps(Settings::Manager::getBool("auto use object specular maps", "Shaders"));
resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders"));
resourceSystem->getSceneManager()->setApplyLightingToEnvMaps(Settings::Manager::getBool("apply lighting to environment maps", "Shaders"));
resourceSystem->getSceneManager()->setFFPLighting(clampLighting || !forceShaders || !SceneUtil::LightManager::queryNonFFPLightingSupport());
osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager;
osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(mResourceSystem->getSceneManager()->getFFPLighting());
sceneRoot->setLightingMask(Mask_Lighting);
mSceneRoot = sceneRoot;
sceneRoot->setStartLight(1);
@ -235,8 +237,12 @@ namespace MWRender
mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager()));
Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines();
Shader::ShaderManager::DefineMap lightDefines = sceneRoot->getLightDefines();
Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines();
for (auto itr = lightDefines.begin(); itr != lightDefines.end(); itr++)
globalDefines[itr->first] = itr->second;
for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++)
globalDefines[itr->first] = itr->second;
@ -248,7 +254,7 @@ namespace MWRender
float groundcoverDistance = (Constants::CellSizeInUnits * std::max(1, Settings::Manager::getInt("distance", "Groundcover")) - 1024) * 0.93;
globalDefines["groundcoverFadeStart"] = std::to_string(groundcoverDistance * 0.9f);
globalDefines["groundcoverFadeEnd"] = std::to_string(groundcoverDistance);
// It is unnecessary to stop/start the viewer as no frames are being rendered yet.
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines);
@ -354,6 +360,7 @@ namespace MWRender
mSunLight->setAmbient(osg::Vec4f(0,0,0,1));
mSunLight->setSpecular(osg::Vec4f(0,0,0,0));
mSunLight->setConstantAttenuation(1.f);
sceneRoot->setSunlight(mSunLight);
sceneRoot->addChild(source);
sceneRoot->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON);

@ -27,6 +27,7 @@
#include <components/sceneutil/shadow.hpp>
#include <components/sceneutil/waterutil.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/misc/constants.hpp>
@ -644,6 +645,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R
osg::ref_ptr<osg::Program> program (new osg::Program);
program->addShader(vertexShader);
program->addShader(fragmentShader);
if (!mResourceSystem->getSceneManager()->getFFPLighting())
program->addBindUniformBlock("SunlightBuffer", 9);
shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON);
node->setStateSet(shaderStateset);

@ -220,12 +220,13 @@ namespace Resource
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
: ResourceManager(vfs)
, mShaderManager(new Shader::ShaderManager)
, mShaderManager(new Shader::ShaderManager(this))
, mForceShaders(false)
, mClampLighting(true)
, mAutoUseNormalMaps(false)
, mAutoUseSpecularMaps(false)
, mApplyLightingToEnvMaps(false)
, mFFPLighting(true)
, mInstanceCache(new MultiObjectCache)
, mSharedStateManager(new SharedStateManager)
, mImageManager(imageManager)
@ -297,6 +298,16 @@ namespace Resource
mApplyLightingToEnvMaps = apply;
}
void SceneManager::setFFPLighting(bool apply)
{
mFFPLighting = apply;
}
bool SceneManager::getFFPLighting() const
{
return mFFPLighting;
}
SceneManager::~SceneManager()
{
// this has to be defined in the .cpp file as we can't delete incomplete types

@ -100,6 +100,9 @@ namespace Resource
void setApplyLightingToEnvMaps(bool apply);
void setFFPLighting(bool apply);
bool getFFPLighting() const;
void setShaderPath(const std::string& path);
/// Check if a given scene is loaded and if so, update its usage timestamp to prevent it from being unloaded
@ -184,6 +187,7 @@ namespace Resource
bool mAutoUseSpecularMaps;
std::string mSpecularMapPattern;
bool mApplyLightingToEnvMaps;
bool mFFPLighting;
osg::ref_ptr<MultiObjectCache> mInstanceCache;

@ -1,11 +1,145 @@
#include "lightmanager.hpp"
#include <osg/BufferObject>
#include <osgUtil/CullVisitor>
#include <components/sceneutil/util.hpp>
#include <components/misc/stringops.hpp>
#include <components/settings/settings.hpp>
#include <components/debug/debuglog.hpp>
namespace
{
/* similar to the boost::hash_combine */
template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
bool sortLights(const SceneUtil::LightManager::LightSourceViewBound* left, const SceneUtil::LightManager::LightSourceViewBound* right)
{
return left->mViewBound.center().length2() - left->mViewBound.radius2()*81 < right->mViewBound.center().length2() - right->mViewBound.radius2()*81;
}
}
namespace SceneUtil
{
static int sLightId = 0;
class LightBuffer : public osg::Referenced
{
public:
LightBuffer(int elements, int count=1)
: mNumElements(elements)
, mData(new osg::Vec4Array(elements * count))
, mDirty(false)
{}
virtual ~LightBuffer() {}
osg::ref_ptr<osg::Vec4Array> getData()
{
return mData;
}
bool isDirty() const
{
return mDirty;
}
void dirty()
{
mData->dirty();
mDirty = false;
}
int blockSize() const
{
return mData->getNumElements() * sizeof(GL_FLOAT) * osg::Vec4::num_components;
}
protected:
size_t mNumElements;
osg::ref_ptr<osg::Vec4Array> mData;
bool mDirty;
};
/*
* struct:
* vec4 diffuse
* vec4 ambient
* vec4 specular
* vec4 direction
*/
class SunlightBuffer : public LightBuffer
{
public:
enum Type {Diffuse, Ambient, Specular, Direction};
SunlightBuffer()
: LightBuffer(4)
{}
void setValue(Type type, const osg::Vec4& value)
{
if (getValue(type) == value)
return;
(*mData)[type] = value;
mDirty = true;
}
osg::Vec4 getValue(Type type)
{
return (*mData)[type];
}
};
/*
* struct:
* vec4 diffuse
* vec4 ambient
* vec4 position
* vec4 illumination (constant, linear, quadratic)
*/
class PointLightBuffer : public LightBuffer
{
public:
enum Type {Diffuse, Ambient, Position, Attenuation};
PointLightBuffer(int count)
: LightBuffer(4, count)
{}
void setValue(int index, Type type, const osg::Vec4& value)
{
if (getValue(index, type) == value)
return;
(*mData)[mNumElements * index + type] = value;
mDirty = true;
}
osg::Vec4 getValue(int index, Type type)
{
return (*mData)[mNumElements * index + type];
}
static constexpr int queryBlockSize(int sz)
{
return 4 * osg::Vec4::num_components * sizeof(GL_FLOAT) * sz;
}
};
class LightStateCache
{
@ -13,7 +147,7 @@ namespace SceneUtil
osg::Light* lastAppliedLight[8];
};
LightStateCache* getLightStateCache(unsigned int contextid)
LightStateCache* getLightStateCache(size_t contextid)
{
static std::vector<LightStateCache> cacheVector;
if (cacheVector.size() < contextid+1)
@ -21,14 +155,143 @@ namespace SceneUtil
return &cacheVector[contextid];
}
// Resets the modelview matrix to just the view matrix before applying lights.
SunlightStateAttribute::SunlightStateAttribute()
: mBuffer(new SunlightBuffer)
{
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
mBuffer->getData()->setBufferObject(ubo);
mUbb = new osg::UniformBufferBinding(9 , mBuffer->getData().get(), 0, mBuffer->blockSize());
}
SunlightStateAttribute::SunlightStateAttribute(const SunlightStateAttribute &copy, const osg::CopyOp &copyop)
: osg::StateAttribute(copy, copyop), mBuffer(copy.mBuffer)
{}
int SunlightStateAttribute::compare(const StateAttribute &sa) const
{
throw std::runtime_error("LightStateAttribute::compare: unimplemented");
}
void SunlightStateAttribute::setFromLight(const osg::Light* light)
{
mBuffer->setValue(SunlightBuffer::Diffuse, light->getDiffuse());
mBuffer->setValue(SunlightBuffer::Ambient, light->getAmbient());
mBuffer->setValue(SunlightBuffer::Specular, light->getSpecular());
mBuffer->setValue(SunlightBuffer::Direction, light->getPosition());
}
void SunlightStateAttribute::setStateSet(osg::StateSet* stateset, int mode)
{
stateset->setAttributeAndModes(mUbb, mode);
stateset->setAssociatedModes(this, mode);
mBuffer->dirty();
}
class DisableLight : public osg::StateAttribute
{
public:
DisableLight() : mIndex(0) {}
DisableLight(int index) : mIndex(index) {}
DisableLight(const DisableLight& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
: osg::StateAttribute(copy,copyop), mIndex(copy.mIndex) {}
osg::Object* cloneType() const override { return new DisableLight(mIndex); }
osg::Object* clone(const osg::CopyOp& copyop) const override { return new DisableLight(*this,copyop); }
bool isSameKindAs(const osg::Object* obj) const override { return dynamic_cast<const DisableLight *>(obj)!=nullptr; }
const char* libraryName() const override { return "SceneUtil"; }
const char* className() const override { return "DisableLight"; }
Type getType() const override { return LIGHT; }
unsigned int getMember() const override
{
return mIndex;
}
bool getModeUsage(ModeUsage & usage) const override
{
usage.usesMode(GL_LIGHT0 + mIndex);
return true;
}
int compare(const StateAttribute &sa) const override
{
throw std::runtime_error("DisableLight::compare: unimplemented");
}
void apply(osg::State& state) const override
{
int lightNum = GL_LIGHT0 + mIndex;
glLightfv( lightNum, GL_AMBIENT, mnullptr.ptr() );
glLightfv( lightNum, GL_DIFFUSE, mnullptr.ptr() );
glLightfv( lightNum, GL_SPECULAR, mnullptr.ptr() );
LightStateCache* cache = getLightStateCache(state.getContextID());
cache->lastAppliedLight[mIndex] = nullptr;
}
private:
size_t mIndex;
osg::Vec4f mnullptr;
};
class LightStateAttribute : public osg::StateAttribute
{
public:
LightStateAttribute() : mIndex(0) {}
LightStateAttribute(unsigned int index, const std::vector<osg::ref_ptr<osg::Light> >& lights) : mIndex(index), mLights(lights) {}
LightStateAttribute() : mBuffer(nullptr) {}
LightStateAttribute(const std::vector<osg::ref_ptr<osg::Light> >& lights, const osg::ref_ptr<PointLightBuffer>& buffer) : mLights(lights), mBuffer(buffer) {}
LightStateAttribute(const LightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
: osg::StateAttribute(copy,copyop), mLights(copy.mLights), mBuffer(copy.mBuffer) {}
int compare(const StateAttribute &sa) const override
{
throw std::runtime_error("LightStateAttribute::compare: unimplemented");
}
META_StateAttribute(NifOsg, LightStateAttribute, osg::StateAttribute::LIGHT)
void apply(osg::State& state) const override
{
if (mLights.empty())
return;
osg::Matrix modelViewMatrix = state.getModelViewMatrix();
state.applyModelViewMatrix(state.getInitialViewMatrix());
if (mBuffer)
{
for (size_t i = 0; i < mLights.size(); ++i)
{
mBuffer->setValue(i, PointLightBuffer::Diffuse, mLights[i]->getDiffuse());
mBuffer->setValue(i, PointLightBuffer::Ambient, mLights[i]->getAmbient());
mBuffer->setValue(i, PointLightBuffer::Position, mLights[i]->getPosition() * state.getModelViewMatrix());
mBuffer->setValue(i, PointLightBuffer::Attenuation,
osg::Vec4(mLights[i]->getConstantAttenuation(),
mLights[i]->getLinearAttenuation(),
mLights[i]->getQuadraticAttenuation(), 0.0));
}
if (mBuffer && mBuffer->isDirty())
mBuffer->dirty();
}
state.applyModelViewMatrix(modelViewMatrix);
}
private:
std::vector<osg::ref_ptr<osg::Light>> mLights;
osg::ref_ptr<PointLightBuffer> mBuffer;
};
class FFPLightStateAttribute : public osg::StateAttribute
{
public:
FFPLightStateAttribute() : mIndex(0) {}
FFPLightStateAttribute(size_t index, const std::vector<osg::ref_ptr<osg::Light> >& lights) : mIndex(index), mLights(lights) {}
FFPLightStateAttribute(const FFPLightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
: osg::StateAttribute(copy,copyop), mIndex(copy.mIndex), mLights(copy.mLights) {}
unsigned int getMember() const override
@ -38,17 +301,17 @@ namespace SceneUtil
bool getModeUsage(ModeUsage & usage) const override
{
for (unsigned int i=0; i<mLights.size(); ++i)
for (size_t i=0; i<mLights.size(); ++i)
usage.usesMode(GL_LIGHT0 + mIndex + i);
return true;
}
int compare(const StateAttribute &sa) const override
{
throw std::runtime_error("LightStateAttribute::compare: unimplemented");
throw std::runtime_error("FFPLightStateAttribute::compare: unimplemented");
}
META_StateAttribute(NifOsg, LightStateAttribute, osg::StateAttribute::LIGHT)
META_StateAttribute(NifOsg, FFPLightStateAttribute, osg::StateAttribute::LIGHT)
void apply(osg::State& state) const override
{
@ -60,7 +323,7 @@ namespace SceneUtil
LightStateCache* cache = getLightStateCache(state.getContextID());
for (unsigned int i=0; i<mLights.size(); ++i)
for (size_t i=0; i<mLights.size(); ++i)
{
osg::Light* current = cache->lastAppliedLight[i+mIndex];
if (current != mLights[i].get())
@ -90,14 +353,14 @@ namespace SceneUtil
}
private:
unsigned int mIndex;
size_t mIndex;
std::vector<osg::ref_ptr<osg::Light> > mLights;
std::vector<osg::ref_ptr<osg::Light>> mLights;
};
LightManager* findLightManager(const osg::NodePath& path)
{
for (unsigned int i=0;i<path.size(); ++i)
for (size_t i=0;i<path.size(); ++i)
{
if (LightManager* lightManager = dynamic_cast<LightManager*>(path[i]))
return lightManager;
@ -160,33 +423,161 @@ namespace SceneUtil
}
};
LightManager::LightManager()
class SunlightCallback : public osg::NodeCallback
{
public:
SunlightCallback(LightManager* lightManager) : mLightManager(lightManager) {}
void operator()(osg::Node* node, osg::NodeVisitor* nv) override
{
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
if (mLastFrameNumber != cv->getTraversalNumber())
{
mLastFrameNumber = cv->getTraversalNumber();
auto sun = mLightManager->getSunlight();
if (!sun)
return;
auto buf = mLightManager->getSunBuffer();
buf->setValue(SunlightBuffer::Diffuse, sun->getDiffuse());
buf->setValue(SunlightBuffer::Ambient, sun->getAmbient());
buf->setValue(SunlightBuffer::Specular, sun->getSpecular());
buf->setValue(SunlightBuffer::Direction, sun->getPosition() * *cv->getCurrentRenderStage()->getInitialViewMatrix());
if (buf->isDirty())
buf->dirty();
}
traverse(node, nv);
}
private:
LightManager* mLightManager;
size_t mLastFrameNumber;
};
LightManager::LightManager(bool ffp)
: mStartLight(0)
, mLightingMask(~0u)
, mSun(nullptr)
, mSunBuffer(nullptr)
, mFFP(ffp)
{
setUpdateCallback(new LightManagerUpdateCallback);
for (unsigned int i=0; i<8; ++i)
mDummies.push_back(new LightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light> >()));
if (usingFFP())
{
for (int i=0; i<getMaxLights(); ++i)
mDummies.push_back(new FFPLightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light> >()));
return;
}
auto* stateset = getOrCreateStateSet();
mSunBuffer = new SunlightBuffer();
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
mSunBuffer->getData()->setBufferObject(ubo);
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(9 , mSunBuffer->getData().get(), 0, mSunBuffer->blockSize());
stateset->setAttributeAndModes(ubb.get(), osg::StateAttribute::ON);
stateset->addUniform(new osg::Uniform("PointLightCount", 0));
addCullCallback(new SunlightCallback(this));
}
LightManager::LightManager(const LightManager &copy, const osg::CopyOp &copyop)
: osg::Group(copy, copyop)
, mStartLight(copy.mStartLight)
, mLightingMask(copy.mLightingMask)
, mSun(copy.mSun)
, mSunBuffer(copy.mSunBuffer)
, mFFP(copy.mFFP)
{
}
bool LightManager::usingFFP() const
{
return mFFP;
}
int LightManager::getMaxLights() const
{
if (usingFFP()) return LightManager::mFFPMaxLights;
return std::clamp(Settings::Manager::getInt("max lights", "Shaders"), 0, getMaxLightsInScene());
}
int LightManager::getMaxLightsInScene() const
{
static constexpr int max = 16384 / PointLightBuffer::queryBlockSize(1);
return max;
}
Shader::ShaderManager::DefineMap LightManager::getLightDefines() const
{
Shader::ShaderManager::DefineMap defines;
bool ffp = usingFFP();
defines["ffpLighting"] = ffp ? "1" : "0";
defines["sunDirection"] = ffp ? "gl_LightSource[0].position" : "Sun.direction";
defines["sunAmbient"] = ffp ? "gl_LightSource[0].ambient" : "Sun.ambient";
defines["sunDiffuse"] = ffp ? "gl_LightSource[0].diffuse" : "Sun.diffuse";
defines["sunSpecular"] = ffp ? "gl_LightSource[0].specular" : "Sun.specular";
defines["maxLights"] = std::to_string(getMaxLights());
defines["maxLightsInScene"] = std::to_string(getMaxLightsInScene());
return defines;
}
bool LightManager::queryNonFFPLightingSupport()
{
osg::GLExtensions* exts = osg::GLExtensions::Get(0, false);
if (!exts || !exts->isUniformBufferObjectSupported)
{
auto ffpWarning = Misc::StringUtils::format("GL_ARB_uniform_buffer_object not supported: Falling back to FFP %zu light limit. Can not set lights to %i."
, LightManager::mFFPMaxLights
, Settings::Manager::getInt("max lights", "Shaders"));
Log(Debug::Warning) << ffpWarning;
return false;
}
return true;
}
void LightManager::setLightingMask(unsigned int mask)
void LightManager::setLightingMask(size_t mask)
{
mLightingMask = mask;
}
unsigned int LightManager::getLightingMask() const
size_t LightManager::getLightingMask() const
{
return mLightingMask;
}
void LightManager::setStartLight(int start)
{
if (!usingFFP()) return;
mStartLight = start;
// Set default light state to zero
// This is necessary because shaders don't respect glDisable(GL_LIGHTX) so in addition to disabling
// we'll have to set a light state that has no visible effect
for (int i=start; i<getMaxLights(); ++i)
{
osg::ref_ptr<DisableLight> defaultLight (new DisableLight(i));
getOrCreateStateSet()->setAttributeAndModes(defaultLight, osg::StateAttribute::OFF);
}
}
int LightManager::getStartLight() const
{
return mStartLight;
}
void LightManager::update()
{
mLights.clear();
@ -200,7 +591,7 @@ namespace SceneUtil
}
}
void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum)
void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat, size_t frameNum)
{
LightSourceTransform l;
l.mLightSource = lightSource;
@ -211,19 +602,28 @@ namespace SceneUtil
mLights.push_back(l);
}
/* similar to the boost::hash_combine */
template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
void LightManager::setSunlight(osg::ref_ptr<osg::Light> sun)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
if (usingFFP()) return;
mSun = sun;
}
osg::ref_ptr<osg::Light> LightManager::getSunlight()
{
return mSun;
}
osg::ref_ptr<SunlightBuffer> LightManager::getSunBuffer()
{
return mSunBuffer;
}
osg::ref_ptr<osg::StateSet> LightManager::getLightListStateSet(const LightList &lightList, unsigned int frameNum)
osg::ref_ptr<osg::StateSet> LightManager::getLightListStateSet(const LightList &lightList, size_t frameNum)
{
// possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists)
size_t hash = 0;
for (unsigned int i=0; i<lightList.size();++i)
for (size_t i=0; i<lightList.size();++i)
hash_combine(hash, lightList[i]->mLightSource->getId());
LightStateSetMap& stateSetCache = mStateSetCache[frameNum%2];
@ -236,21 +636,35 @@ namespace SceneUtil
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
std::vector<osg::ref_ptr<osg::Light> > lights;
lights.reserve(lightList.size());
for (unsigned int i=0; i<lightList.size();++i)
for (size_t i=0; i<lightList.size();++i)
lights.emplace_back(lightList[i]->mLightSource->getLight(frameNum));
// the first light state attribute handles the actual state setting for all lights
// it's best to batch these up so that we don't need to touch the modelView matrix more than necessary
// don't use setAttributeAndModes, that does not support light indices!
stateset->setAttribute(new LightStateAttribute(mStartLight, std::move(lights)), osg::StateAttribute::ON);
for (unsigned int i=0; i<lightList.size(); ++i)
stateset->setMode(GL_LIGHT0 + mStartLight + i, osg::StateAttribute::ON);
// need to push some dummy attributes to ensure proper state tracking
// lights need to reset to their default when the StateSet is popped
for (unsigned int i=1; i<lightList.size(); ++i)
stateset->setAttribute(mDummies[i+mStartLight].get(), osg::StateAttribute::ON);
if (usingFFP())
{
// the first light state attribute handles the actual state setting for all lights
// it's best to batch these up so that we don't need to touch the modelView matrix more than necessary
// don't use setAttributeAndModes, that does not support light indices!
stateset->setAttribute(new FFPLightStateAttribute(mStartLight, std::move(lights)), osg::StateAttribute::ON);
for (size_t i=0; i<lightList.size(); ++i)
stateset->setMode(GL_LIGHT0 + mStartLight + i, osg::StateAttribute::ON);
// need to push some dummy attributes to ensure proper state tracking
// lights need to reset to their default when the StateSet is popped
for (size_t i=1; i<lightList.size(); ++i)
stateset->setAttribute(mDummies[i+mStartLight].get(), osg::StateAttribute::ON);
}
else
{
osg::ref_ptr<PointLightBuffer> buffer = new PointLightBuffer(lights.size());
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
buffer->getData()->setBufferObject(ubo);
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(8 ,buffer->getData().get(), 0, buffer->blockSize());
stateset->addUniform(new osg::Uniform("PointLightCount", (int)lights.size()));
stateset->setAttributeAndModes(ubb.get(), osg::StateAttribute::ON);
stateset->setAttribute(new LightStateAttribute(std::move(lights), buffer), osg::StateAttribute::ON);
}
stateSetCache.emplace(hash, stateset);
return stateset;
@ -262,7 +676,7 @@ namespace SceneUtil
return mLights;
}
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix)
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum)
{
osg::observer_ptr<osg::Camera> camPtr (camera);
std::map<osg::observer_ptr<osg::Camera>, LightSourceViewBoundCollection>::iterator it = mLightsInViewSpace.find(camPtr);
@ -286,75 +700,6 @@ namespace SceneUtil
return it->second;
}
class DisableLight : public osg::StateAttribute
{
public:
DisableLight() : mIndex(0) {}
DisableLight(int index) : mIndex(index) {}
DisableLight(const DisableLight& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
: osg::StateAttribute(copy,copyop), mIndex(copy.mIndex) {}
osg::Object* cloneType() const override { return new DisableLight(mIndex); }
osg::Object* clone(const osg::CopyOp& copyop) const override { return new DisableLight(*this,copyop); }
bool isSameKindAs(const osg::Object* obj) const override { return dynamic_cast<const DisableLight *>(obj)!=nullptr; }
const char* libraryName() const override { return "SceneUtil"; }
const char* className() const override { return "DisableLight"; }
Type getType() const override { return LIGHT; }
unsigned int getMember() const override
{
return mIndex;
}
bool getModeUsage(ModeUsage & usage) const override
{
usage.usesMode(GL_LIGHT0 + mIndex);
return true;
}
int compare(const StateAttribute &sa) const override
{
throw std::runtime_error("DisableLight::compare: unimplemented");
}
void apply(osg::State& state) const override
{
int lightNum = GL_LIGHT0 + mIndex;
glLightfv( lightNum, GL_AMBIENT, mnullptr.ptr() );
glLightfv( lightNum, GL_DIFFUSE, mnullptr.ptr() );
glLightfv( lightNum, GL_SPECULAR, mnullptr.ptr() );
LightStateCache* cache = getLightStateCache(state.getContextID());
cache->lastAppliedLight[mIndex] = nullptr;
}
private:
unsigned int mIndex;
osg::Vec4f mnullptr;
};
void LightManager::setStartLight(int start)
{
mStartLight = start;
// Set default light state to zero
// This is necessary because shaders don't respect glDisable(GL_LIGHTX) so in addition to disabling
// we'll have to set a light state that has no visible effect
for (int i=start; i<8; ++i)
{
osg::ref_ptr<DisableLight> defaultLight (new DisableLight(i));
getOrCreateStateSet()->setAttributeAndModes(defaultLight, osg::StateAttribute::OFF);
}
}
int LightManager::getStartLight() const
{
return mStartLight;
}
static int sLightId = 0;
LightSource::LightSource()
: mRadius(0.f)
{
@ -372,12 +717,6 @@ namespace SceneUtil
mLight[i] = new osg::Light(*copy.mLight[i].get(), copyop);
}
bool sortLights (const LightManager::LightSourceViewBound* left, const LightManager::LightSourceViewBound* right)
{
return left->mViewBound.center().length2() - left->mViewBound.radius2()*81 < right->mViewBound.center().length2() - right->mViewBound.radius2()*81;
}
void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv)
{
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
@ -413,7 +752,7 @@ namespace SceneUtil
// Don't use Camera::getViewMatrix, that one might be relative to another camera!
const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix();
const std::vector<LightManager::LightSourceViewBound>& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix);
const std::vector<LightManager::LightSourceViewBound>& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix, mLastFrameNumber);
// get the node bounds in view space
// NB do not node->getBound() * modelView, that would apply the node's transformation twice
@ -421,7 +760,7 @@ namespace SceneUtil
osg::Transform* transform = node->asTransform();
if (transform)
{
for (unsigned int i=0; i<transform->getNumChildren(); ++i)
for (size_t i=0; i<transform->getNumChildren(); ++i)
nodeBound.expandBy(transform->getChild(i)->getBound());
}
else
@ -430,7 +769,7 @@ namespace SceneUtil
transformBoundingSphere(mat, nodeBound);
mLightList.clear();
for (unsigned int i=0; i<lights.size(); ++i)
for (size_t i=0; i<lights.size(); ++i)
{
const LightManager::LightSourceViewBound& l = lights[i];
@ -443,7 +782,7 @@ namespace SceneUtil
}
if (!mLightList.empty())
{
unsigned int maxLights = static_cast<unsigned int> (8 - mLightManager->getStartLight());
size_t maxLights = mLightManager->getMaxLights() - mLightManager->getStartLight();
osg::StateSet* stateset = nullptr;

@ -8,6 +8,9 @@
#include <osg/Group>
#include <osg/NodeVisitor>
#include <osg/observer_ptr>
#include <osg/BufferIndexBinding>
#include <components/shader/shadermanager.hpp>
namespace osgUtil
{
@ -16,6 +19,27 @@ namespace osgUtil
namespace SceneUtil
{
class SunlightBuffer;
// Used to override sun. Rarely useful but necassary for local map.
class SunlightStateAttribute : public osg::StateAttribute
{
public:
SunlightStateAttribute();
SunlightStateAttribute(const SunlightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
int compare(const StateAttribute &sa) const override;
META_StateAttribute(NifOsg, SunlightStateAttribute, osg::StateAttribute::LIGHT)
void setFromLight(const osg::Light* light);
void setStateSet(osg::StateSet* stateset, int mode=osg::StateAttribute::ON);
private:
osg::ref_ptr<SunlightBuffer> mBuffer;
osg::ref_ptr<osg::UniformBufferBinding> mUbb;
};
/// LightSource managed by a LightManager.
/// @par Typically used for point lights. Spot lights are not supported yet. Directional lights affect the whole scene
@ -57,7 +81,7 @@ namespace SceneUtil
/// Get the osg::Light safe for modification in the given frame.
/// @par May be used externally to animate the light's color/attenuation properties,
/// and is used internally to synchronize the light's position with the position of the LightSource.
osg::Light* getLight(unsigned int frame)
osg::Light* getLight(size_t frame)
{
return mLight[frame % 2];
}
@ -83,10 +107,25 @@ namespace SceneUtil
class LightManager : public osg::Group
{
public:
struct LightSourceTransform
{
LightSource* mLightSource;
osg::Matrixf mWorldMatrix;
};
struct LightSourceViewBound
{
LightSource* mLightSource;
osg::BoundingSphere mViewBound;
};
typedef std::vector<const LightSourceViewBound*> LightList;
static bool queryNonFFPLightingSupport();
META_Node(SceneUtil, LightManager)
LightManager();
LightManager(bool ffp = true);
LightManager(const LightManager& copy, const osg::CopyOp& copyop);
@ -94,40 +133,36 @@ namespace SceneUtil
/// By default, it's ~0u i.e. always on.
/// If you have some views that do not require lighting, then set the Camera's cull mask to not include
/// the lightingMask for a much faster cull and rendering.
void setLightingMask (unsigned int mask);
unsigned int getLightingMask() const;
void setLightingMask (size_t mask);
size_t getLightingMask() const;
/// Set the first light index that should be used by this manager, typically the number of directional lights in the scene.
void setStartLight(int start);
int getStartLight() const;
/// Internal use only, called automatically by the LightManager's UpdateCallback
void update();
/// Internal use only, called automatically by the LightSource's UpdateCallback
void addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum);
struct LightSourceTransform
{
LightSource* mLightSource;
osg::Matrixf mWorldMatrix;
};
void addLight(LightSource* lightSource, const osg::Matrixf& worldMat, size_t frameNum);
const std::vector<LightSourceTransform>& getLights() const;
struct LightSourceViewBound
{
LightSource* mLightSource;
osg::BoundingSphere mViewBound;
};
const std::vector<LightSourceViewBound>& getLightsInViewSpace(osg::Camera* camera, const osg::RefMatrix* viewMatrix, size_t frameNum);
const std::vector<LightSourceViewBound>& getLightsInViewSpace(osg::Camera* camera, const osg::RefMatrix* viewMatrix);
osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList, size_t frameNum);
typedef std::vector<const LightSourceViewBound*> LightList;
void setSunlight(osg::ref_ptr<osg::Light> sun);
osg::ref_ptr<osg::Light> getSunlight();
osg::ref_ptr<SunlightBuffer> getSunBuffer();
osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList, unsigned int frameNum);
bool usingFFP() const;
int getMaxLights() const;
int getMaxLightsInScene() const;
Shader::ShaderManager::DefineMap getLightDefines() const;
private:
// Lights collected from the scene graph. Only valid during the cull traversal.
@ -144,7 +179,14 @@ namespace SceneUtil
int mStartLight;
unsigned int mLightingMask;
size_t mLightingMask;
osg::ref_ptr<osg::Light> mSun;
osg::ref_ptr<SunlightBuffer> mSunBuffer;
bool mFFP;
static constexpr int mFFPMaxLights = 8;
};
/// To receive lighting, objects must be decorated by a LightListCallback. Light list callbacks must be added via
@ -180,7 +222,7 @@ namespace SceneUtil
private:
LightManager* mLightManager;
unsigned int mLastFrameNumber;
size_t mLastFrameNumber;
LightManager::LightList mLightList;
std::set<SceneUtil::LightSource*> mIgnoredLightSources;
};

@ -9,12 +9,20 @@
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/debug/debuglog.hpp>
#include <components/misc/stringops.hpp>
namespace Shader
{
ShaderManager::ShaderManager(Resource::SceneManager* sceneManager)
: mSceneManager(sceneManager)
{
}
void ShaderManager::setShaderPath(const std::string &path)
{
mPath = path;
@ -344,6 +352,11 @@ namespace Shader
program->addShader(fragmentShader);
program->addBindAttribLocation("aOffset", 6);
program->addBindAttribLocation("aRotation", 7);
if (!mSceneManager->getFFPLighting())
{
program->addBindUniformBlock("PointLightBuffer", 8);
program->addBindUniformBlock("SunlightBuffer", 9);
}
found = mPrograms.insert(std::make_pair(std::make_pair(vertexShader, fragmentShader), program)).first;
}
return found->second;

@ -11,6 +11,11 @@
#include <osgViewer/Viewer>
namespace Resource
{
class SceneManager;
}
namespace Shader
{
@ -19,6 +24,9 @@ namespace Shader
class ShaderManager
{
public:
ShaderManager(Resource::SceneManager* sceneManager);
void setShaderPath(const std::string& path);
typedef std::map<std::string, std::string> DefineMap;
@ -59,6 +67,8 @@ namespace Shader
typedef std::map<std::pair<osg::ref_ptr<osg::Shader>, osg::ref_ptr<osg::Shader> >, osg::ref_ptr<osg::Program> > ProgramMap;
ProgramMap mPrograms;
Resource::SceneManager* mSceneManager;
std::mutex mMutex;
};

@ -442,6 +442,11 @@ apply lighting to environment maps = false
# This makes fogging independent from the viewing angle. Shaders will be used to render all objects.
radial fog = false
# Set maximum number of lights per object, does not include the sun.
# This feature may not work on your device, in which case it will fall back to the previous OpenGL limit of 8 lights.
# "[Shaders]/clamp lighting" must be set to 'false' and "[Shaders]/force shaders" must be set to 'true' for this to take effect.
max lights = 16
[Input]
# Capture control of the cursor prevent movement outside the window.

@ -25,6 +25,7 @@ set(SHADER_FILES
shadowcasting_vertex.glsl
shadowcasting_fragment.glsl
vertexcolors.glsl
sun.glsl
)
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}")

@ -1,4 +1,5 @@
#version 120
#extension GL_ARB_uniform_buffer_object : enable
#define GROUNDCOVER

@ -1,5 +1,7 @@
#version 120
#extension GL_ARB_uniform_buffer_object : enable
#define GROUNDCOVER
attribute vec4 aOffset;

@ -1,13 +1,62 @@
#define MAX_LIGHTS 8
#if !@ffpLighting
void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal)
#include "sun.glsl"
#define getLight PointLights
struct PointLight
{
vec4 diffuse;
vec4 ambient;
vec4 position;
vec4 attenuation;
};
uniform mat4 osg_ViewMatrix;
uniform int PointLightCount;
uniform int PointLightIndex[@maxLights];
layout(std140) uniform PointLightBuffer
{
PointLight PointLights[@maxLights];
};
#else
#define getLight gl_LightSource
#endif
void perLightSun(out vec3 ambientOut, out vec3 diffuseOut, vec3 viewPos, vec3 viewNormal)
{
vec3 lightDir = @sunDirection.xyz;
lightDir = normalize(lightDir);
ambientOut = @sunAmbient.xyz;
float lambert = dot(viewNormal.xyz, lightDir);
#ifndef GROUNDCOVER
lambert = max(lambert, 0.0);
#else
float eyeCosine = dot(normalize(viewPos), viewNormal.xyz);
if (lambert < 0.0)
{
lambert = -lambert;
eyeCosine = -eyeCosine;
}
lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0);
#endif
diffuseOut = @sunDiffuse.xyz * lambert;
}
void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal)
{
vec3 lightDir = gl_LightSource[lightIndex].position.xyz - viewPos * gl_LightSource[lightIndex].position.w;
vec3 lightDir = getLight[lightIndex].position.xyz - viewPos;
//vec3 lightDir = (osg_ViewMatrix * vec4(getLight[lightIndex].position, 1.0)).xyz - viewPos;
float lightDistance = length(lightDir);
lightDir = normalize(lightDir);
float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0);
ambientOut = gl_LightSource[lightIndex].ambient.xyz * illumination;
float illumination = clamp(1.0 / (getLight[lightIndex].attenuation.x + getLight[lightIndex].attenuation.y * lightDistance + getLight[lightIndex].attenuation.z * lightDistance * lightDistance), 0.0, 1.0);
ambientOut = getLight[lightIndex].ambient.xyz * illumination;
float lambert = dot(viewNormal.xyz, lightDir) * illumination;
#ifndef GROUNDCOVER
@ -21,7 +70,7 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie
}
lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0);
#endif
diffuseOut = gl_LightSource[lightIndex].diffuse.xyz * lambert;
diffuseOut = getLight[lightIndex].diffuse.xyz * lambert;
}
#if PER_PIXEL_LIGHTING
@ -32,7 +81,8 @@ void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 a
{
vec3 ambientOut, diffuseOut;
// This light gets added a second time in the loop to fix Mesa users' slowdown, so we need to negate its contribution here.
perLight(ambientOut, diffuseOut, 0, viewPos, viewNormal);
perLightSun(ambientOut, diffuseOut, viewPos, viewNormal);
#if PER_PIXEL_LIGHTING
diffuseLight = diffuseOut * shadowing - diffuseOut;
#else
@ -40,22 +90,31 @@ void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 a
diffuseLight = -diffuseOut;
#endif
ambientLight = gl_LightModel.ambient.xyz;
for (int i=0; i<MAX_LIGHTS; ++i)
#if !@ffpLighting
perLightSun(ambientOut, diffuseOut, viewPos, viewNormal);
ambientLight += ambientOut;
diffuseLight += diffuseOut;
for (int i=0; i<PointLightCount; ++i)
{
perLight(ambientOut, diffuseOut, i, viewPos, viewNormal);
perLightPoint(ambientOut, diffuseOut, i, viewPos, viewNormal);
#else
for (int i=0; i<@maxLights; ++i)
{
perLightPoint(ambientOut, diffuseOut, i, viewPos, viewNormal);
#endif
ambientLight += ambientOut;
diffuseLight += diffuseOut;
}
}
vec3 getSpecular(vec3 viewNormal, vec3 viewDirection, float shininess, vec3 matSpec)
{
vec3 lightDir = normalize(gl_LightSource[0].position.xyz);
vec3 lightDir = normalize(@sunDirection.xyz);
float NdotL = dot(viewNormal, lightDir);
if (NdotL <= 0.0)
return vec3(0.0);
vec3 halfVec = normalize(lightDir - viewDirection);
float NdotH = dot(viewNormal, halfVec);
return pow(max(NdotH, 0.0), max(1e-4, shininess)) * gl_LightSource[0].specular.xyz * matSpec;
return pow(max(NdotH, 0.0), max(1e-4, shininess)) * @sunSpecular.xyz * matSpec;
}

@ -1,5 +1,7 @@
#version 120
#extension GL_ARB_uniform_buffer_object : enable
#if @diffuseMap
uniform sampler2D diffuseMap;
varying vec2 diffuseMapUV;
@ -66,8 +68,8 @@ varying vec3 passNormal;
#include "vertexcolors.glsl"
#include "shadows_fragment.glsl"
#include "lighting.glsl"
#include "parallax.glsl"
#include "lighting.glsl"
void main()
{

@ -1,5 +1,7 @@
#version 120
#extension GL_ARB_uniform_buffer_object : enable
#if @diffuseMap
varying vec2 diffuseMapUV;
#endif
@ -51,7 +53,6 @@ varying vec3 passNormal;
#include "vertexcolors.glsl"
#include "shadows_vertex.glsl"
#include "lighting.glsl"
void main(void)

@ -0,0 +1,14 @@
#if !@ffpLighting
struct Sunlight
{
vec4 diffuse;
vec4 ambient;
vec4 specular;
vec4 direction;
};
layout(std140) uniform SunlightBuffer
{
Sunlight Sun;
};
#endif

@ -1,5 +1,7 @@
#version 120
#extension GL_ARB_uniform_buffer_object : enable
varying vec2 uv;
uniform sampler2D diffuseMap;
@ -26,8 +28,8 @@ varying vec3 passNormal;
#include "vertexcolors.glsl"
#include "shadows_fragment.glsl"
#include "lighting.glsl"
#include "parallax.glsl"
#include "lighting.glsl"
void main()
{

@ -1,5 +1,7 @@
#version 120
#extension GL_ARB_uniform_buffer_object : enable
varying vec2 uv;
varying float euclideanDepth;
varying float linearDepth;
@ -15,7 +17,6 @@ varying vec3 passNormal;
#include "vertexcolors.glsl"
#include "shadows_vertex.glsl"
#include "lighting.glsl"
void main(void)

@ -1,5 +1,7 @@
#version 120
#extension GL_ARB_uniform_buffer_object : enable
#define REFRACTION @refraction_enabled
// Inspired by Blender GLSL Water by martinsh ( https://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html )
@ -143,6 +145,7 @@ uniform vec3 nodePosition;
uniform float rainIntensity;
#include "shadows_fragment.glsl"
#include "sun.glsl"
float frustumDepth;
@ -192,7 +195,7 @@ void main(void)
normal3 * midWaves.y + normal4 * smallWaves.x + normal5 * smallWaves.y + rippleAdd);
normal = normalize(vec3(-normal.x * bump, -normal.y * bump, normal.z));
vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(gl_LightSource[0].position.xyz, 0.0)).xyz);
vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(@sunDirection.xyz, 0.0)).xyz);
vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz;
vec3 vVec = normalize(position.xyz - cameraPos.xyz);
@ -247,11 +250,11 @@ void main(void)
vec3 scatterColour = mix(SCATTER_COLOUR*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0));
vec3 lR = reflect(lVec, lNormal);
float lightScatter = clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0) * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0);
gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz + vec3(rainRipple.w) * 0.2;
gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * @sunSpecular.xyz + vec3(rainRipple.w) * 0.2;
gl_FragData[0].w = 1.0;
#else
gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz + vec3(rainRipple.w) * 0.7;
gl_FragData[0].w = clamp(fresnel*6.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0);
gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * @sunSpecular.xyz + vec3(rainRipple.w) * 0.7;
gl_FragData[0].w = clamp(fresnel*6.0 + specular * @sunSpecular.w, 0.0, 1.0); //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0);
#endif
// fog

Loading…
Cancel
Save