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:
parent
e36bdb490e
commit
7d004bf757
3 changed files with 140 additions and 53 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue