1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-30 18:45:38 +00:00

experimental point light bindings

This commit is contained in:
cody glassman 2022-05-14 22:53:53 -07:00
parent fee639a74f
commit 0cb63ca4e6
13 changed files with 168 additions and 12 deletions

View file

@ -94,6 +94,8 @@ namespace MWRender
, mNormals(false)
, mPrevNormals(false)
, mNormalsSupported(false)
, mPassLights(false)
, mPrevPassLights(false)
, mMainTemplate(new osg::Texture2D)
{
mSoftParticles = Settings::Manager::getBool("soft particles", "Shaders") && !Stereo::getStereo() && !Stereo::getMultiview();
@ -393,9 +395,10 @@ namespace MWRender
mDirty = false;
}
if (mNormalsSupported && mNormals != mPrevNormals)
if ((mNormalsSupported && mNormals != mPrevNormals) || (mPassLights != mPrevPassLights))
{
mPrevNormals = mNormals;
mPrevPassLights = mPassLights;
mViewer->stopThreading();
@ -404,10 +407,15 @@ namespace MWRender
defines["disableNormals"] = mNormals ? "0" : "1";
shaderManager.setGlobalDefines(defines);
mRendering.getLightRoot()->setCollectPPLights(mPassLights);
mStateUpdater->bindPointLights(mPassLights ? mRendering.getLightRoot()->getPPLightsBuffer() : nullptr);
mStateUpdater->reset();
mViewer->startThreading();
createTexturesAndCamera(frameId);
createObjectsForFrame(frameId);
mDirty = true;
mDirtyFrameId = !frameId;
}
@ -491,6 +499,7 @@ namespace MWRender
bool sunglare = true;
mHDR = false;
mNormals = false;
mPassLights = false;
for (const auto& technique : mTechniques)
{
@ -513,6 +522,9 @@ namespace MWRender
if (technique->getNormals())
mNormals = true;
if (technique->getLights())
mPassLights = true;
if (node.mFlags & fx::Technique::Flag_Disable_SunGlare)
sunglare = false;

View file

@ -212,6 +212,8 @@ namespace MWRender
bool mNormals;
bool mPrevNormals;
bool mNormalsSupported;
bool mPassLights;
bool mPrevPassLights;
bool mUBO;
int mGLSLVersion;

View file

@ -42,6 +42,8 @@
#include <components/sceneutil/writescene.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/misc/constants.hpp>
#include <components/terrain/terraingrid.hpp>
#include <components/terrain/quadtreeworld.hpp>
@ -558,10 +560,9 @@ namespace MWRender
cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING;
}
mViewer->getCamera()->setCullingMode( cullingMode );
mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
mViewer->getCamera()->setCullingMode(cullingMode);
mViewer->getCamera()->setName(Constants::SceneCamera);
auto mask = ~(Mask_UpdateVisitor | Mask_SimpleWater);
MWBase::Environment::get().getWindowManager()->setCullMask(mask);
@ -650,7 +651,7 @@ namespace MWRender
return mViewer->getFrameStamp()->getReferenceTime();
}
osg::Group* RenderingManager::getLightRoot()
SceneUtil::LightManager* RenderingManager::getLightRoot()
{
return mSceneRoot.get();
}
@ -1360,7 +1361,7 @@ namespace MWRender
it->second == "light fade start" ||
it->second == "max lights"))
{
auto* lightManager = static_cast<SceneUtil::LightManager*>(getLightRoot());
auto* lightManager = getLightRoot();
lightManager->processChangedSettings(changed);
if (it->second == "max lights" && !lightManager->usingFFP())

View file

@ -59,6 +59,7 @@ namespace SceneUtil
{
class ShadowManager;
class WorkQueue;
class LightManager;
}
namespace DetourNavigator
@ -116,7 +117,7 @@ namespace MWRender
double getReferenceTime() const;
osg::Group* getLightRoot();
SceneUtil::LightManager* getLightRoot();
void setNightEyeFactor(float factor);
@ -271,7 +272,7 @@ namespace MWRender
osg::ref_ptr<osgViewer::Viewer> mViewer;
osg::ref_ptr<osg::Group> mRootNode;
osg::ref_ptr<osg::Group> mSceneRoot;
osg::ref_ptr<SceneUtil::LightManager> mSceneRoot;
Resource::ResourceSystem* mResourceSystem;
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;

View file

@ -28,6 +28,7 @@
#include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/detournavigator/navigator.hpp>
#include <components/detournavigator/settings.hpp>
@ -197,7 +198,7 @@ namespace MWWorld
}
mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, resourcePath, *mNavigator, mGroundcoverStore));
mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering.get(), mPhysics.get()));
mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot()->asGroup(), resourceSystem, mRendering.get(), mPhysics.get()));
mRendering->preloadCommonAssets();
mWeatherManager.reset(new MWWorld::WeatherManager(*mRendering, mStore));

View file

@ -13,6 +13,7 @@
#include <components/misc/stringops.hpp>
#include <components/sceneutil/util.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/clearcolor.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/stereo/multiview.hpp>
@ -77,6 +78,34 @@ uniform @builtinSampler omw_SamplerLastPass;
uniform @builtinSampler omw_SamplerDepth;
uniform @builtinSampler omw_SamplerNormals;
uniform vec4 omw_PointLights[@pointLightCount];
uniform int omw_PointLightsCount;
int omw_GetPointLightCount()
{
return omw_PointLightsCount;
}
vec3 omw_GetPointLightViewPos(int index)
{
return omw_PointLights[(index * 3)].xyz;
}
vec3 omw_GetPointLightDiffuse(int index)
{
return omw_PointLights[(index * 3) + 1].xyz;
}
vec3 omw_GetPointLightAttenuation(int index)
{
return omw_PointLights[(index * 3) + 2].xyz;
}
float omw_GetPointLightRadius(int index)
{
return omw_PointLights[(index * 3) + 2].w;
}
#if @ubo
layout(std140) uniform _data { _omw_data omw; };
#else
@ -143,6 +172,7 @@ uniform @builtinSampler omw_SamplerNormals;
extBlock << "#ifdef " << extension << '\n' << "\t#extension " << extension << ": enable" << '\n' << "#endif" << '\n';
const std::vector<std::pair<std::string,std::string>> defines = {
{"@pointLightCount", std::to_string(SceneUtil::PPLightBuffer::sMaxPPLightsArraySize)},
{"@version", std::to_string(technique.getGLSLVersion())},
{"@multiview", Stereo::getMultiview() ? "1" : "0"},
{"@builtinSampler", Stereo::getMultiview() ? "sampler2DArray" : "sampler2D"},

View file

@ -56,5 +56,8 @@ namespace fx
std::apply([&] (const auto& ... v) { (setUniform(v) , ...); }, mData.getData());
}
if (mPointLightBuffer)
mPointLightBuffer->applyUniforms(nv->getTraversalNumber(), stateset);
}
}

View file

@ -3,6 +3,7 @@
#include <osg/BufferTemplate>
#include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/statesetupdater.hpp>
#include <components/std140/ubo.hpp>
@ -86,12 +87,21 @@ namespace fx
void setWeatherTransition(float transition) { mData.get<WeatherTransition>() = transition; }
void bindPointLights(std::shared_ptr<SceneUtil::PPLightBuffer> buffer)
{
mPointLightBuffer = buffer;
}
static std::string getStructDefinition()
{
static std::string definition = UniformData::getDefinition("_omw_data");
return definition;
}
void setDefaults(osg::StateSet* stateset) override;
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override;
private:
struct ProjectionMatrix : std140::Mat4 { static constexpr std::string_view sName = "projectionMatrix"; };
@ -180,12 +190,10 @@ namespace fx
IsInterior
>;
private:
void setDefaults(osg::StateSet* stateset) override;
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override;
UniformData mData;
bool mUseUBO;
std::shared_ptr<SceneUtil::PPLightBuffer> mPointLightBuffer;
};
}

View file

@ -59,6 +59,7 @@ namespace fx
mValid = false;
mHDR = false;
mNormals = false;
mLights = false;
mEnabled = true;
mPassMap.clear();
mPasses.clear();
@ -238,6 +239,8 @@ namespace fx
mHDR = parseBool();
else if (key == "pass_normals")
mNormals = parseBool() && mSupportsNormals;
else if (key == "pass_lights")
mLights = parseBool();
else if (key == "glsl_profile")
{
expect<Lexer::String>();

View file

@ -129,6 +129,8 @@ namespace fx
bool getNormals() const { return mNormals && mSupportsNormals; }
bool getLights() const { return mLights; }
const PassList& getPasses() { return mPasses; }
const TexList& getTextures() const { return mTextures; }
@ -253,6 +255,7 @@ namespace fx
bool mValid;
bool mHDR;
bool mNormals;
bool mLights;
int mWidth;
int mHeight;

View file

@ -39,6 +39,9 @@ const float TorsoHeight = 0.75f;
static constexpr float sStepSizeUp = 34.0f;
static constexpr float sMaxSlope = 46.0f;
// Identifier for main scene camera
const std::string SceneCamera = "SceneCam";
}
#endif

View file

@ -18,6 +18,7 @@
#include <components/misc/hash.hpp>
#include <components/misc/stringops.hpp>
#include <components/misc/constants.hpp>
#include <components/debug/debuglog.hpp>
@ -839,6 +840,7 @@ namespace SceneUtil
, mPointLightFadeEnd(copy.mPointLightFadeEnd)
, mPointLightFadeStart(copy.mPointLightFadeStart)
, mMaxLights(copy.mMaxLights)
, mPPLightBuffer(copy.mPPLightBuffer)
{
}
@ -1001,6 +1003,9 @@ namespace SceneUtil
void LightManager::update(size_t frameNum)
{
if (mPPLightBuffer)
mPPLightBuffer->clear(frameNum);
getLightIndexMap(frameNum).clear();
mLights.clear();
mLightsInViewSpace.clear();
@ -1132,6 +1137,17 @@ namespace SceneUtil
l.mLightSource = transform.mLightSource;
l.mViewBound = viewBound;
it->second.push_back(l);
if (mPPLightBuffer && it->first->getName() == Constants::SceneCamera)
{
const auto* light = l.mLightSource->getLight(frameNum);
mPPLightBuffer->setLight(frameNum, light->getPosition() * (*viewMatrix),
light->getDiffuse(),
light->getConstantAttenuation(),
light->getLinearAttenuation(),
light->getQuadraticAttenuation(),
l.mLightSource->getRadius());
}
}
}
@ -1168,6 +1184,14 @@ namespace SceneUtil
return uniform;
}
void LightManager::setCollectPPLights(bool enabled)
{
if (enabled)
mPPLightBuffer = std::make_shared<PPLightBuffer>();
else
mPPLightBuffer = nullptr;
}
LightSource::LightSource()
: mRadius(0.f)
, mActorFade(1.f)

View file

@ -26,6 +26,64 @@ namespace SceneUtil
class LightBuffer;
struct StateSetGenerator;
class PPLightBuffer
{
public:
inline static constexpr auto sMaxPPLights = 30;
inline static constexpr auto sMaxPPLightsArraySize = sMaxPPLights * 3;
PPLightBuffer()
{
for (size_t i = 0; i < 2; ++i)
{
mIndex[i] = 0;
mUniformBuffers[i] = new osg::Uniform(osg::Uniform::FLOAT_VEC4, "omw_PointLights", sMaxPPLightsArraySize);
mUniformCount[i] = new osg::Uniform("omw_PointLightsCount", static_cast<int>(0));
}
}
void applyUniforms(size_t frame, osg::StateSet* stateset)
{
size_t frameId = frame % 2;
if (!stateset->getUniform("omw_PointLights"))
stateset->addUniform(mUniformBuffers[frameId]);
if (!stateset->getUniform("omw_PointLightsCount"))
stateset->addUniform(mUniformCount[frameId]);
mUniformBuffers[frameId]->dirty();
mUniformCount[frameId]->dirty();
}
void clear(size_t frame)
{
mIndex[frame % 2] = 0;
}
void setLight(size_t frame, const osg::Vec4f& position, osg::Vec4f diffuse, float ac, float al, float aq, float radius)
{
size_t frameId = frame % 2;
size_t i = mIndex[frameId];
if (i >= (sMaxPPLights - 1))
return;
i *= 3;
mUniformBuffers[frameId]->setElement(i + 0, position);
mUniformBuffers[frameId]->setElement(i + 1, diffuse);
mUniformBuffers[frameId]->setElement(i + 2, osg::Vec4f(ac, al, aq, radius));
mIndex[frameId]++;
mUniformCount[frameId]->set(static_cast<int>(mIndex[frameId]));
}
private:
std::array<size_t, 2> mIndex;
std::array<osg::ref_ptr<osg::Uniform>, 2> mUniformBuffers;
std::array<osg::ref_ptr<osg::Uniform>, 2> mUniformCount;
};
enum class LightingMethod
{
FFP,
@ -227,6 +285,11 @@ namespace SceneUtil
osg::ref_ptr<osg::Uniform> generateLightBufferUniform(const osg::Matrixf& sun);
// Whether to collect main scene camera points lights into a buffer to be later sent to postprocessing shaders
void setCollectPPLights(bool enabled);
std::shared_ptr<PPLightBuffer> getPPLightsBuffer() { return mPPLightBuffer; }
private:
void initFFP(int targetLights);
void initPerObjectUniform(int targetLights);
@ -285,6 +348,8 @@ namespace SceneUtil
static constexpr auto mFFPMaxLights = 8;
static const std::unordered_map<std::string, LightingMethod> mLightingMethodSettingMap;
std::shared_ptr<PPLightBuffer> mPPLightBuffer;
};
/// To receive lighting, objects must be decorated by a LightListCallback. Light list callbacks must be added via