Add shared UBO

pull/3065/head
glassmancody.info 4 years ago
parent c5ea966f24
commit 9d9074c244

@ -83,6 +83,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
defines["clamp"] = "1"; // Clamp lighting
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
defines["radialFog"] = "0";
defines["ffpLighting"] = "0";
for (const auto& define : shadowDefines)
defines[define.first] = define.second;
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) );
SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager;
lightMgr->setStartLight(1);
lightMgr->setLightingMask(Mask_Lighting);
mRootNode = lightMgr;

@ -1613,7 +1613,7 @@ namespace MWRender
{
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)

@ -213,9 +213,11 @@ namespace MWRender
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(mResourceSystem->getSceneManager()->getFFPLighting());
bool useFFP = clampLighting || !forceShaders || !SceneUtil::LightManager::queryNonFFPLightingSupport();
resourceSystem->getSceneManager()->setFFPLighting(useFFP);
resourceSystem->getSceneManager()->getShaderManager().setFFPLighting(useFFP);
osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(useFFP);
sceneRoot->setLightingMask(Mask_Lighting);
mSceneRoot = sceneRoot;
sceneRoot->setStartLight(1);

@ -646,7 +646,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R
program->addShader(vertexShader);
program->addShader(fragmentShader);
if (!mResourceSystem->getSceneManager()->getFFPLighting())
program->addBindUniformBlock("SunlightBuffer", 9);
program->addBindUniformBlock("SunlightBuffer", 0);
shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON);
node->setStateSet(shaderStateset);

@ -220,7 +220,7 @@ namespace Resource
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
: ResourceManager(vfs)
, mShaderManager(new Shader::ShaderManager(this))
, mShaderManager(new Shader::ShaderManager)
, mForceShaders(false)
, mClampLighting(true)
, mAutoUseNormalMaps(false)

@ -11,13 +11,14 @@
namespace SceneUtil
{
LightController::LightController()
LightController::LightController(bool useFFPLighting)
: mType(LT_Normal)
, mPhase(0.25f + Misc::Rng::rollClosedProbability() * 0.75f)
, mBrightness(0.675f)
, mStartTime(0.0)
, mLastTime(0.0)
, mTicksToAdvance(0.f)
, mFFPLighting(useFFPLighting)
{
}
@ -62,7 +63,11 @@ namespace SceneUtil
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);
}

@ -20,7 +20,7 @@ namespace SceneUtil
LT_PulseSlow
};
LightController();
LightController(bool useFFPLighting=true);
void setType(LightType type);
@ -36,6 +36,7 @@ namespace SceneUtil
double mStartTime;
double mLastTime;
float mTicksToAdvance;
bool mFFPLighting;
};
}

@ -1,6 +1,7 @@
#include "lightmanager.hpp"
#include <osg/BufferObject>
#include <osg/BufferIndexBinding>
#include <osgUtil/CullVisitor>
@ -12,6 +13,8 @@
#include <components/debug/debuglog.hpp>
#include "apps/openmw/mwrender/vismask.hpp"
namespace
{
/* similar to the boost::hash_combine */
@ -32,6 +35,10 @@ namespace SceneUtil
{
static int sLightId = 0;
////////////////////////////////////////////////////////////////////////////////
// Internal Data Structures
////////////////////////////////////////////////////////////////////////////////
class LightBuffer : public osg::Referenced
{
public:
@ -59,11 +66,6 @@ namespace SceneUtil
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;
@ -114,7 +116,7 @@ namespace SceneUtil
{
public:
enum Type {Diffuse, Ambient, Position, Attenuation};
enum Type {Position, Diffuse, Ambient, Attenuation};
PointLightBuffer(int count)
: LightBuffer(4, count)
@ -124,9 +126,10 @@ namespace SceneUtil
{
if (getValue(index, type) == value)
return;
(*mData)[mNumElements * index + type] = value;
int indexOffset = mNumElements * index + type;
(*mData)[indexOffset] = value;
mDirty = true;
}
@ -155,12 +158,16 @@ namespace SceneUtil
return &cacheVector[contextid];
}
////////////////////////////////////////////////////////////////////////////////
// State Attributes
////////////////////////////////////////////////////////////////////////////////
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());
mUbb = new osg::UniformBufferBinding(0, mBuffer->getData().get(), 0, mBuffer->getData()->getTotalDataSize());
}
SunlightStateAttribute::SunlightStateAttribute(const SunlightStateAttribute &copy, const osg::CopyOp &copyop)
@ -235,56 +242,6 @@ namespace SceneUtil
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
{
public:
@ -368,6 +325,10 @@ namespace SceneUtil
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// Node Callbacks
////////////////////////////////////////////////////////////////////////////////
// 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.
class CollectLightCallback : public osg::NodeCallback
@ -460,6 +421,42 @@ namespace SceneUtil
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)
: mStartLight(0)
, mLightingMask(~0u)
@ -467,28 +464,44 @@ namespace SceneUtil
, mSunBuffer(nullptr)
, mFFP(ffp)
{
setUpdateCallback(new LightManagerUpdateCallback);
if (usingFFP())
{
for (int i=0; i<getMaxLights(); ++i)
mDummies.push_back(new FFPLightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light> >()));
setUpdateCallback(new LightManagerUpdateCallback);
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);
{ // sunlight UBO data
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(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));
setUpdateCallback(new LightManagerUpdateCallback);
addCullCallback(new SunlightCallback(this));
}
////////////////////////////////////////////////////////////////////////////////
LightManager::LightManager(const LightManager &copy, const osg::CopyOp &copyop)
: osg::Group(copy, copyop)
, mStartLight(copy.mStartLight)
@ -507,7 +520,7 @@ namespace SceneUtil
int LightManager::getMaxLights() const
{
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
@ -579,16 +592,18 @@ namespace SceneUtil
}
void LightManager::update()
{
{
mLights.clear();
mLightsInViewSpace.clear();
// do an occasional cleanup for orphaned lights
// Do an occasional cleanup for orphaned lights.
for (int i=0; i<2; ++i)
{
if (mStateSetCache[i].size() > 5000)
if (mStateSetCache[i].size() > 5000 || mIndexNeedsRecompiling)
mStateSetCache[i].clear();
}
mIndexNeedsRecompiling = false;
}
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(),
worldMat.getTrans().y(),
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)
@ -627,20 +643,21 @@ namespace SceneUtil
hash_combine(hash, lightList[i]->mLightSource->getId());
LightStateSetMap& stateSetCache = mStateSetCache[frameNum%2];
LightStateSetMap::iterator found = stateSetCache.find(hash);
if (found != stateSetCache.end())
return found->second;
else
{
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())
{
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
// 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!
@ -656,14 +673,18 @@ namespace SceneUtil
}
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);
osg::ref_ptr<osg::IntArray> indices = new osg::IntArray(getMaxLights());
osg::ref_ptr<osg::Uniform> indicesUni = new osg::Uniform(osg::Uniform::Type::INT, "PointLightIndex", indices->size());
int validCount = 0;
for (size_t i = 0; i < lightList.size(); ++i)
{
auto it = mLightData.find(lightList[i]->mLightSource->getId());
if (it != mLightData.end())
indices->at(validCount++) = it->second;
}
indicesUni->setArray(indices);
stateset->addUniform(indicesUni);
stateset->addUniform(new osg::Uniform("PointLightCount", validCount));
}
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)
{
osg::observer_ptr<osg::Camera> camPtr (camera);
@ -695,13 +711,47 @@ namespace SceneUtil
l.mLightSource = lightIt->mLightSource;
l.mViewBound = viewBound;
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;
}
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()
: mRadius(0.f)
, mBrightness{1.0,1.0}
{
setUpdateCallback(new CollectLightCallback);
mId = sLightId++;
@ -753,7 +803,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, mLastFrameNumber);
// get the node bounds in view space
// NB do not node->getBound() * modelView, that would apply the node's transformation twice
osg::BoundingSphere nodeBound;
@ -818,7 +868,6 @@ namespace SceneUtil
else
stateset = mLightManager->getLightListStateSet(mLightList, cv->getTraversalNumber());
cv->pushStateSet(stateset);
return true;
}

@ -2,13 +2,15 @@
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
#include <set>
#include <cassert>
#include <unordered_map>
#include <unordered_set>
#include <osg/Light>
#include <osg/Group>
#include <osg/NodeVisitor>
#include <osg/observer_ptr>
#include <osg/BufferIndexBinding>
#include <components/shader/shadermanager.hpp>
@ -17,9 +19,16 @@ namespace osgUtil
class CullVisitor;
}
namespace osg
{
class UniformBufferBinding;
class UniformBufferObject;
}
namespace SceneUtil
{
class SunlightBuffer;
class PointLightBuffer;
// Used to override sun. Rarely useful but necassary for local map.
class SunlightStateAttribute : public osg::StateAttribute
@ -59,6 +68,8 @@ namespace SceneUtil
int mId;
float mBrightness[2];
public:
META_Node(SceneUtil, LightSource)
@ -78,6 +89,16 @@ namespace SceneUtil
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.
/// @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.
@ -119,7 +140,7 @@ namespace SceneUtil
osg::BoundingSphere mViewBound;
};
typedef std::vector<const LightSourceViewBound*> LightList;
using LightList = std::vector<const LightSourceViewBound*>;
static bool queryNonFFPLightingSupport();
@ -146,8 +167,6 @@ namespace SceneUtil
/// 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);
@ -165,6 +184,11 @@ namespace SceneUtil
Shader::ShaderManager::DefineMap getLightDefines() const;
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.
std::vector<LightSourceTransform> mLights;
@ -184,6 +208,21 @@ namespace SceneUtil
osg::ref_ptr<osg::Light> mSun;
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;
static constexpr int mFFPMaxLights = 8;

@ -58,7 +58,7 @@ namespace SceneUtil
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");
node->accept(visitor);
@ -85,17 +85,21 @@ namespace SceneUtil
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);
}
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<osg::Light> light (new osg::Light);
lightSource->setNodeMask(lightMask);
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);
configureLight(light, radius, isExterior);
@ -112,7 +116,7 @@ namespace SceneUtil
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());
if (esmLight->mData.mFlags & ESM::Light::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 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.
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.
/// @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 isExterior Is the light outside? May be used for deciding which attenuation settings to use.
/// @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
{
ShaderManager::ShaderManager(Resource::SceneManager* sceneManager)
: mSceneManager(sceneManager)
ShaderManager::ShaderManager()
: mFFPLighting(false)
{
}
void ShaderManager::setShaderPath(const std::string &path)
@ -28,6 +27,11 @@ namespace Shader
mPath = path;
}
void ShaderManager::setFFPLighting(bool useFFP)
{
mFFPLighting = useFFP;
}
bool addLineDirectivesAfterConditionalBlocks(std::string& source)
{
for (size_t position = 0; position < source.length(); )
@ -352,10 +356,10 @@ namespace Shader
program->addShader(fragmentShader);
program->addBindAttribLocation("aOffset", 6);
program->addBindAttribLocation("aRotation", 7);
if (!mSceneManager->getFFPLighting())
if (!mFFPLighting)
{
program->addBindUniformBlock("PointLightBuffer", 8);
program->addBindUniformBlock("SunlightBuffer", 9);
program->addBindUniformBlock("SunlightBuffer", 0);
program->addBindUniformBlock("PointLightBuffer", 1);
}
found = mPrograms.insert(std::make_pair(std::make_pair(vertexShader, fragmentShader), program)).first;
}

@ -25,10 +25,12 @@ namespace Shader
{
public:
ShaderManager(Resource::SceneManager* sceneManager);
ShaderManager();
void setShaderPath(const std::string& path);
void setFFPLighting(bool useFFP);
typedef std::map<std::string, std::string> DefineMap;
/// 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;
ProgramMap mPrograms;
Resource::SceneManager* mSceneManager;
bool mFFPLighting;
std::mutex mMutex;
};

@ -6,19 +6,21 @@
struct PointLight
{
vec4 position;
vec4 diffuse;
vec4 ambient;
vec4 position;
vec4 attenuation;
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
float radius;
};
uniform mat4 osg_ViewMatrix;
uniform int PointLightCount;
uniform int PointLightIndex[@maxLights];
layout(std140) uniform PointLightBuffer
{
PointLight PointLights[@maxLights];
PointLight PointLights[@maxLightsInScene];
};
#else
@ -47,15 +49,26 @@ void perLightSun(out vec3 ambientOut, out vec3 diffuseOut, vec3 viewPos, vec3 vi
diffuseOut = @sunDiffuse.xyz * lambert;
}
uniform float osg_SimulationTime;
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;
vec4 pos = getLight[lightIndex].position;
vec3 lightDir = pos.xyz - viewPos;
float lightDistance = length(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;
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);
#endif
#if @ffpLighting
diffuseOut = getLight[lightIndex].diffuse.xyz * lambert;
#else
diffuseOut = (getLight[lightIndex].diffuse.xyz * pos.w) * lambert;
#endif
}
#if PER_PIXEL_LIGHTING
@ -97,7 +115,7 @@ void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 a
diffuseLight += diffuseOut;
for (int i=0; i<PointLightCount; ++i)
{
perLightPoint(ambientOut, diffuseOut, i, viewPos, viewNormal);
perLightPoint(ambientOut, diffuseOut, PointLightIndex[i], viewPos, viewNormal);
#else
for (int i=0; i<@maxLights; ++i)
{

Loading…
Cancel
Save