mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-06 17:15:35 +00:00
Add shared UBO
This commit is contained in:
parent
c5ea966f24
commit
9d9074c244
15 changed files with 253 additions and 127 deletions
|
@ -83,6 +83,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
||||||
defines["clamp"] = "1"; // Clamp lighting
|
defines["clamp"] = "1"; // Clamp lighting
|
||||||
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
||||||
defines["radialFog"] = "0";
|
defines["radialFog"] = "0";
|
||||||
|
defines["ffpLighting"] = "0";
|
||||||
for (const auto& define : shadowDefines)
|
for (const auto& define : shadowDefines)
|
||||||
defines[define.first] = define.second;
|
defines[define.first] = define.second;
|
||||||
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
||||||
|
|
|
@ -72,6 +72,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f)
|
||||||
mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
|
mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
|
||||||
|
|
||||||
SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager;
|
SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager;
|
||||||
|
lightMgr->setStartLight(1);
|
||||||
lightMgr->setLightingMask(Mask_Lighting);
|
lightMgr->setLightingMask(Mask_Lighting);
|
||||||
mRootNode = lightMgr;
|
mRootNode = lightMgr;
|
||||||
|
|
||||||
|
|
|
@ -1613,7 +1613,7 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior();
|
bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior();
|
||||||
|
|
||||||
SceneUtil::addLight(parent, esmLight, Mask_ParticleSystem, Mask_Lighting, exterior);
|
SceneUtil::addLight(parent, esmLight, Mask_ParticleSystem, Mask_Lighting, exterior, mResourceSystem->getSceneManager()->getFFPLighting());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture)
|
void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, const std::string& texture)
|
||||||
|
|
|
@ -213,9 +213,11 @@ namespace MWRender
|
||||||
resourceSystem->getSceneManager()->setAutoUseSpecularMaps(Settings::Manager::getBool("auto use object specular maps", "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()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders"));
|
||||||
resourceSystem->getSceneManager()->setApplyLightingToEnvMaps(Settings::Manager::getBool("apply lighting to environment maps", "Shaders"));
|
resourceSystem->getSceneManager()->setApplyLightingToEnvMaps(Settings::Manager::getBool("apply lighting to environment maps", "Shaders"));
|
||||||
resourceSystem->getSceneManager()->setFFPLighting(clampLighting || !forceShaders || !SceneUtil::LightManager::queryNonFFPLightingSupport());
|
bool useFFP = clampLighting || !forceShaders || !SceneUtil::LightManager::queryNonFFPLightingSupport();
|
||||||
|
resourceSystem->getSceneManager()->setFFPLighting(useFFP);
|
||||||
osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(mResourceSystem->getSceneManager()->getFFPLighting());
|
resourceSystem->getSceneManager()->getShaderManager().setFFPLighting(useFFP);
|
||||||
|
|
||||||
|
osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(useFFP);
|
||||||
sceneRoot->setLightingMask(Mask_Lighting);
|
sceneRoot->setLightingMask(Mask_Lighting);
|
||||||
mSceneRoot = sceneRoot;
|
mSceneRoot = sceneRoot;
|
||||||
sceneRoot->setStartLight(1);
|
sceneRoot->setStartLight(1);
|
||||||
|
|
|
@ -646,7 +646,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R
|
||||||
program->addShader(vertexShader);
|
program->addShader(vertexShader);
|
||||||
program->addShader(fragmentShader);
|
program->addShader(fragmentShader);
|
||||||
if (!mResourceSystem->getSceneManager()->getFFPLighting())
|
if (!mResourceSystem->getSceneManager()->getFFPLighting())
|
||||||
program->addBindUniformBlock("SunlightBuffer", 9);
|
program->addBindUniformBlock("SunlightBuffer", 0);
|
||||||
shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON);
|
shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON);
|
||||||
|
|
||||||
node->setStateSet(shaderStateset);
|
node->setStateSet(shaderStateset);
|
||||||
|
|
|
@ -220,7 +220,7 @@ namespace Resource
|
||||||
|
|
||||||
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
|
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
|
||||||
: ResourceManager(vfs)
|
: ResourceManager(vfs)
|
||||||
, mShaderManager(new Shader::ShaderManager(this))
|
, mShaderManager(new Shader::ShaderManager)
|
||||||
, mForceShaders(false)
|
, mForceShaders(false)
|
||||||
, mClampLighting(true)
|
, mClampLighting(true)
|
||||||
, mAutoUseNormalMaps(false)
|
, mAutoUseNormalMaps(false)
|
||||||
|
|
|
@ -11,13 +11,14 @@
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
LightController::LightController()
|
LightController::LightController(bool useFFPLighting)
|
||||||
: mType(LT_Normal)
|
: mType(LT_Normal)
|
||||||
, mPhase(0.25f + Misc::Rng::rollClosedProbability() * 0.75f)
|
, mPhase(0.25f + Misc::Rng::rollClosedProbability() * 0.75f)
|
||||||
, mBrightness(0.675f)
|
, mBrightness(0.675f)
|
||||||
, mStartTime(0.0)
|
, mStartTime(0.0)
|
||||||
, mLastTime(0.0)
|
, mLastTime(0.0)
|
||||||
, mTicksToAdvance(0.f)
|
, mTicksToAdvance(0.f)
|
||||||
|
, mFFPLighting(useFFPLighting)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +63,11 @@ namespace SceneUtil
|
||||||
mPhase = mPhase <= 0.5f ? 1.f : 0.25f;
|
mPhase = mPhase <= 0.5f ? 1.f : 0.25f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static_cast<SceneUtil::LightSource*>(node)->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * mBrightness);
|
auto* lightSource = static_cast<SceneUtil::LightSource*>(node);
|
||||||
|
if (mFFPLighting)
|
||||||
|
lightSource->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * mBrightness);
|
||||||
|
else
|
||||||
|
lightSource->setBrightness(nv->getTraversalNumber(), mBrightness);
|
||||||
|
|
||||||
traverse(node, nv);
|
traverse(node, nv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace SceneUtil
|
||||||
LT_PulseSlow
|
LT_PulseSlow
|
||||||
};
|
};
|
||||||
|
|
||||||
LightController();
|
LightController(bool useFFPLighting=true);
|
||||||
|
|
||||||
void setType(LightType type);
|
void setType(LightType type);
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ namespace SceneUtil
|
||||||
double mStartTime;
|
double mStartTime;
|
||||||
double mLastTime;
|
double mLastTime;
|
||||||
float mTicksToAdvance;
|
float mTicksToAdvance;
|
||||||
|
bool mFFPLighting;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "lightmanager.hpp"
|
#include "lightmanager.hpp"
|
||||||
|
|
||||||
#include <osg/BufferObject>
|
#include <osg/BufferObject>
|
||||||
|
#include <osg/BufferIndexBinding>
|
||||||
|
|
||||||
#include <osgUtil/CullVisitor>
|
#include <osgUtil/CullVisitor>
|
||||||
|
|
||||||
|
@ -12,6 +13,8 @@
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
|
#include "apps/openmw/mwrender/vismask.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
/* similar to the boost::hash_combine */
|
/* similar to the boost::hash_combine */
|
||||||
|
@ -32,6 +35,10 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
static int sLightId = 0;
|
static int sLightId = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Internal Data Structures
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class LightBuffer : public osg::Referenced
|
class LightBuffer : public osg::Referenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -59,11 +66,6 @@ namespace SceneUtil
|
||||||
mDirty = false;
|
mDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int blockSize() const
|
|
||||||
{
|
|
||||||
return mData->getNumElements() * sizeof(GL_FLOAT) * osg::Vec4::num_components;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
size_t mNumElements;
|
size_t mNumElements;
|
||||||
osg::ref_ptr<osg::Vec4Array> mData;
|
osg::ref_ptr<osg::Vec4Array> mData;
|
||||||
|
@ -114,7 +116,7 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Type {Diffuse, Ambient, Position, Attenuation};
|
enum Type {Position, Diffuse, Ambient, Attenuation};
|
||||||
|
|
||||||
PointLightBuffer(int count)
|
PointLightBuffer(int count)
|
||||||
: LightBuffer(4, count)
|
: LightBuffer(4, count)
|
||||||
|
@ -124,9 +126,10 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
if (getValue(index, type) == value)
|
if (getValue(index, type) == value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
(*mData)[mNumElements * index + type] = value;
|
int indexOffset = mNumElements * index + type;
|
||||||
|
(*mData)[indexOffset] = value;
|
||||||
|
|
||||||
mDirty = true;
|
mDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,12 +158,16 @@ namespace SceneUtil
|
||||||
return &cacheVector[contextid];
|
return &cacheVector[contextid];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// State Attributes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SunlightStateAttribute::SunlightStateAttribute()
|
SunlightStateAttribute::SunlightStateAttribute()
|
||||||
: mBuffer(new SunlightBuffer)
|
: mBuffer(new SunlightBuffer)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
||||||
mBuffer->getData()->setBufferObject(ubo);
|
mBuffer->getData()->setBufferObject(ubo);
|
||||||
mUbb = new osg::UniformBufferBinding(9 , mBuffer->getData().get(), 0, mBuffer->blockSize());
|
mUbb = new osg::UniformBufferBinding(0, mBuffer->getData().get(), 0, mBuffer->getData()->getTotalDataSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
SunlightStateAttribute::SunlightStateAttribute(const SunlightStateAttribute ©, const osg::CopyOp ©op)
|
SunlightStateAttribute::SunlightStateAttribute(const SunlightStateAttribute ©, const osg::CopyOp ©op)
|
||||||
|
@ -235,56 +242,6 @@ namespace SceneUtil
|
||||||
osg::Vec4f mnullptr;
|
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
class FFPLightStateAttribute : public osg::StateAttribute
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -368,6 +325,10 @@ namespace SceneUtil
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Node Callbacks
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Set on a LightSource. Adds the light source to its light manager for the current frame.
|
// Set on a LightSource. Adds the light source to its light manager for the current frame.
|
||||||
// This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager.
|
// This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager.
|
||||||
class CollectLightCallback : public osg::NodeCallback
|
class CollectLightCallback : public osg::NodeCallback
|
||||||
|
@ -460,6 +421,42 @@ namespace SceneUtil
|
||||||
size_t mLastFrameNumber;
|
size_t mLastFrameNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LightManagerStateAttribute : public osg::StateAttribute
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LightManagerStateAttribute() : mLightManager(nullptr) {}
|
||||||
|
LightManagerStateAttribute(LightManager* lightManager) : mLightManager(lightManager) {}
|
||||||
|
|
||||||
|
LightManagerStateAttribute(const LightManagerStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
|
||||||
|
: osg::StateAttribute(copy,copyop),mLightManager(copy.mLightManager) {}
|
||||||
|
|
||||||
|
int compare(const StateAttribute &sa) const override
|
||||||
|
{
|
||||||
|
throw std::runtime_error("LightManagerStateAttribute::compare: unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
META_StateAttribute(NifOsg, LightManagerStateAttribute, osg::StateAttribute::LIGHT)
|
||||||
|
|
||||||
|
void apply(osg::State& state) const override
|
||||||
|
{
|
||||||
|
osg::Matrix modelViewMatrix = state.getModelViewMatrix();
|
||||||
|
|
||||||
|
state.applyModelViewMatrix(state.getInitialViewMatrix());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mLightManager->mPointLightProxyData.size(); i++)
|
||||||
|
{
|
||||||
|
auto& data = mLightManager->mPointLightProxyData[i];
|
||||||
|
auto pos = data.mPosition * state.getInitialViewMatrix();
|
||||||
|
pos[3] = data.mBrightness;
|
||||||
|
mLightManager->mPointBuffer->setValue(i, PointLightBuffer::Position, pos);
|
||||||
|
}
|
||||||
|
state.applyModelViewMatrix(modelViewMatrix);
|
||||||
|
mLightManager->mPointBuffer->dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
LightManager* mLightManager;
|
||||||
|
};
|
||||||
|
|
||||||
LightManager::LightManager(bool ffp)
|
LightManager::LightManager(bool ffp)
|
||||||
: mStartLight(0)
|
: mStartLight(0)
|
||||||
, mLightingMask(~0u)
|
, mLightingMask(~0u)
|
||||||
|
@ -467,28 +464,44 @@ namespace SceneUtil
|
||||||
, mSunBuffer(nullptr)
|
, mSunBuffer(nullptr)
|
||||||
, mFFP(ffp)
|
, mFFP(ffp)
|
||||||
{
|
{
|
||||||
setUpdateCallback(new LightManagerUpdateCallback);
|
|
||||||
|
|
||||||
if (usingFFP())
|
if (usingFFP())
|
||||||
{
|
{
|
||||||
for (int i=0; i<getMaxLights(); ++i)
|
for (int i=0; i<getMaxLights(); ++i)
|
||||||
mDummies.push_back(new FFPLightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light> >()));
|
mDummies.push_back(new FFPLightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light> >()));
|
||||||
|
setUpdateCallback(new LightManagerUpdateCallback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* stateset = getOrCreateStateSet();
|
auto* stateset = getOrCreateStateSet();
|
||||||
|
|
||||||
mSunBuffer = new SunlightBuffer();
|
{ // sunlight UBO data
|
||||||
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
mSunBuffer = new SunlightBuffer();
|
||||||
mSunBuffer->getData()->setBufferObject(ubo);
|
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
||||||
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(9 , mSunBuffer->getData().get(), 0, mSunBuffer->blockSize());
|
mSunBuffer->getData()->setBufferObject(ubo);
|
||||||
stateset->setAttributeAndModes(ubb.get(), osg::StateAttribute::ON);
|
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(0, mSunBuffer->getData().get(), 0, mSunBuffer->getData()->getTotalDataSize());
|
||||||
|
stateset->setAttributeAndModes(ubb.get(), osg::StateAttribute::ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // point lights UBO data
|
||||||
|
mPointBuffer = new PointLightBuffer(getMaxLightsInScene());
|
||||||
|
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
||||||
|
mPointBuffer->getData()->setBufferObject(ubo);
|
||||||
|
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(1, mPointBuffer->getData().get(), 0, mPointBuffer->getData()->getTotalDataSize());
|
||||||
|
stateset->setAttributeAndModes(ubb.get(), osg::StateAttribute::ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPointLightProxyData.resize(getMaxLightsInScene());
|
||||||
|
|
||||||
|
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE);
|
||||||
|
stateset->setAttribute(new LightManagerStateAttribute(this), osg::StateAttribute::ON);
|
||||||
stateset->addUniform(new osg::Uniform("PointLightCount", 0));
|
stateset->addUniform(new osg::Uniform("PointLightCount", 0));
|
||||||
|
|
||||||
|
setUpdateCallback(new LightManagerUpdateCallback);
|
||||||
addCullCallback(new SunlightCallback(this));
|
addCullCallback(new SunlightCallback(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op)
|
LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op)
|
||||||
: osg::Group(copy, copyop)
|
: osg::Group(copy, copyop)
|
||||||
, mStartLight(copy.mStartLight)
|
, mStartLight(copy.mStartLight)
|
||||||
|
@ -507,7 +520,7 @@ namespace SceneUtil
|
||||||
int LightManager::getMaxLights() const
|
int LightManager::getMaxLights() const
|
||||||
{
|
{
|
||||||
if (usingFFP()) return LightManager::mFFPMaxLights;
|
if (usingFFP()) return LightManager::mFFPMaxLights;
|
||||||
return std::clamp(Settings::Manager::getInt("max lights", "Shaders"), 0, getMaxLightsInScene());
|
return std::clamp(Settings::Manager::getInt("max lights", "Shaders"),LightManager::mFFPMaxLights , getMaxLightsInScene());
|
||||||
}
|
}
|
||||||
|
|
||||||
int LightManager::getMaxLightsInScene() const
|
int LightManager::getMaxLightsInScene() const
|
||||||
|
@ -579,16 +592,18 @@ namespace SceneUtil
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightManager::update()
|
void LightManager::update()
|
||||||
{
|
{
|
||||||
mLights.clear();
|
mLights.clear();
|
||||||
mLightsInViewSpace.clear();
|
mLightsInViewSpace.clear();
|
||||||
|
|
||||||
// do an occasional cleanup for orphaned lights
|
// Do an occasional cleanup for orphaned lights.
|
||||||
for (int i=0; i<2; ++i)
|
for (int i=0; i<2; ++i)
|
||||||
{
|
{
|
||||||
if (mStateSetCache[i].size() > 5000)
|
if (mStateSetCache[i].size() > 5000 || mIndexNeedsRecompiling)
|
||||||
mStateSetCache[i].clear();
|
mStateSetCache[i].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mIndexNeedsRecompiling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat, size_t frameNum)
|
void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat, size_t frameNum)
|
||||||
|
@ -599,7 +614,8 @@ namespace SceneUtil
|
||||||
lightSource->getLight(frameNum)->setPosition(osg::Vec4f(worldMat.getTrans().x(),
|
lightSource->getLight(frameNum)->setPosition(osg::Vec4f(worldMat.getTrans().x(),
|
||||||
worldMat.getTrans().y(),
|
worldMat.getTrans().y(),
|
||||||
worldMat.getTrans().z(), 1.f));
|
worldMat.getTrans().z(), 1.f));
|
||||||
mLights.push_back(l);
|
if (mLights.size() < static_cast<size_t>(getMaxLightsInScene()))
|
||||||
|
mLights.emplace_back(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightManager::setSunlight(osg::ref_ptr<osg::Light> sun)
|
void LightManager::setSunlight(osg::ref_ptr<osg::Light> sun)
|
||||||
|
@ -627,20 +643,21 @@ namespace SceneUtil
|
||||||
hash_combine(hash, lightList[i]->mLightSource->getId());
|
hash_combine(hash, lightList[i]->mLightSource->getId());
|
||||||
|
|
||||||
LightStateSetMap& stateSetCache = mStateSetCache[frameNum%2];
|
LightStateSetMap& stateSetCache = mStateSetCache[frameNum%2];
|
||||||
|
|
||||||
LightStateSetMap::iterator found = stateSetCache.find(hash);
|
LightStateSetMap::iterator found = stateSetCache.find(hash);
|
||||||
if (found != stateSetCache.end())
|
if (found != stateSetCache.end())
|
||||||
return found->second;
|
return found->second;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
|
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
|
||||||
std::vector<osg::ref_ptr<osg::Light> > lights;
|
|
||||||
lights.reserve(lightList.size());
|
|
||||||
for (size_t i=0; i<lightList.size();++i)
|
|
||||||
lights.emplace_back(lightList[i]->mLightSource->getLight(frameNum));
|
|
||||||
|
|
||||||
if (usingFFP())
|
if (usingFFP())
|
||||||
{
|
{
|
||||||
|
std::vector<osg::ref_ptr<osg::Light> > lights;
|
||||||
|
lights.reserve(lightList.size());
|
||||||
|
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
|
// 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
|
// 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!
|
// don't use setAttributeAndModes, that does not support light indices!
|
||||||
|
@ -656,14 +673,18 @@ namespace SceneUtil
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
osg::ref_ptr<PointLightBuffer> buffer = new PointLightBuffer(lights.size());
|
osg::ref_ptr<osg::IntArray> indices = new osg::IntArray(getMaxLights());
|
||||||
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
osg::ref_ptr<osg::Uniform> indicesUni = new osg::Uniform(osg::Uniform::Type::INT, "PointLightIndex", indices->size());
|
||||||
buffer->getData()->setBufferObject(ubo);
|
int validCount = 0;
|
||||||
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(8 ,buffer->getData().get(), 0, buffer->blockSize());
|
for (size_t i = 0; i < lightList.size(); ++i)
|
||||||
stateset->addUniform(new osg::Uniform("PointLightCount", (int)lights.size()));
|
{
|
||||||
stateset->setAttributeAndModes(ubb.get(), osg::StateAttribute::ON);
|
auto it = mLightData.find(lightList[i]->mLightSource->getId());
|
||||||
|
if (it != mLightData.end())
|
||||||
stateset->setAttribute(new LightStateAttribute(std::move(lights), buffer), osg::StateAttribute::ON);
|
indices->at(validCount++) = it->second;
|
||||||
|
}
|
||||||
|
indicesUni->setArray(indices);
|
||||||
|
stateset->addUniform(indicesUni);
|
||||||
|
stateset->addUniform(new osg::Uniform("PointLightCount", validCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
stateSetCache.emplace(hash, stateset);
|
stateSetCache.emplace(hash, stateset);
|
||||||
|
@ -671,11 +692,6 @@ namespace SceneUtil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<LightManager::LightSourceTransform>& LightManager::getLights() const
|
|
||||||
{
|
|
||||||
return mLights;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum)
|
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum)
|
||||||
{
|
{
|
||||||
osg::observer_ptr<osg::Camera> camPtr (camera);
|
osg::observer_ptr<osg::Camera> camPtr (camera);
|
||||||
|
@ -695,13 +711,47 @@ namespace SceneUtil
|
||||||
l.mLightSource = lightIt->mLightSource;
|
l.mLightSource = lightIt->mLightSource;
|
||||||
l.mViewBound = viewBound;
|
l.mViewBound = viewBound;
|
||||||
it->second.push_back(l);
|
it->second.push_back(l);
|
||||||
|
|
||||||
|
if (usingFFP()) continue;
|
||||||
|
|
||||||
|
auto* light = l.mLightSource->getLight(frameNum);
|
||||||
|
|
||||||
|
auto dataIt = mLightData.find(l.mLightSource->getId());
|
||||||
|
if (dataIt != mLightData.end())
|
||||||
|
{
|
||||||
|
mPointLightProxyData[dataIt->second].mPosition = light->getPosition();
|
||||||
|
mPointLightProxyData[dataIt->second].mBrightness = l.mLightSource->getBrightness(frameNum);
|
||||||
|
mPointBuffer->setValue(dataIt->second, PointLightBuffer::Diffuse, light->getDiffuse());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mLightData.size() >= static_cast<size_t>(getMaxLightsInScene()))
|
||||||
|
{
|
||||||
|
mIndexNeedsRecompiling = true;
|
||||||
|
mLightData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = mLightData.size();
|
||||||
|
updateGPUPointLight(index, l.mLightSource, frameNum);
|
||||||
|
mLightData.emplace(l.mLightSource->getId(), index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LightManager::updateGPUPointLight(int index, LightSource* lightSource, size_t frameNum)
|
||||||
|
{
|
||||||
|
auto* light = lightSource->getLight(frameNum);
|
||||||
|
mPointLightProxyData[index].mPosition = light->getPosition();
|
||||||
|
mPointLightProxyData[index].mBrightness = lightSource->getBrightness(frameNum);
|
||||||
|
mPointBuffer->setValue(index, PointLightBuffer::Diffuse, light->getDiffuse());
|
||||||
|
mPointBuffer->setValue(index, PointLightBuffer::Ambient, light->getAmbient());
|
||||||
|
mPointBuffer->setValue(index, PointLightBuffer::Attenuation, osg::Vec4(light->getConstantAttenuation(), light->getLinearAttenuation(), light->getQuadraticAttenuation(), lightSource->getRadius()));
|
||||||
|
}
|
||||||
|
|
||||||
LightSource::LightSource()
|
LightSource::LightSource()
|
||||||
: mRadius(0.f)
|
: mRadius(0.f)
|
||||||
|
, mBrightness{1.0,1.0}
|
||||||
{
|
{
|
||||||
setUpdateCallback(new CollectLightCallback);
|
setUpdateCallback(new CollectLightCallback);
|
||||||
mId = sLightId++;
|
mId = sLightId++;
|
||||||
|
@ -753,7 +803,7 @@ namespace SceneUtil
|
||||||
// Don't use Camera::getViewMatrix, that one might be relative to another camera!
|
// Don't use Camera::getViewMatrix, that one might be relative to another camera!
|
||||||
const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix();
|
const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix();
|
||||||
const std::vector<LightManager::LightSourceViewBound>& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix, mLastFrameNumber);
|
const std::vector<LightManager::LightSourceViewBound>& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix, mLastFrameNumber);
|
||||||
|
|
||||||
// get the node bounds in view space
|
// get the node bounds in view space
|
||||||
// NB do not node->getBound() * modelView, that would apply the node's transformation twice
|
// NB do not node->getBound() * modelView, that would apply the node's transformation twice
|
||||||
osg::BoundingSphere nodeBound;
|
osg::BoundingSphere nodeBound;
|
||||||
|
@ -818,7 +868,6 @@ namespace SceneUtil
|
||||||
else
|
else
|
||||||
stateset = mLightManager->getLightListStateSet(mLightList, cv->getTraversalNumber());
|
stateset = mLightManager->getLightListStateSet(mLightList, cv->getTraversalNumber());
|
||||||
|
|
||||||
|
|
||||||
cv->pushStateSet(stateset);
|
cv->pushStateSet(stateset);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
|
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <cassert>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <osg/Light>
|
#include <osg/Light>
|
||||||
|
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
#include <osg/NodeVisitor>
|
#include <osg/NodeVisitor>
|
||||||
#include <osg/observer_ptr>
|
#include <osg/observer_ptr>
|
||||||
#include <osg/BufferIndexBinding>
|
|
||||||
|
|
||||||
#include <components/shader/shadermanager.hpp>
|
#include <components/shader/shadermanager.hpp>
|
||||||
|
|
||||||
|
@ -17,9 +19,16 @@ namespace osgUtil
|
||||||
class CullVisitor;
|
class CullVisitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace osg
|
||||||
|
{
|
||||||
|
class UniformBufferBinding;
|
||||||
|
class UniformBufferObject;
|
||||||
|
}
|
||||||
|
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
class SunlightBuffer;
|
class SunlightBuffer;
|
||||||
|
class PointLightBuffer;
|
||||||
|
|
||||||
// Used to override sun. Rarely useful but necassary for local map.
|
// Used to override sun. Rarely useful but necassary for local map.
|
||||||
class SunlightStateAttribute : public osg::StateAttribute
|
class SunlightStateAttribute : public osg::StateAttribute
|
||||||
|
@ -59,6 +68,8 @@ namespace SceneUtil
|
||||||
|
|
||||||
int mId;
|
int mId;
|
||||||
|
|
||||||
|
float mBrightness[2];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
META_Node(SceneUtil, LightSource)
|
META_Node(SceneUtil, LightSource)
|
||||||
|
@ -78,6 +89,16 @@ namespace SceneUtil
|
||||||
mRadius = radius;
|
mRadius = radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float getBrightness(size_t frame)
|
||||||
|
{
|
||||||
|
return mBrightness[frame % 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBrightness(size_t frame, float brightness)
|
||||||
|
{
|
||||||
|
mBrightness[frame % 2] = brightness;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the osg::Light safe for modification in the given frame.
|
/// Get the osg::Light safe for modification in the given frame.
|
||||||
/// @par May be used externally to animate the light's color/attenuation properties,
|
/// @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.
|
/// and is used internally to synchronize the light's position with the position of the LightSource.
|
||||||
|
@ -119,7 +140,7 @@ namespace SceneUtil
|
||||||
osg::BoundingSphere mViewBound;
|
osg::BoundingSphere mViewBound;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<const LightSourceViewBound*> LightList;
|
using LightList = std::vector<const LightSourceViewBound*>;
|
||||||
|
|
||||||
static bool queryNonFFPLightingSupport();
|
static bool queryNonFFPLightingSupport();
|
||||||
|
|
||||||
|
@ -146,8 +167,6 @@ namespace SceneUtil
|
||||||
/// Internal use only, called automatically by the LightSource's UpdateCallback
|
/// Internal use only, called automatically by the LightSource's UpdateCallback
|
||||||
void addLight(LightSource* lightSource, const osg::Matrixf& worldMat, size_t frameNum);
|
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);
|
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);
|
osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList, size_t frameNum);
|
||||||
|
@ -165,6 +184,11 @@ namespace SceneUtil
|
||||||
Shader::ShaderManager::DefineMap getLightDefines() const;
|
Shader::ShaderManager::DefineMap getLightDefines() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
friend class LightManagerStateAttribute;
|
||||||
|
|
||||||
|
void updateGPUPointLight(int index, LightSource* lightSource, size_t frameNum);
|
||||||
|
|
||||||
// Lights collected from the scene graph. Only valid during the cull traversal.
|
// Lights collected from the scene graph. Only valid during the cull traversal.
|
||||||
std::vector<LightSourceTransform> mLights;
|
std::vector<LightSourceTransform> mLights;
|
||||||
|
|
||||||
|
@ -184,6 +208,21 @@ namespace SceneUtil
|
||||||
osg::ref_ptr<osg::Light> mSun;
|
osg::ref_ptr<osg::Light> mSun;
|
||||||
osg::ref_ptr<SunlightBuffer> mSunBuffer;
|
osg::ref_ptr<SunlightBuffer> mSunBuffer;
|
||||||
|
|
||||||
|
struct PointLightProxyData
|
||||||
|
{
|
||||||
|
osg::Vec4 mPosition;
|
||||||
|
float mBrightness;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<PointLightProxyData> mPointLightProxyData;
|
||||||
|
osg::ref_ptr<PointLightBuffer> mPointBuffer;
|
||||||
|
|
||||||
|
// < Light ID , Buffer Index >
|
||||||
|
using LightDataMap = std::unordered_map<int, int>;
|
||||||
|
LightDataMap mLightData;
|
||||||
|
|
||||||
|
bool mIndexNeedsRecompiling;
|
||||||
|
|
||||||
bool mFFP;
|
bool mFFP;
|
||||||
|
|
||||||
static constexpr int mFFPMaxLights = 8;
|
static constexpr int mFFPMaxLights = 8;
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace SceneUtil
|
||||||
light->setQuadraticAttenuation(quadraticAttenuation);
|
light->setQuadraticAttenuation(quadraticAttenuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLight (osg::Group* node, const ESM::Light* esmLight, unsigned int partsysMask, unsigned int lightMask, bool isExterior)
|
void addLight (osg::Group* node, const ESM::Light* esmLight, unsigned int partsysMask, unsigned int lightMask, bool isExterior, bool useFFPLighting)
|
||||||
{
|
{
|
||||||
SceneUtil::FindByNameVisitor visitor("AttachLight");
|
SceneUtil::FindByNameVisitor visitor("AttachLight");
|
||||||
node->accept(visitor);
|
node->accept(visitor);
|
||||||
|
@ -85,17 +85,21 @@ namespace SceneUtil
|
||||||
attachTo = trans;
|
attachTo = trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<LightSource> lightSource = createLightSource(esmLight, lightMask, isExterior);
|
osg::ref_ptr<LightSource> lightSource = createLightSource(esmLight, lightMask, isExterior, osg::Vec4f(0,0,0,1), useFFPLighting);
|
||||||
attachTo->addChild(lightSource);
|
attachTo->addChild(lightSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<LightSource> createLightSource(const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, const osg::Vec4f& ambient)
|
osg::ref_ptr<LightSource> createLightSource(const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, const osg::Vec4f& ambient, bool useFFPLighting)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<SceneUtil::LightSource> lightSource (new SceneUtil::LightSource);
|
osg::ref_ptr<SceneUtil::LightSource> lightSource (new SceneUtil::LightSource);
|
||||||
osg::ref_ptr<osg::Light> light (new osg::Light);
|
osg::ref_ptr<osg::Light> light (new osg::Light);
|
||||||
lightSource->setNodeMask(lightMask);
|
lightSource->setNodeMask(lightMask);
|
||||||
|
|
||||||
float radius = esmLight->mData.mRadius;
|
float radius = esmLight->mData.mRadius;
|
||||||
|
// arbitrary multipler to reduce light popping, this is hard to avoid with per-object lighting
|
||||||
|
// we offset this multipler in shaders
|
||||||
|
if (!useFFPLighting)
|
||||||
|
radius *= 2.0;
|
||||||
lightSource->setRadius(radius);
|
lightSource->setRadius(radius);
|
||||||
|
|
||||||
configureLight(light, radius, isExterior);
|
configureLight(light, radius, isExterior);
|
||||||
|
@ -112,7 +116,7 @@ namespace SceneUtil
|
||||||
|
|
||||||
lightSource->setLight(light);
|
lightSource->setLight(light);
|
||||||
|
|
||||||
osg::ref_ptr<SceneUtil::LightController> ctrl (new SceneUtil::LightController);
|
osg::ref_ptr<SceneUtil::LightController> ctrl (new SceneUtil::LightController(useFFPLighting));
|
||||||
ctrl->setDiffuse(light->getDiffuse());
|
ctrl->setDiffuse(light->getDiffuse());
|
||||||
if (esmLight->mData.mFlags & ESM::Light::Flicker)
|
if (esmLight->mData.mFlags & ESM::Light::Flicker)
|
||||||
ctrl->setType(SceneUtil::LightController::LT_Flicker);
|
ctrl->setType(SceneUtil::LightController::LT_Flicker);
|
||||||
|
|
|
@ -32,14 +32,14 @@ namespace SceneUtil
|
||||||
/// @param partsysMask Node mask to ignore when computing the sub graph's bounding box.
|
/// @param partsysMask Node mask to ignore when computing the sub graph's bounding box.
|
||||||
/// @param lightMask Mask to assign to the newly created LightSource.
|
/// @param lightMask Mask to assign to the newly created LightSource.
|
||||||
/// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use.
|
/// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use.
|
||||||
void addLight (osg::Group* node, const ESM::Light* esmLight, unsigned int partsysMask, unsigned int lightMask, bool isExterior);
|
void addLight (osg::Group* node, const ESM::Light* esmLight, unsigned int partsysMask, unsigned int lightMask, bool isExterior, bool useFFPLighting=true);
|
||||||
|
|
||||||
/// @brief Convert an ESM::Light to a SceneUtil::LightSource, and return it.
|
/// @brief Convert an ESM::Light to a SceneUtil::LightSource, and return it.
|
||||||
/// @param esmLight The light definition coming from the game files containing radius, color, flicker, etc.
|
/// @param esmLight The light definition coming from the game files containing radius, color, flicker, etc.
|
||||||
/// @param lightMask Mask to assign to the newly created LightSource.
|
/// @param lightMask Mask to assign to the newly created LightSource.
|
||||||
/// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use.
|
/// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use.
|
||||||
/// @param ambient Ambient component of the light.
|
/// @param ambient Ambient component of the light.
|
||||||
osg::ref_ptr<LightSource> createLightSource (const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, const osg::Vec4f& ambient=osg::Vec4f(0,0,0,1));
|
osg::ref_ptr<LightSource> createLightSource (const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, const osg::Vec4f& ambient=osg::Vec4f(0,0,0,1), bool useFFPLighting=true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,9 @@
|
||||||
namespace Shader
|
namespace Shader
|
||||||
{
|
{
|
||||||
|
|
||||||
ShaderManager::ShaderManager(Resource::SceneManager* sceneManager)
|
ShaderManager::ShaderManager()
|
||||||
: mSceneManager(sceneManager)
|
: mFFPLighting(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderManager::setShaderPath(const std::string &path)
|
void ShaderManager::setShaderPath(const std::string &path)
|
||||||
|
@ -28,6 +27,11 @@ namespace Shader
|
||||||
mPath = path;
|
mPath = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShaderManager::setFFPLighting(bool useFFP)
|
||||||
|
{
|
||||||
|
mFFPLighting = useFFP;
|
||||||
|
}
|
||||||
|
|
||||||
bool addLineDirectivesAfterConditionalBlocks(std::string& source)
|
bool addLineDirectivesAfterConditionalBlocks(std::string& source)
|
||||||
{
|
{
|
||||||
for (size_t position = 0; position < source.length(); )
|
for (size_t position = 0; position < source.length(); )
|
||||||
|
@ -352,10 +356,10 @@ namespace Shader
|
||||||
program->addShader(fragmentShader);
|
program->addShader(fragmentShader);
|
||||||
program->addBindAttribLocation("aOffset", 6);
|
program->addBindAttribLocation("aOffset", 6);
|
||||||
program->addBindAttribLocation("aRotation", 7);
|
program->addBindAttribLocation("aRotation", 7);
|
||||||
if (!mSceneManager->getFFPLighting())
|
if (!mFFPLighting)
|
||||||
{
|
{
|
||||||
program->addBindUniformBlock("PointLightBuffer", 8);
|
program->addBindUniformBlock("SunlightBuffer", 0);
|
||||||
program->addBindUniformBlock("SunlightBuffer", 9);
|
program->addBindUniformBlock("PointLightBuffer", 1);
|
||||||
}
|
}
|
||||||
found = mPrograms.insert(std::make_pair(std::make_pair(vertexShader, fragmentShader), program)).first;
|
found = mPrograms.insert(std::make_pair(std::make_pair(vertexShader, fragmentShader), program)).first;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,12 @@ namespace Shader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ShaderManager(Resource::SceneManager* sceneManager);
|
ShaderManager();
|
||||||
|
|
||||||
void setShaderPath(const std::string& path);
|
void setShaderPath(const std::string& path);
|
||||||
|
|
||||||
|
void setFFPLighting(bool useFFP);
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> DefineMap;
|
typedef std::map<std::string, std::string> DefineMap;
|
||||||
|
|
||||||
/// Create or retrieve a shader instance.
|
/// Create or retrieve a shader instance.
|
||||||
|
@ -67,7 +69,7 @@ namespace Shader
|
||||||
typedef std::map<std::pair<osg::ref_ptr<osg::Shader>, osg::ref_ptr<osg::Shader> >, osg::ref_ptr<osg::Program> > ProgramMap;
|
typedef std::map<std::pair<osg::ref_ptr<osg::Shader>, osg::ref_ptr<osg::Shader> >, osg::ref_ptr<osg::Program> > ProgramMap;
|
||||||
ProgramMap mPrograms;
|
ProgramMap mPrograms;
|
||||||
|
|
||||||
Resource::SceneManager* mSceneManager;
|
bool mFFPLighting;
|
||||||
|
|
||||||
std::mutex mMutex;
|
std::mutex mMutex;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,19 +6,21 @@
|
||||||
|
|
||||||
struct PointLight
|
struct PointLight
|
||||||
{
|
{
|
||||||
|
vec4 position;
|
||||||
vec4 diffuse;
|
vec4 diffuse;
|
||||||
vec4 ambient;
|
vec4 ambient;
|
||||||
vec4 position;
|
float constantAttenuation;
|
||||||
vec4 attenuation;
|
float linearAttenuation;
|
||||||
|
float quadraticAttenuation;
|
||||||
|
float radius;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform mat4 osg_ViewMatrix;
|
|
||||||
uniform int PointLightCount;
|
uniform int PointLightCount;
|
||||||
uniform int PointLightIndex[@maxLights];
|
uniform int PointLightIndex[@maxLights];
|
||||||
|
|
||||||
layout(std140) uniform PointLightBuffer
|
layout(std140) uniform PointLightBuffer
|
||||||
{
|
{
|
||||||
PointLight PointLights[@maxLights];
|
PointLight PointLights[@maxLightsInScene];
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -47,15 +49,26 @@ void perLightSun(out vec3 ambientOut, out vec3 diffuseOut, vec3 viewPos, vec3 vi
|
||||||
diffuseOut = @sunDiffuse.xyz * lambert;
|
diffuseOut = @sunDiffuse.xyz * lambert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uniform float osg_SimulationTime;
|
||||||
void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal)
|
void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal)
|
||||||
{
|
{
|
||||||
vec3 lightDir = getLight[lightIndex].position.xyz - viewPos;
|
vec4 pos = getLight[lightIndex].position;
|
||||||
//vec3 lightDir = (osg_ViewMatrix * vec4(getLight[lightIndex].position, 1.0)).xyz - viewPos;
|
vec3 lightDir = pos.xyz - viewPos;
|
||||||
|
|
||||||
float lightDistance = length(lightDir);
|
float lightDistance = length(lightDir);
|
||||||
lightDir = normalize(lightDir);
|
lightDir = normalize(lightDir);
|
||||||
|
|
||||||
float illumination = clamp(1.0 / (getLight[lightIndex].attenuation.x + getLight[lightIndex].attenuation.y * lightDistance + getLight[lightIndex].attenuation.z * lightDistance * lightDistance), 0.0, 1.0);
|
float illumination = clamp(1.0 / (getLight[lightIndex].constantAttenuation + getLight[lightIndex].linearAttenuation * lightDistance + getLight[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0);
|
||||||
|
|
||||||
|
// Add an artificial cutoff, otherwise effected objects will be brightly lit and adjacent objects not effected by this light will be dark by contrast
|
||||||
|
// This causes nasty artifacts, especially with active grid so it is necassary for now.
|
||||||
|
#if !@ffpLighting
|
||||||
|
float cutoff = getLight[lightIndex].radius * 0.5;
|
||||||
|
illumination *= 1.0 - smoothstep(0.0, 1.0, ((lightDistance / cutoff) - 1.0) * 0.887);
|
||||||
|
illumination = max(0.0, illumination);
|
||||||
|
#endif
|
||||||
|
|
||||||
ambientOut = getLight[lightIndex].ambient.xyz * illumination;
|
ambientOut = getLight[lightIndex].ambient.xyz * illumination;
|
||||||
|
|
||||||
float lambert = dot(viewNormal.xyz, lightDir) * illumination;
|
float lambert = dot(viewNormal.xyz, lightDir) * illumination;
|
||||||
|
@ -70,7 +83,12 @@ void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec
|
||||||
}
|
}
|
||||||
lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0);
|
lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if @ffpLighting
|
||||||
diffuseOut = getLight[lightIndex].diffuse.xyz * lambert;
|
diffuseOut = getLight[lightIndex].diffuse.xyz * lambert;
|
||||||
|
#else
|
||||||
|
diffuseOut = (getLight[lightIndex].diffuse.xyz * pos.w) * lambert;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PER_PIXEL_LIGHTING
|
#if PER_PIXEL_LIGHTING
|
||||||
|
@ -97,7 +115,7 @@ void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 a
|
||||||
diffuseLight += diffuseOut;
|
diffuseLight += diffuseOut;
|
||||||
for (int i=0; i<PointLightCount; ++i)
|
for (int i=0; i<PointLightCount; ++i)
|
||||||
{
|
{
|
||||||
perLightPoint(ambientOut, diffuseOut, i, viewPos, viewNormal);
|
perLightPoint(ambientOut, diffuseOut, PointLightIndex[i], viewPos, viewNormal);
|
||||||
#else
|
#else
|
||||||
for (int i=0; i<@maxLights; ++i)
|
for (int i=0; i<@maxLights; ++i)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue