mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-06 21:45:35 +00:00
discard off-screen lights (#3120)
Currently, we run culling tests against all lights in the scene during LightListCallback::pushLightState. We can avoid most of these tests by removing off-screen lights at an earlier stage. We should benchmark the cumulative time spent within LightListCallback::pushLightState before and after this PR.
This commit is contained in:
parent
787f91211d
commit
cd4d76f8c5
2 changed files with 57 additions and 57 deletions
|
@ -1192,8 +1192,10 @@ namespace SceneUtil
|
||||||
return stateset;
|
return stateset;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum)
|
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osgUtil::CullVisitor *cv, const osg::RefMatrix* viewMatrix, size_t frameNum)
|
||||||
{
|
{
|
||||||
|
osg::Camera* camera = cv->getCurrentCamera();
|
||||||
|
|
||||||
osg::observer_ptr<osg::Camera> camPtr (camera);
|
osg::observer_ptr<osg::Camera> camPtr (camera);
|
||||||
auto it = mLightsInViewSpace.find(camPtr);
|
auto it = mLightsInViewSpace.find(camPtr);
|
||||||
|
|
||||||
|
@ -1209,7 +1211,7 @@ namespace SceneUtil
|
||||||
|
|
||||||
float radius = transform.mLightSource->getRadius();
|
float radius = transform.mLightSource->getRadius();
|
||||||
|
|
||||||
osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), radius * mPointLightRadiusMultiplier);
|
osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), radius);
|
||||||
transformBoundingSphere(worldViewMat, viewBound);
|
transformBoundingSphere(worldViewMat, viewBound);
|
||||||
|
|
||||||
if (!isReflection && mPointLightFadeEnd != 0.f)
|
if (!isReflection && mPointLightFadeEnd != 0.f)
|
||||||
|
@ -1223,6 +1225,15 @@ namespace SceneUtil
|
||||||
light->setDiffuse(light->getDiffuse() * fade);
|
light->setDiffuse(light->getDiffuse() * fade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove lights culled by this camera
|
||||||
|
if (!usingFFP())
|
||||||
|
{
|
||||||
|
viewBound._radius *= 2.f;
|
||||||
|
if (cv->getModelViewCullingStack().front().isCulled(viewBound))
|
||||||
|
continue;
|
||||||
|
viewBound._radius /= 2.f;
|
||||||
|
}
|
||||||
|
viewBound._radius *= mPointLightRadiusMultiplier;
|
||||||
LightSourceViewBound l;
|
LightSourceViewBound l;
|
||||||
l.mLightSource = transform.mLightSource;
|
l.mLightSource = transform.mLightSource;
|
||||||
l.mViewBound = viewBound;
|
l.mViewBound = viewBound;
|
||||||
|
@ -1295,46 +1306,41 @@ namespace SceneUtil
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Possible optimizations:
|
// Possible optimizations:
|
||||||
// - cull list of lights by the camera frustum
|
|
||||||
// - organize lights in a quad tree
|
// - organize lights in a quad tree
|
||||||
|
|
||||||
|
|
||||||
// update light list if necessary
|
mLastFrameNumber = cv->getTraversalNumber();
|
||||||
// makes sure we don't update it more than once per frame when rendering with multiple cameras
|
|
||||||
if (mLastFrameNumber != cv->getTraversalNumber())
|
// 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, 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;
|
||||||
|
osg::Transform* transform = node->asTransform();
|
||||||
|
if (transform)
|
||||||
{
|
{
|
||||||
mLastFrameNumber = cv->getTraversalNumber();
|
for (size_t i = 0; i < transform->getNumChildren(); ++i)
|
||||||
|
nodeBound.expandBy(transform->getChild(i)->getBound());
|
||||||
// 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;
|
|
||||||
osg::Transform* transform = node->asTransform();
|
|
||||||
if (transform)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < transform->getNumChildren(); ++i)
|
|
||||||
nodeBound.expandBy(transform->getChild(i)->getBound());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
nodeBound = node->getBound();
|
|
||||||
osg::Matrixf mat = *cv->getModelViewMatrix();
|
|
||||||
transformBoundingSphere(mat, nodeBound);
|
|
||||||
|
|
||||||
mLightList.clear();
|
|
||||||
for (size_t i = 0; i < lights.size(); ++i)
|
|
||||||
{
|
|
||||||
const LightManager::LightSourceViewBound& l = lights[i];
|
|
||||||
|
|
||||||
if (mIgnoredLightSources.count(l.mLightSource))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (l.mViewBound.intersects(nodeBound))
|
|
||||||
mLightList.push_back(&l);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
nodeBound = node->getBound();
|
||||||
|
osg::Matrixf mat = *cv->getModelViewMatrix();
|
||||||
|
transformBoundingSphere(mat, nodeBound);
|
||||||
|
|
||||||
|
mLightList.clear();
|
||||||
|
for (size_t i = 0; i < lights.size(); ++i)
|
||||||
|
{
|
||||||
|
const LightManager::LightSourceViewBound& l = lights[i];
|
||||||
|
|
||||||
|
if (mIgnoredLightSources.count(l.mLightSource))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (l.mViewBound.intersects(nodeBound))
|
||||||
|
mLightList.push_back(&l);
|
||||||
|
}
|
||||||
|
|
||||||
if (!mLightList.empty())
|
if (!mLightList.empty())
|
||||||
{
|
{
|
||||||
size_t maxLights = mLightManager->getMaxLights() - mLightManager->getStartLight();
|
size_t maxLights = mLightManager->getMaxLights() - mLightManager->getStartLight();
|
||||||
|
@ -1343,31 +1349,25 @@ namespace SceneUtil
|
||||||
|
|
||||||
if (mLightList.size() > maxLights)
|
if (mLightList.size() > maxLights)
|
||||||
{
|
{
|
||||||
// remove lights culled by this camera
|
|
||||||
LightManager::LightList lightList = mLightList;
|
LightManager::LightList lightList = mLightList;
|
||||||
for (auto it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights;)
|
|
||||||
{
|
|
||||||
osg::CullStack::CullingStack& stack = cv->getModelViewCullingStack();
|
|
||||||
|
|
||||||
osg::BoundingSphere bs = (*it)->mViewBound;
|
if (mLightManager->usingFFP())
|
||||||
bs._radius = bs._radius * 2.0;
|
{
|
||||||
osg::CullingSet& cullingSet = stack.front();
|
for (auto it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights;)
|
||||||
if (cullingSet.isCulled(bs))
|
|
||||||
{
|
{
|
||||||
it = lightList.erase(it);
|
osg::BoundingSphere bs = (*it)->mViewBound;
|
||||||
continue;
|
bs._radius = bs._radius * 2.0;
|
||||||
|
if (cv->getModelViewCullingStack().front().isCulled(bs))
|
||||||
|
it = lightList.erase(it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lightList.size() > maxLights)
|
// sort by proximity to camera, then get rid of furthest away lights
|
||||||
{
|
std::sort(lightList.begin(), lightList.end(), sortLights);
|
||||||
// sort by proximity to camera, then get rid of furthest away lights
|
while (lightList.size() > maxLights)
|
||||||
std::sort(lightList.begin(), lightList.end(), sortLights);
|
lightList.pop_back();
|
||||||
while (lightList.size() > maxLights)
|
|
||||||
lightList.pop_back();
|
|
||||||
}
|
|
||||||
stateset = mLightManager->getLightListStateSet(lightList, cv->getTraversalNumber(), cv->getCurrentRenderStage()->getInitialViewMatrix());
|
stateset = mLightManager->getLightListStateSet(lightList, cv->getTraversalNumber(), cv->getCurrentRenderStage()->getInitialViewMatrix());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -157,7 +157,7 @@ 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<LightSourceViewBound>& getLightsInViewSpace(osg::Camera* camera, const osg::RefMatrix* viewMatrix, size_t frameNum);
|
const std::vector<LightSourceViewBound>& getLightsInViewSpace(osgUtil::CullVisitor* cv, const osg::RefMatrix* viewMatrix, size_t frameNum);
|
||||||
|
|
||||||
osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList, size_t frameNum, const osg::RefMatrix* viewMatrix);
|
osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList, size_t frameNum, const osg::RefMatrix* viewMatrix);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue