1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-03 13:09:40 +00:00

waterculling for both terrain

This commit is contained in:
bzzt 2019-06-13 13:37:00 +00:00 committed by Bret Curtis
parent e791e65684
commit ed20d869b4
8 changed files with 129 additions and 3 deletions

View file

@ -282,8 +282,6 @@ namespace MWRender
mEffectManager.reset(new EffectManager(sceneRoot, mResourceSystem)); mEffectManager.reset(new EffectManager(sceneRoot, mResourceSystem));
mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath));
DLLandFogStart = Settings::Manager::getFloat("distant land fog start", "Fog"); DLLandFogStart = Settings::Manager::getFloat("distant land fog start", "Fog");
DLLandFogEnd = Settings::Manager::getFloat("distant land fog end", "Fog"); DLLandFogEnd = Settings::Manager::getFloat("distant land fog end", "Fog");
DLUnderwaterFogStart = Settings::Manager::getFloat("distant underwater fog start", "Fog"); DLUnderwaterFogStart = Settings::Manager::getFloat("distant underwater fog start", "Fog");
@ -322,6 +320,9 @@ namespace MWRender
mTerrain->setTargetFrameRate(Settings::Manager::getFloat("target framerate", "Cells")); mTerrain->setTargetFrameRate(Settings::Manager::getFloat("target framerate", "Cells"));
mTerrain->setWorkQueue(mWorkQueue.get()); mTerrain->setWorkQueue(mWorkQueue.get());
// water goes after terrain for correct waterculling order
mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath));
mCamera.reset(new Camera(mViewer->getCamera())); mCamera.reset(new Camera(mViewer->getCamera()));
mViewer->setLightingMode(osgViewer::View::NO_LIGHT); mViewer->setLightingMode(osgViewer::View::NO_LIGHT);
@ -541,6 +542,8 @@ namespace MWRender
void RenderingManager::enableTerrain(bool enable) void RenderingManager::enableTerrain(bool enable)
{ {
if (!enable)
mWater->setCullCallback(nullptr);
mTerrain->enable(enable); mTerrain->enable(enable);
} }
@ -740,6 +743,7 @@ namespace MWRender
void RenderingManager::setWaterHeight(float height) void RenderingManager::setWaterHeight(float height)
{ {
mWater->setCullCallback(mTerrain->getHeightCullCallback(height, Mask_Water));
mWater->setHeight(height); mWater->setHeight(height);
mSky->setWaterHeight(height); mSky->setWaterHeight(height);
} }

View file

@ -436,6 +436,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem
, mToggled(true) , mToggled(true)
, mTop(0) , mTop(0)
, mInterior(false) , mInterior(false)
, mCullCallback(nullptr)
{ {
mSimulation.reset(new RippleSimulation(mSceneRoot, resourceSystem)); mSimulation.reset(new RippleSimulation(mSceneRoot, resourceSystem));
@ -466,6 +467,29 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem
ico->add(mWaterNode); ico->add(mWaterNode);
} }
void Water::setCullCallback(osg::Callback* callback)
{
if (mCullCallback)
{
mWaterNode->removeCullCallback(mCullCallback);
if (mReflection)
mReflection->removeCullCallback(mCullCallback);
if (mRefraction)
mRefraction->removeCullCallback(mCullCallback);
}
mCullCallback = callback;
if (callback)
{
mWaterNode->addCullCallback(callback);
if (mReflection)
mReflection->addCullCallback(callback);
if (mRefraction)
mRefraction->addCullCallback(callback);
}
}
osg::Uniform *Water::getRainIntensityUniform() osg::Uniform *Water::getRainIntensityUniform()
{ {
return mRainIntensityUniform.get(); return mRainIntensityUniform.get();
@ -491,6 +515,8 @@ void Water::updateWaterMaterial()
mReflection = new Reflection(mInterior); mReflection = new Reflection(mInterior);
mReflection->setWaterLevel(mTop); mReflection->setWaterLevel(mTop);
mReflection->setScene(mSceneRoot); mReflection->setScene(mSceneRoot);
if (mCullCallback)
mReflection->addCullCallback(mCullCallback);
mParent->addChild(mReflection); mParent->addChild(mReflection);
if (Settings::Manager::getBool("refraction", "Water")) if (Settings::Manager::getBool("refraction", "Water"))
@ -498,6 +524,8 @@ void Water::updateWaterMaterial()
mRefraction = new Refraction; mRefraction = new Refraction;
mRefraction->setWaterLevel(mTop); mRefraction->setWaterLevel(mTop);
mRefraction->setScene(mSceneRoot); mRefraction->setScene(mSceneRoot);
if (mCullCallback)
mRefraction->addCullCallback(mCullCallback);
mParent->addChild(mRefraction); mParent->addChild(mRefraction);
} }

View file

@ -71,6 +71,8 @@ namespace MWRender
float mTop; float mTop;
bool mInterior; bool mInterior;
osg::Callback* mCullCallback;
osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY);
void updateVisible(); void updateVisible();
@ -88,6 +90,8 @@ namespace MWRender
const std::string& resourcePath); const std::string& resourcePath);
~Water(); ~Water();
void setCullCallback(osg::Callback* callback);
void listAssetsToPreload(std::vector<std::string>& textures); void listAssetsToPreload(std::vector<std::string>& textures);
void setEnabled(bool enabled); void setEnabled(bool enabled);

View file

@ -307,6 +307,38 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, C
entry.mRenderingNode = chunkManager->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags); entry.mRenderingNode = chunkManager->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags);
} }
void updateWaterCullingView(HeightCullCallback* callback, ViewData* vd, osgUtil::CullVisitor* cv, float cellworldsize, bool outofworld)
{
if (!(cv->getTraversalMask() & callback->getCullMask()))
return;
float lowZ = FLT_MAX;
float highZ = callback->getHighZ();
if (cv->getEyePoint().z() <= highZ || outofworld)
{
callback->setLowZ(-FLT_MAX);
return;
}
cv->pushCurrentMask();
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
{
ViewData::Entry& entry = vd->getEntry(i);
osg::BoundingBox bb = static_cast<osg::Drawable*>(entry.mRenderingNode->asGroup()->getChild(0))->getBoundingBox();
float minZ = bb._min.z();
if (minZ > highZ)
continue;
osg::Vec3f ofs (entry.mNode->getCenter().x()*cellworldsize, entry.mNode->getCenter().y()*cellworldsize, 0.f);
bb._min += ofs; bb._max += ofs;
bb._min.z() = highZ;
bb._max.z() = highZ;
if (cv->isCulled(bb))
continue;
lowZ = minZ;
break;
}
callback->setLowZ(lowZ);
cv->popCurrentMask();
}
void QuadTreeWorld::accept(osg::NodeVisitor &nv) void QuadTreeWorld::accept(osg::NodeVisitor &nv)
{ {
bool isCullVisitor = nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR; bool isCullVisitor = nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR;
@ -384,6 +416,9 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
entry.mRenderingNode->accept(nv); entry.mRenderingNode->accept(nv);
} }
if (isCullVisitor)
updateWaterCullingView(mHeightCullCallback, vd, static_cast<osgUtil::CullVisitor*>(&nv), mStorage->getCellWorldSize(), !mGrid.empty());
if (!isCullVisitor) if (!isCullVisitor)
vd->clear(); // we can't reuse intersection views in the next frame because they only contain what is touched by the intersection ray. vd->clear(); // we can't reuse intersection views in the next frame because they only contain what is touched by the intersection ray.

View file

@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include <osg/Group> #include <osg/Group>
#include <osg/ComputeBoundsVisitor>
#include "chunkmanager.hpp" #include "chunkmanager.hpp"
#include "compositemaprenderer.hpp" #include "compositemaprenderer.hpp"
@ -80,6 +81,7 @@ void TerrainGrid::loadCell(int x, int y)
mTerrainRoot->addChild(terrainNode); mTerrainRoot->addChild(terrainNode);
mGrid[std::make_pair(x,y)] = terrainNode; mGrid[std::make_pair(x,y)] = terrainNode;
updateWaterCulling();
} }
void TerrainGrid::unloadCell(int x, int y) void TerrainGrid::unloadCell(int x, int y)
@ -94,6 +96,15 @@ void TerrainGrid::unloadCell(int x, int y)
mTerrainRoot->removeChild(terrainNode); mTerrainRoot->removeChild(terrainNode);
mGrid.erase(it); mGrid.erase(it);
updateWaterCulling();
}
void TerrainGrid::updateWaterCulling()
{
osg::ComputeBoundsVisitor computeBoundsVisitor;
mTerrainRoot->accept(computeBoundsVisitor);
float lowZ = computeBoundsVisitor.getBoundingBox()._min.z();
mHeightCullCallback->setLowZ(lowZ);
} }
View *TerrainGrid::createView() View *TerrainGrid::createView()

View file

@ -27,8 +27,9 @@ namespace Terrain
View* createView(); View* createView();
private: protected:
osg::ref_ptr<osg::Node> buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter); osg::ref_ptr<osg::Node> buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter);
void updateWaterCulling();
// split each ESM::Cell into mNumSplits*mNumSplits terrain chunks // split each ESM::Cell into mNumSplits*mNumSplits terrain chunks
unsigned int mNumSplits; unsigned int mNumSplits;

View file

@ -19,6 +19,7 @@ World::World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSyst
, mParent(parent) , mParent(parent)
, mResourceSystem(resourceSystem) , mResourceSystem(resourceSystem)
, mBorderVisible(false) , mBorderVisible(false)
, mHeightCullCallback(new HeightCullCallback)
{ {
mTerrainRoot = new osg::Group; mTerrainRoot = new osg::Group;
mTerrainRoot->setNodeMask(nodeMask); mTerrainRoot->setNodeMask(nodeMask);
@ -120,4 +121,11 @@ void World::clearAssociatedCaches()
mChunkManager->clearCache(); mChunkManager->clearCache();
} }
osg::Callback* World::getHeightCullCallback(float highz, unsigned int mask)
{
mHeightCullCallback->setHighZ(highz);
mHeightCullCallback->setCullMask(mask);
return mHeightCullCallback;
}
} }

View file

@ -4,6 +4,7 @@
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Referenced> #include <osg/Referenced>
#include <osg/Vec3f> #include <osg/Vec3f>
#include <osg/NodeCallback>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
@ -39,6 +40,37 @@ namespace Terrain
class ChunkManager; class ChunkManager;
class CompositeMapRenderer; class CompositeMapRenderer;
class HeightCullCallback : public osg::NodeCallback
{
public:
HeightCullCallback() : mLowZ(-FLT_MAX), mHighZ(FLT_MAX), mMask(~0) {}
void setLowZ(float z)
{
mLowZ = z;
}
float getLowZ() const { return mLowZ; }
void setHighZ(float highZ)
{
mHighZ = highZ;
}
float getHighZ() const { return mHighZ; }
void setCullMask(unsigned int mask) { mMask = mask; }
unsigned int getCullMask() const { return mMask; }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (mLowZ <= mHighZ)
traverse(node, nv);
}
private:
float mLowZ;
float mHighZ;
unsigned int mMask;
};
/** /**
* @brief A View is a collection of rendering objects that are visible from a given camera/intersection. * @brief A View is a collection of rendering objects that are visible from a given camera/intersection.
* The base View class is part of the interface for usage in conjunction with preload feature. * The base View class is part of the interface for usage in conjunction with preload feature.
@ -116,6 +148,8 @@ namespace Terrain
Storage* getStorage() { return mStorage; } Storage* getStorage() { return mStorage; }
osg::Callback* getHeightCullCallback(float highz, unsigned int mask);
protected: protected:
Storage* mStorage; Storage* mStorage;
@ -135,6 +169,7 @@ namespace Terrain
bool mBorderVisible; bool mBorderVisible;
std::set<std::pair<int,int>> mLoadedCells; std::set<std::pair<int,int>> mLoadedCells;
osg::ref_ptr<HeightCullCallback> mHeightCullCallback;
}; };
} }