forked from teamnwah/openmw-tes3coop
Preliminary rendering of QuadTreeWorld
This commit is contained in:
parent
e36bdb490e
commit
7d004bf757
3 changed files with 140 additions and 53 deletions
|
@ -5,46 +5,7 @@
|
|||
#include <osgUtil/CullVisitor>
|
||||
|
||||
#include "defs.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;
|
||||
}
|
||||
|
||||
}
|
||||
#include "viewdata.hpp"
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
@ -104,6 +65,10 @@ QuadTreeNode::QuadTreeNode(QuadTreeNode* parent, ChildDirection direction, float
|
|||
mNeighbours[i] = 0;
|
||||
}
|
||||
|
||||
QuadTreeNode::~QuadTreeNode()
|
||||
{
|
||||
}
|
||||
|
||||
QuadTreeNode* QuadTreeNode::getParent()
|
||||
{
|
||||
return mParent;
|
||||
|
@ -125,18 +90,47 @@ void QuadTreeNode::initNeighbours()
|
|||
|
||||
void QuadTreeNode::traverse(osg::NodeVisitor &nv)
|
||||
{
|
||||
if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR)
|
||||
return;
|
||||
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
||||
{
|
||||
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.
|
||||
if (cv->isCulled(mBoundingBox))
|
||||
return;
|
||||
}
|
||||
|
||||
// do another culling test against bounding box as its much more accurate than the bounding sphere.
|
||||
if (cv->isCulled(mBoundingBox))
|
||||
return;
|
||||
if ((mLodCallback && mLodCallback->isSufficientDetail(this, nv)) || !getNumChildren())
|
||||
getView(nv)->add(this);
|
||||
else
|
||||
osg::Group::traverse(nv);
|
||||
}
|
||||
|
||||
//float dist = distance(getBoundingBox(), nv.getEyePoint());
|
||||
void QuadTreeNode::setLodCallback(LodCallback *lodCallback)
|
||||
{
|
||||
mLodCallback = lodCallback;
|
||||
}
|
||||
|
||||
osg::Group::traverse(nv);
|
||||
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)
|
||||
|
|
|
@ -17,10 +17,23 @@ namespace Terrain
|
|||
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
|
||||
{
|
||||
public:
|
||||
QuadTreeNode(QuadTreeNode* parent, ChildDirection dir, float size, const osg::Vec2f& center);
|
||||
virtual ~QuadTreeNode();
|
||||
|
||||
QuadTreeNode* getParent();
|
||||
|
||||
|
@ -49,6 +62,17 @@ namespace Terrain
|
|||
|
||||
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:
|
||||
QuadTreeNode* mParent;
|
||||
|
||||
|
@ -59,6 +83,10 @@ namespace Terrain
|
|||
osg::BoundingBox mBoundingBox;
|
||||
float mSize;
|
||||
osg::Vec2f mCenter;
|
||||
|
||||
osg::ref_ptr<LodCallback> mLodCallback;
|
||||
|
||||
osg::ref_ptr<ViewDataMap> mViewDataMap;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -4,10 +4,8 @@
|
|||
|
||||
#include "quadtreenode.hpp"
|
||||
#include "storage.hpp"
|
||||
|
||||
|
||||
#include <osg/io_utils>
|
||||
#include <osg/Timer>
|
||||
#include "viewdata.hpp"
|
||||
#include "chunkmanager.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -29,11 +27,57 @@ namespace
|
|||
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
|
||||
{
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -84,6 +128,7 @@ public:
|
|||
float centerY = (mMinY+mMaxY)/2.f + (size-origSizeY)/2.f;
|
||||
|
||||
mRootNode = new RootNode(size, osg::Vec2f(centerX, centerY));
|
||||
mRootNode->setViewDataMap(new ViewDataMap);
|
||||
addChildren(mRootNode);
|
||||
|
||||
mRootNode->initNeighbours();
|
||||
|
@ -125,6 +170,8 @@ public:
|
|||
}
|
||||
|
||||
osg::ref_ptr<QuadTreeNode> node = new QuadTreeNode(parent, direction, size, center);
|
||||
node->setLodCallback(new DefaultLodCallback);
|
||||
node->setViewDataMap(parent->getViewDataMap());
|
||||
parent->addChild(node);
|
||||
|
||||
if (center.x() - size > mMaxX
|
||||
|
@ -190,10 +237,28 @@ QuadTreeWorld::~QuadTreeWorld()
|
|||
|
||||
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;
|
||||
|
||||
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)
|
||||
|
|
Loading…
Reference in a new issue