mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 16:15:31 +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["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());
|
||||
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(mResourceSystem->getSceneManager()->getFFPLighting());
|
||||
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)
|
||||
|
@ -125,7 +127,8 @@ 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 ©, const osg::CopyOp ©op)
|
||||
|
@ -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();
|
||||
|
||||
{ // 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(9 , mSunBuffer->getData().get(), 0, mSunBuffer->blockSize());
|
||||
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 ©, const osg::CopyOp ©op)
|
||||
: 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
|
||||
|
@ -583,12 +596,14 @@ namespace SceneUtil
|
|||
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)
|
||||
|
@ -634,13 +650,14 @@ namespace SceneUtil
|
|||
else
|
||||
{
|
||||
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
|
||||
|
||||
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));
|
||||
|
||||
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!
|
||||
|
@ -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++;
|
||||
|
@ -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…
Reference in a new issue