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

Preliminary rendering of QuadTreeWorld

This commit is contained in:
scrawl 2017-03-08 22:19:48 +01:00
parent e36bdb490e
commit 7d004bf757
3 changed files with 140 additions and 53 deletions

View file

@ -5,46 +5,7 @@
#include <osgUtil/CullVisitor> #include <osgUtil/CullVisitor>
#include "defs.hpp" #include "defs.hpp"
#include "viewdata.hpp"
namespace
{
float distance(const osg::BoundingBox& box, const osg::Vec3f& v)
{
if (box.contains(v))
return 0;
else
{
osg::Vec3f maxDist(0,0,0);
if (v.x() < box.xMin())
maxDist.x() = box.xMin() - v.x();
else if (v.x() > box.xMax())
maxDist.x() = v.x() - box.xMax();
if (v.y() < box.yMin())
maxDist.y() = box.yMin() - v.y();
else if (v.y() > box.yMax())
maxDist.y() = v.y() - box.yMax();
if (v.z() < box.zMin())
maxDist.z() = box.zMin() - v.z();
else if (v.z() > box.zMax())
maxDist.z() = v.z() - box.zMax();
return maxDist.length();
}
}
int Log2( int n )
{
assert(n > 0);
int targetlevel = 0;
while (n >>= 1) ++targetlevel;
return targetlevel;
}
}
namespace Terrain namespace Terrain
{ {
@ -104,6 +65,10 @@ QuadTreeNode::QuadTreeNode(QuadTreeNode* parent, ChildDirection direction, float
mNeighbours[i] = 0; mNeighbours[i] = 0;
} }
QuadTreeNode::~QuadTreeNode()
{
}
QuadTreeNode* QuadTreeNode::getParent() QuadTreeNode* QuadTreeNode::getParent()
{ {
return mParent; return mParent;
@ -125,20 +90,49 @@ void QuadTreeNode::initNeighbours()
void QuadTreeNode::traverse(osg::NodeVisitor &nv) void QuadTreeNode::traverse(osg::NodeVisitor &nv)
{ {
if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR) if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
return; {
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv); osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
// do another culling test against bounding box as its much more accurate than the bounding sphere. // do another culling test against bounding box as its much more accurate than the bounding sphere.
if (cv->isCulled(mBoundingBox)) if (cv->isCulled(mBoundingBox))
return; return;
}
//float dist = distance(getBoundingBox(), nv.getEyePoint()); if ((mLodCallback && mLodCallback->isSufficientDetail(this, nv)) || !getNumChildren())
getView(nv)->add(this);
else
osg::Group::traverse(nv); osg::Group::traverse(nv);
} }
void QuadTreeNode::setLodCallback(LodCallback *lodCallback)
{
mLodCallback = lodCallback;
}
void QuadTreeNode::setViewDataMap(ViewDataMap *map)
{
mViewDataMap = map;
}
ViewDataMap *QuadTreeNode::getViewDataMap()
{
return mViewDataMap;
}
ViewData* QuadTreeNode::getView(osg::NodeVisitor &nv)
{
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
{
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
return mViewDataMap->getViewData(cv->getCurrentCamera(), true);
}
else // INTERSECTION_VISITOR
{
return mViewDataMap->getViewData(&nv, false);
}
}
void QuadTreeNode::setBoundingBox(const osg::BoundingBox &boundingBox) void QuadTreeNode::setBoundingBox(const osg::BoundingBox &boundingBox)
{ {
mBoundingBox = boundingBox; mBoundingBox = boundingBox;

View file

@ -17,10 +17,23 @@ namespace Terrain
Root Root
}; };
class QuadTreeNode;
class LodCallback : public osg::Referenced
{
public:
virtual ~LodCallback() {}
virtual bool isSufficientDetail(QuadTreeNode *node, osg::NodeVisitor &nv) = 0;
};
class ViewDataMap;
class ViewData;
class QuadTreeNode : public osg::Group class QuadTreeNode : public osg::Group
{ {
public: public:
QuadTreeNode(QuadTreeNode* parent, ChildDirection dir, float size, const osg::Vec2f& center); QuadTreeNode(QuadTreeNode* parent, ChildDirection dir, float size, const osg::Vec2f& center);
virtual ~QuadTreeNode();
QuadTreeNode* getParent(); QuadTreeNode* getParent();
@ -49,6 +62,17 @@ namespace Terrain
virtual void traverse(osg::NodeVisitor& nv); virtual void traverse(osg::NodeVisitor& nv);
/// Set the Lod callback to use for determining when to stop traversing further down the quad tree.
void setLodCallback(LodCallback* lodCallback);
/// Set the view data map that the finally used nodes for a given camera/intersection are pushed onto.
void setViewDataMap(ViewDataMap* map);
ViewDataMap* getViewDataMap();
/// Create or retrieve a view for the given traversal.
ViewData* getView(osg::NodeVisitor& nv);
private: private:
QuadTreeNode* mParent; QuadTreeNode* mParent;
@ -59,6 +83,10 @@ namespace Terrain
osg::BoundingBox mBoundingBox; osg::BoundingBox mBoundingBox;
float mSize; float mSize;
osg::Vec2f mCenter; osg::Vec2f mCenter;
osg::ref_ptr<LodCallback> mLodCallback;
osg::ref_ptr<ViewDataMap> mViewDataMap;
}; };
} }

View file

@ -4,10 +4,8 @@
#include "quadtreenode.hpp" #include "quadtreenode.hpp"
#include "storage.hpp" #include "storage.hpp"
#include "viewdata.hpp"
#include "chunkmanager.hpp"
#include <osg/io_utils>
#include <osg/Timer>
namespace namespace
{ {
@ -29,11 +27,57 @@ namespace
return 1 << depth; return 1 << depth;
} }
int Log2( unsigned int n )
{
int targetlevel = 0;
while (n >>= 1) ++targetlevel;
return targetlevel;
}
float distance(const osg::BoundingBox& box, const osg::Vec3f& v)
{
if (box.contains(v))
return 0;
else
{
osg::Vec3f maxDist(0,0,0);
if (v.x() < box.xMin())
maxDist.x() = box.xMin() - v.x();
else if (v.x() > box.xMax())
maxDist.x() = v.x() - box.xMax();
if (v.y() < box.yMin())
maxDist.y() = box.yMin() - v.y();
else if (v.y() > box.yMax())
maxDist.y() = v.y() - box.yMax();
if (v.z() < box.zMin())
maxDist.z() = box.zMin() - v.z();
else if (v.z() > box.zMax())
maxDist.z() = v.z() - box.zMax();
return maxDist.length();
}
}
} }
namespace Terrain namespace Terrain
{ {
class DefaultLodCallback : public LodCallback
{
public:
virtual bool isSufficientDetail(QuadTreeNode* node, osg::NodeVisitor& nv)
{
float dist = distance(node->getBoundingBox(), nv.getEyePoint());
int nativeLodLevel = Log2(static_cast<unsigned int>(node->getSize()*4));
int lodLevel = Log2(static_cast<unsigned int>(dist/2048.0));
return nativeLodLevel <= lodLevel;
}
};
class RootNode : public QuadTreeNode class RootNode : public QuadTreeNode
{ {
@ -84,6 +128,7 @@ public:
float centerY = (mMinY+mMaxY)/2.f + (size-origSizeY)/2.f; float centerY = (mMinY+mMaxY)/2.f + (size-origSizeY)/2.f;
mRootNode = new RootNode(size, osg::Vec2f(centerX, centerY)); mRootNode = new RootNode(size, osg::Vec2f(centerX, centerY));
mRootNode->setViewDataMap(new ViewDataMap);
addChildren(mRootNode); addChildren(mRootNode);
mRootNode->initNeighbours(); mRootNode->initNeighbours();
@ -125,6 +170,8 @@ public:
} }
osg::ref_ptr<QuadTreeNode> node = new QuadTreeNode(parent, direction, size, center); osg::ref_ptr<QuadTreeNode> node = new QuadTreeNode(parent, direction, size, center);
node->setLodCallback(new DefaultLodCallback);
node->setViewDataMap(parent->getViewDataMap());
parent->addChild(node); parent->addChild(node);
if (center.x() - size > mMaxX if (center.x() - size > mMaxX
@ -190,10 +237,28 @@ QuadTreeWorld::~QuadTreeWorld()
void QuadTreeWorld::accept(osg::NodeVisitor &nv) void QuadTreeWorld::accept(osg::NodeVisitor &nv)
{ {
if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR)// && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR)
return; return;
mRootNode->traverse(nv); mRootNode->traverse(nv);
ViewData* vd = mRootNode->getView(nv);
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
{
ViewData::Entry& entry = vd->getEntry(i);
if (!entry.mRenderingNode)
{
int lod = Log2(int(entry.mNode->getSize()));
entry.mRenderingNode = mChunkManager->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), lod);
}
entry.mRenderingNode->accept(nv);
}
vd->reset(nv.getTraversalNumber());
mRootNode->getViewDataMap()->clearUnusedViews(nv.getTraversalNumber());
} }
void QuadTreeWorld::loadCell(int x, int y) void QuadTreeWorld::loadCell(int x, int y)