mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 07:45:39 +00:00
initial commit
This commit is contained in:
parent
2b144ff3dd
commit
dda735c54a
23 changed files with 710 additions and 178 deletions
|
@ -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,15 +155,53 @@ namespace SceneUtil
|
|||
return &cacheVector[contextid];
|
||||
}
|
||||
|
||||
// Resets the modelview matrix to just the view matrix before applying lights.
|
||||
class LightStateAttribute : public osg::StateAttribute
|
||||
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 ©, const osg::CopyOp ©op)
|
||||
: 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:
|
||||
LightStateAttribute() : mIndex(0) {}
|
||||
LightStateAttribute(unsigned int index, const std::vector<osg::ref_ptr<osg::Light> >& lights) : mIndex(index), mLights(lights) {}
|
||||
DisableLight() : mIndex(0) {}
|
||||
DisableLight(int index) : mIndex(index) {}
|
||||
|
||||
LightStateAttribute(const LightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
|
||||
: osg::StateAttribute(copy,copyop), mIndex(copy.mIndex), mLights(copy.mLights) {}
|
||||
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
|
||||
{
|
||||
|
@ -38,11 +210,40 @@ namespace SceneUtil
|
|||
|
||||
bool getModeUsage(ModeUsage & usage) const override
|
||||
{
|
||||
for (unsigned int i=0; i<mLights.size(); ++i)
|
||||
usage.usesMode(GL_LIGHT0 + mIndex + i);
|
||||
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() : 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");
|
||||
|
@ -50,6 +251,68 @@ namespace SceneUtil
|
|||
|
||||
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
|
||||
{
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
bool getModeUsage(ModeUsage & usage) const override
|
||||
{
|
||||
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("FFPLightStateAttribute::compare: unimplemented");
|
||||
}
|
||||
|
||||
META_StateAttribute(NifOsg, FFPLightStateAttribute, osg::StateAttribute::LIGHT)
|
||||
|
||||
void apply(osg::State& state) const override
|
||||
{
|
||||
if (mLights.empty())
|
||||
|
@ -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 ©, const osg::CopyOp ©op)
|
||||
: osg::Group(copy, copyop)
|
||||
, mStartLight(copy.mStartLight)
|
||||
, mLightingMask(copy.mLightingMask)
|
||||
, mSun(copy.mSun)
|
||||
, mSunBuffer(copy.mSunBuffer)
|
||||
, mFFP(copy.mFFP)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LightManager::setLightingMask(unsigned int mask)
|
||||
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(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::StateSet> LightManager::getLightListStateSet(const LightList &lightList, unsigned int frameNum)
|
||||
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, 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);
|
||||
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 (unsigned int i=0; i<lightList.size(); ++i)
|
||||
stateset->setMode(GL_LIGHT0 + mStartLight + i, 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 (unsigned int i=1; i<lightList.size(); ++i)
|
||||
stateset->setAttribute(mDummies[i+mStartLight].get(), 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,51 +107,62 @@ namespace SceneUtil
|
|||
class LightManager : public osg::Group
|
||||
{
|
||||
public:
|
||||
|
||||
META_Node(SceneUtil, LightManager)
|
||||
|
||||
LightManager();
|
||||
|
||||
LightManager(const LightManager& copy, const osg::CopyOp& copyop);
|
||||
|
||||
/// @param mask This mask is compared with the current Camera's cull mask to determine if lighting is desired.
|
||||
/// 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;
|
||||
|
||||
/// 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;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
typedef std::vector<const LightSourceViewBound*> LightList;
|
||||
|
||||
osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList, unsigned int frameNum);
|
||||
static bool queryNonFFPLightingSupport();
|
||||
|
||||
META_Node(SceneUtil, LightManager)
|
||||
|
||||
LightManager(bool ffp = true);
|
||||
|
||||
LightManager(const LightManager& copy, const osg::CopyOp& copyop);
|
||||
|
||||
/// @param mask This mask is compared with the current Camera's cull mask to determine if lighting is desired.
|
||||
/// 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 (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, size_t frameNum);
|
||||
|
||||
const std::vector<LightSourceTransform>& getLights() const;
|
||||
|
||||
const std::vector<LightSourceViewBound>& getLightsInViewSpace(osg::Camera* camera, const osg::RefMatrix* viewMatrix, size_t frameNum);
|
||||
|
||||
osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList, size_t frameNum);
|
||||
|
||||
void setSunlight(osg::ref_ptr<osg::Light> sun);
|
||||
osg::ref_ptr<osg::Light> getSunlight();
|
||||
|
||||
osg::ref_ptr<SunlightBuffer> getSunBuffer();
|
||||
|
||||
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
|
||||
{
|
||||
vec3 lightDir = gl_LightSource[lightIndex].position.xyz - viewPos * gl_LightSource[lightIndex].position.w;
|
||||
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 = 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)
|
||||
|
|
14
files/shaders/sun.glsl
Normal file
14
files/shaders/sun.glsl
Normal file
|
@ -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…
Reference in a new issue