mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-29 22:36:43 +00:00
Merge pull request #2325 from akortunov/optimize_terrain
Optimize the Distant Terrain memory consumption
This commit is contained in:
commit
bc0e214cd9
10 changed files with 139 additions and 180 deletions
|
@ -30,7 +30,6 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T
|
||||||
, mCompositeMapSize(512)
|
, mCompositeMapSize(512)
|
||||||
, mCompositeMapLevel(1.f)
|
, mCompositeMapLevel(1.f)
|
||||||
, mMaxCompGeometrySize(1.f)
|
, mMaxCompGeometrySize(1.f)
|
||||||
, mCullingActive(true)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -208,7 +207,8 @@ osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Ve
|
||||||
|
|
||||||
mCompositeMapRenderer->addCompositeMap(compositeMap.get(), false);
|
mCompositeMapRenderer->addCompositeMap(compositeMap.get(), false);
|
||||||
|
|
||||||
transform->getOrCreateUserDataContainer()->setUserData(compositeMap);
|
geometry->setCompositeMap(compositeMap);
|
||||||
|
geometry->setCompositeMapRenderer(mCompositeMapRenderer);
|
||||||
|
|
||||||
TextureLayer layer;
|
TextureLayer layer;
|
||||||
layer.mDiffuseMap = compositeMap->mTexture;
|
layer.mDiffuseMap = compositeMap->mTexture;
|
||||||
|
@ -222,14 +222,7 @@ osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Ve
|
||||||
}
|
}
|
||||||
|
|
||||||
transform->addChild(geometry);
|
transform->addChild(geometry);
|
||||||
|
transform->getBound();
|
||||||
if (!mCullingActive)
|
|
||||||
{
|
|
||||||
transform->setCullingActive(false);
|
|
||||||
geometry->setCullingActive(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
transform->getBound();
|
|
||||||
|
|
||||||
if (mSceneManager->getIncrementalCompileOperation())
|
if (mSceneManager->getIncrementalCompileOperation())
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,7 +61,6 @@ QuadTreeNode::QuadTreeNode(QuadTreeNode* parent, ChildDirection direction, float
|
||||||
, mValidBounds(false)
|
, mValidBounds(false)
|
||||||
, mSize(size)
|
, mSize(size)
|
||||||
, mCenter(center)
|
, mCenter(center)
|
||||||
, mViewDataMap(nullptr)
|
|
||||||
{
|
{
|
||||||
for (unsigned int i=0; i<4; ++i)
|
for (unsigned int i=0; i<4; ++i)
|
||||||
mNeighbours[i] = 0;
|
mNeighbours[i] = 0;
|
||||||
|
@ -109,56 +108,63 @@ void QuadTreeNode::initNeighbours()
|
||||||
getChild(i)->initNeighbours();
|
getChild(i)->initNeighbours();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuadTreeNode::traverse(osg::NodeVisitor &nv)
|
void QuadTreeNode::traverse(ViewData* vd, const osg::Vec3f& viewPoint, LodCallback* lodCallback, float maxDist)
|
||||||
{
|
{
|
||||||
if (!hasValidBounds())
|
if (!hasValidBounds())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool needsUpdate = true;
|
float dist = distance(viewPoint);
|
||||||
ViewData* vd = getView(nv, needsUpdate);
|
if (dist > maxDist)
|
||||||
|
return;
|
||||||
|
|
||||||
if ((mLodCallback && mLodCallback->isSufficientDetail(this, distance(vd->getViewPoint()))) || !getNumChildren())
|
bool stopTraversal = (lodCallback->isSufficientDetail(this, dist)) || !getNumChildren();
|
||||||
vd->add(this, true);
|
|
||||||
|
if (stopTraversal)
|
||||||
|
vd->add(this);
|
||||||
else
|
else
|
||||||
osg::Group::traverse(nv);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QuadTreeNode::setLodCallback(LodCallback *lodCallback)
|
|
||||||
{
|
|
||||||
mLodCallback = lodCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
LodCallback *QuadTreeNode::getLodCallback()
|
|
||||||
{
|
|
||||||
return mLodCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QuadTreeNode::setViewDataMap(ViewDataMap *map)
|
|
||||||
{
|
|
||||||
mViewDataMap = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewDataMap *QuadTreeNode::getViewDataMap()
|
|
||||||
{
|
|
||||||
return mViewDataMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewData* QuadTreeNode::getView(osg::NodeVisitor &nv, bool& needsUpdate)
|
|
||||||
{
|
|
||||||
ViewData* vd = NULL;
|
|
||||||
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
|
||||||
{
|
{
|
||||||
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
|
for (unsigned int i=0; i<getNumChildren(); ++i)
|
||||||
vd = mViewDataMap->getViewData(cv->getCurrentCamera(), nv.getViewPoint(), needsUpdate);
|
getChild(i)->traverse(vd, viewPoint, lodCallback, maxDist);
|
||||||
}
|
}
|
||||||
else // INTERSECTION_VISITOR
|
}
|
||||||
|
|
||||||
|
void QuadTreeNode::traverseTo(ViewData* vd, float size, const osg::Vec2f& center)
|
||||||
|
{
|
||||||
|
if (!hasValidBounds())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (getCenter().x() + getSize()/2.f <= center.x() - size/2.f
|
||||||
|
|| getCenter().x() - getSize()/2.f >= center.x() + size/2.f
|
||||||
|
|| getCenter().y() + getSize()/2.f <= center.y() - size/2.f
|
||||||
|
|| getCenter().y() - getSize()/2.f >= center.y() + size/2.f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool stopTraversal = (getSize() == size);
|
||||||
|
|
||||||
|
if (stopTraversal)
|
||||||
|
vd->add(this);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
osg::Vec3f viewPoint = nv.getViewPoint();
|
for (unsigned int i=0; i<getNumChildren(); ++i)
|
||||||
static osg::ref_ptr<osg::Object> dummyObj = new osg::DummyObject;
|
getChild(i)->traverseTo(vd, size, center);
|
||||||
vd = mViewDataMap->getViewData(dummyObj.get(), viewPoint, needsUpdate);
|
}
|
||||||
needsUpdate = true;
|
}
|
||||||
|
|
||||||
|
void QuadTreeNode::intersect(ViewData* vd, TerrainLineIntersector* intersector)
|
||||||
|
{
|
||||||
|
if (!hasValidBounds())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!intersector->intersectAndClip(getBoundingBox()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (getNumChildren() == 0)
|
||||||
|
vd->add(this);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (unsigned int i=0; i<getNumChildren(); ++i)
|
||||||
|
getChild(i)->intersect(vd, intersector);
|
||||||
}
|
}
|
||||||
return vd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuadTreeNode::setBoundingBox(const osg::BoundingBox &boundingBox)
|
void QuadTreeNode::setBoundingBox(const osg::BoundingBox &boundingBox)
|
||||||
|
|
|
@ -2,12 +2,31 @@
|
||||||
#define OPENMW_COMPONENTS_TERRAIN_QUADTREENODE_H
|
#define OPENMW_COMPONENTS_TERRAIN_QUADTREENODE_H
|
||||||
|
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
|
#include <osgUtil/LineSegmentIntersector>
|
||||||
|
|
||||||
#include "defs.hpp"
|
#include "defs.hpp"
|
||||||
|
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class TerrainLineIntersector : public osgUtil::LineSegmentIntersector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TerrainLineIntersector(osgUtil::LineSegmentIntersector* intersector, osg::Matrix& matrix) :
|
||||||
|
osgUtil::LineSegmentIntersector(intersector->getStart() * matrix, intersector->getEnd() * matrix)
|
||||||
|
{
|
||||||
|
setPrecisionHint(intersector->getPrecisionHint());
|
||||||
|
_intersectionLimit = intersector->getIntersectionLimit();
|
||||||
|
_parent = intersector;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool intersectAndClip(const osg::BoundingBox& bbInput)
|
||||||
|
{
|
||||||
|
osg::Vec3d s(_start), e(_end);
|
||||||
|
return osgUtil::LineSegmentIntersector::intersectAndClip(s, e, bbInput);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
enum ChildDirection
|
enum ChildDirection
|
||||||
{
|
{
|
||||||
NW = 0,
|
NW = 0,
|
||||||
|
@ -72,20 +91,14 @@ namespace Terrain
|
||||||
/// center in cell coordinates
|
/// center in cell coordinates
|
||||||
const osg::Vec2f& getCenter() const;
|
const osg::Vec2f& getCenter() const;
|
||||||
|
|
||||||
virtual void traverse(osg::NodeVisitor& nv);
|
/// Traverse nodes according to LOD selection.
|
||||||
|
void traverse(ViewData* vd, const osg::Vec3f& viewPoint, LodCallback* lodCallback, float maxDist);
|
||||||
|
|
||||||
/// Set the Lod callback to use for determining when to stop traversing further down the quad tree.
|
/// Traverse to a specific node and add only that node.
|
||||||
void setLodCallback(LodCallback* lodCallback);
|
void traverseTo(ViewData* vd, float size, const osg::Vec2f& center);
|
||||||
|
|
||||||
LodCallback* getLodCallback();
|
/// Adds all leaf nodes which intersect the line from start to end
|
||||||
|
void intersect(ViewData* vd, TerrainLineIntersector* intersector);
|
||||||
/// 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, bool& needsUpdate);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QuadTreeNode* mParent;
|
QuadTreeNode* mParent;
|
||||||
|
@ -98,10 +111,6 @@ namespace Terrain
|
||||||
bool mValidBounds;
|
bool mValidBounds;
|
||||||
float mSize;
|
float mSize;
|
||||||
osg::Vec2f mCenter;
|
osg::Vec2f mCenter;
|
||||||
|
|
||||||
osg::ref_ptr<LodCallback> mLodCallback;
|
|
||||||
|
|
||||||
ViewDataMap* mViewDataMap;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,12 +97,10 @@ private:
|
||||||
class QuadTreeBuilder
|
class QuadTreeBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QuadTreeBuilder(Terrain::Storage* storage, ViewDataMap* viewDataMap, float lodFactor, float minSize)
|
QuadTreeBuilder(Terrain::Storage* storage, float minSize)
|
||||||
: mStorage(storage)
|
: mStorage(storage)
|
||||||
, mLodFactor(lodFactor)
|
|
||||||
, mMinX(0.f), mMaxX(0.f), mMinY(0.f), mMaxY(0.f)
|
, mMinX(0.f), mMaxX(0.f), mMinY(0.f), mMaxY(0.f)
|
||||||
, mMinSize(minSize)
|
, mMinSize(minSize)
|
||||||
, mViewDataMap(viewDataMap)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,8 +118,6 @@ 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(mViewDataMap);
|
|
||||||
mRootNode->setLodCallback(new DefaultLodCallback(mLodFactor, mMinSize));
|
|
||||||
addChildren(mRootNode);
|
addChildren(mRootNode);
|
||||||
|
|
||||||
mRootNode->initNeighbours();
|
mRootNode->initNeighbours();
|
||||||
|
@ -170,8 +166,6 @@ 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(parent->getLodCallback());
|
|
||||||
node->setViewDataMap(mViewDataMap);
|
|
||||||
|
|
||||||
if (center.x() - halfSize > mMaxX
|
if (center.x() - halfSize > mMaxX
|
||||||
|| center.x() + halfSize < mMinX
|
|| center.x() + halfSize < mMinX
|
||||||
|
@ -191,15 +185,14 @@ public:
|
||||||
|
|
||||||
if (node->getSize() <= mMinSize)
|
if (node->getSize() <= mMinSize)
|
||||||
{
|
{
|
||||||
// We arrived at a leaf
|
// We arrived at a leaf.
|
||||||
float minZ,maxZ;
|
// Since the tree is used for LOD level selection instead of culling, we do not need to load the actual height data here.
|
||||||
if (mStorage->getMinMaxHeights(size, center, minZ, maxZ))
|
float minZ = -std::numeric_limits<float>::max();
|
||||||
{
|
float maxZ = std::numeric_limits<float>::max();
|
||||||
float cellWorldSize = mStorage->getCellWorldSize();
|
float cellWorldSize = mStorage->getCellWorldSize();
|
||||||
osg::BoundingBox boundingBox(osg::Vec3f((center.x()-halfSize)*cellWorldSize, (center.y()-halfSize)*cellWorldSize, minZ),
|
osg::BoundingBox boundingBox(osg::Vec3f((center.x()-halfSize)*cellWorldSize, (center.y()-halfSize)*cellWorldSize, minZ),
|
||||||
osg::Vec3f((center.x()+halfSize)*cellWorldSize, (center.y()+halfSize)*cellWorldSize, maxZ));
|
osg::Vec3f((center.x()+halfSize)*cellWorldSize, (center.y()+halfSize)*cellWorldSize, maxZ));
|
||||||
node->setBoundingBox(boundingBox);
|
node->setBoundingBox(boundingBox);
|
||||||
}
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -220,9 +213,9 @@ private:
|
||||||
float mLodFactor;
|
float mLodFactor;
|
||||||
float mMinX, mMaxX, mMinY, mMaxY;
|
float mMinX, mMaxX, mMinY, mMaxY;
|
||||||
float mMinSize;
|
float mMinSize;
|
||||||
ViewDataMap* mViewDataMap;
|
|
||||||
|
|
||||||
osg::ref_ptr<RootNode> mRootNode;
|
osg::ref_ptr<RootNode> mRootNode;
|
||||||
|
osg::ref_ptr<LodCallback> mLodCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float compMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize)
|
QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float compMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize)
|
||||||
|
@ -233,9 +226,6 @@ QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resour
|
||||||
, mVertexLodMod(vertexLodMod)
|
, mVertexLodMod(vertexLodMod)
|
||||||
, mViewDistance(std::numeric_limits<float>::max())
|
, mViewDistance(std::numeric_limits<float>::max())
|
||||||
{
|
{
|
||||||
// No need for culling on the Drawable / Transform level as the quad tree performs the culling already.
|
|
||||||
mChunkManager->setCullingActive(false);
|
|
||||||
|
|
||||||
mChunkManager->setCompositeMapSize(compMapResolution);
|
mChunkManager->setCompositeMapSize(compMapResolution);
|
||||||
mChunkManager->setCompositeMapLevel(compMapLevel);
|
mChunkManager->setCompositeMapLevel(compMapLevel);
|
||||||
mChunkManager->setMaxCompositeGeometrySize(maxCompGeometrySize);
|
mChunkManager->setMaxCompositeGeometrySize(maxCompGeometrySize);
|
||||||
|
@ -246,52 +236,6 @@ QuadTreeWorld::~QuadTreeWorld()
|
||||||
mViewDataMap->clear();
|
mViewDataMap->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallback* lodCallback, const osg::Vec3f& viewPoint, bool visible, float maxDist)
|
|
||||||
{
|
|
||||||
if (!node->hasValidBounds())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
|
||||||
visible = visible && !static_cast<osgUtil::CullVisitor*>(nv)->isCulled(node->getBoundingBox());
|
|
||||||
|
|
||||||
float dist = node->distance(viewPoint);
|
|
||||||
if (dist > maxDist)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool stopTraversal = (lodCallback && lodCallback->isSufficientDetail(node, dist)) || !node->getNumChildren();
|
|
||||||
|
|
||||||
if (stopTraversal)
|
|
||||||
vd->add(node, visible);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (unsigned int i=0; i<node->getNumChildren(); ++i)
|
|
||||||
traverse(node->getChild(i), vd, nv, lodCallback, viewPoint, visible, maxDist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void traverseToCell(QuadTreeNode* node, ViewData* vd, int cellX, int cellY)
|
|
||||||
{
|
|
||||||
if (!node->hasValidBounds())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (node->getCenter().x() + node->getSize()/2.f <= cellX
|
|
||||||
|| node->getCenter().x() - node->getSize()/2.f >= cellX+1
|
|
||||||
|| node->getCenter().y() + node->getSize()/2.f <= cellY
|
|
||||||
|| node->getCenter().y() - node->getSize()/2.f >= cellY+1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool stopTraversal = !node->getNumChildren();
|
|
||||||
|
|
||||||
if (stopTraversal)
|
|
||||||
vd->add(node, true);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (unsigned int i=0; i<node->getNumChildren(); ++i)
|
|
||||||
traverseToCell(node->getChild(i), vd, cellX, cellY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get the level of vertex detail to render this node at, expressed relative to the native resolution of the data set.
|
/// get the level of vertex detail to render this node at, expressed relative to the native resolution of the data set.
|
||||||
unsigned int getVertexLod(QuadTreeNode* node, int vertexLodMod)
|
unsigned int getVertexLod(QuadTreeNode* node, int vertexLodMod)
|
||||||
{
|
{
|
||||||
|
@ -383,8 +327,15 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsUpdate = false;
|
bool needsUpdate = true;
|
||||||
ViewData* vd = mRootNode->getView(nv, needsUpdate);
|
ViewData* vd = nullptr;
|
||||||
|
if (isCullVisitor)
|
||||||
|
vd = mViewDataMap->getViewData(static_cast<osgUtil::CullVisitor*>(&nv)->getCurrentCamera(), nv.getViewPoint(), needsUpdate);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static ViewData sIntersectionViewData;
|
||||||
|
vd = &sIntersectionViewData;
|
||||||
|
}
|
||||||
|
|
||||||
if (needsUpdate)
|
if (needsUpdate)
|
||||||
{
|
{
|
||||||
|
@ -400,21 +351,23 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
|
||||||
int x,y;
|
int x,y;
|
||||||
stream >> x;
|
stream >> x;
|
||||||
stream >> y;
|
stream >> y;
|
||||||
traverseToCell(mRootNode.get(), vd, x,y);
|
mRootNode->traverseTo(vd, 1, osg::Vec2f(x+0.5,y+0.5));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getViewPoint(), true, mViewDistance);
|
mRootNode->traverse(vd, cv->getViewPoint(), mLodCallback, mViewDistance);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mRootNode->traverse(nv);
|
|
||||||
}
|
|
||||||
else if (isCullVisitor)
|
|
||||||
{
|
|
||||||
// view point is the same, but must still update visible status in case the camera has rotated
|
|
||||||
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
|
|
||||||
{
|
{
|
||||||
ViewData::Entry& entry = vd->getEntry(i);
|
osgUtil::IntersectionVisitor* iv = static_cast<osgUtil::IntersectionVisitor*>(&nv);
|
||||||
entry.set(entry.mNode, !static_cast<osgUtil::CullVisitor*>(&nv)->isCulled(entry.mNode->getBoundingBox()));
|
osgUtil::LineSegmentIntersector* lineIntersector = dynamic_cast<osgUtil::LineSegmentIntersector*>(iv->getIntersector());
|
||||||
|
if (!lineIntersector)
|
||||||
|
throw std::runtime_error("Cannot update QuadTreeWorld: node visitor is not LineSegmentIntersector");
|
||||||
|
|
||||||
|
osg::Matrix matrix = osg::Matrix::identity();
|
||||||
|
if (lineIntersector->getCoordinateFrame() == osgUtil::Intersector::CoordinateFrame::MODEL && iv->getModelMatrix() == 0)
|
||||||
|
matrix = lineIntersector->getTransformation(*iv, osgUtil::Intersector::CoordinateFrame::MODEL);
|
||||||
|
osg::ref_ptr<TerrainLineIntersector> terrainIntersector (new TerrainLineIntersector(lineIntersector, matrix));
|
||||||
|
mRootNode->intersect(vd, terrainIntersector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,21 +377,11 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
|
||||||
|
|
||||||
loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get());
|
loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get());
|
||||||
|
|
||||||
if (entry.mVisible)
|
entry.mRenderingNode->accept(nv);
|
||||||
{
|
|
||||||
osg::UserDataContainer* udc = entry.mRenderingNode->getUserDataContainer();
|
|
||||||
if (udc && udc->getUserData())
|
|
||||||
{
|
|
||||||
mCompositeMapRenderer->setImmediate(static_cast<CompositeMap*>(udc->getUserData()));
|
|
||||||
udc->setUserData(nullptr);
|
|
||||||
|
|
||||||
}
|
|
||||||
entry.mRenderingNode->accept(nv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCullVisitor)
|
if (!isCullVisitor)
|
||||||
vd->reset(); // 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.
|
||||||
|
|
||||||
vd->markUnchanged();
|
vd->markUnchanged();
|
||||||
|
|
||||||
|
@ -457,7 +400,8 @@ void QuadTreeWorld::ensureQuadTreeBuilt()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const float minSize = 1/8.f;
|
const float minSize = 1/8.f;
|
||||||
QuadTreeBuilder builder(mStorage, mViewDataMap.get(), mLodFactor, minSize);
|
mLodCallback = new DefaultLodCallback(mLodFactor, minSize);
|
||||||
|
QuadTreeBuilder builder(mStorage, minSize);
|
||||||
builder.build();
|
builder.build();
|
||||||
|
|
||||||
mRootNode = builder.getRootNode();
|
mRootNode = builder.getRootNode();
|
||||||
|
@ -483,7 +427,7 @@ void QuadTreeWorld::cacheCell(View *view, int x, int y)
|
||||||
{
|
{
|
||||||
ensureQuadTreeBuilt();
|
ensureQuadTreeBuilt();
|
||||||
ViewData* vd = static_cast<ViewData*>(view);
|
ViewData* vd = static_cast<ViewData*>(view);
|
||||||
traverseToCell(mRootNode.get(), vd, x, y);
|
mRootNode->traverseTo(vd, 1, osg::Vec2f(x+0.5f,y+0.5f));
|
||||||
|
|
||||||
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
|
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -503,7 +447,7 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, std::atomic
|
||||||
|
|
||||||
ViewData* vd = static_cast<ViewData*>(view);
|
ViewData* vd = static_cast<ViewData*>(view);
|
||||||
vd->setViewPoint(viewPoint);
|
vd->setViewPoint(viewPoint);
|
||||||
traverse(mRootNode.get(), vd, nullptr, mRootNode->getLodCallback(), viewPoint, false, mViewDistance);
|
mRootNode->traverse(vd, viewPoint, mLodCallback, mViewDistance);
|
||||||
|
|
||||||
for (unsigned int i=0; i<vd->getNumEntries() && !abort; ++i)
|
for (unsigned int i=0; i<vd->getNumEntries() && !abort; ++i)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace Terrain
|
||||||
{
|
{
|
||||||
class RootNode;
|
class RootNode;
|
||||||
class ViewDataMap;
|
class ViewDataMap;
|
||||||
|
class LodCallback;
|
||||||
|
|
||||||
/// @brief Terrain implementation that loads cells into a Quad Tree, with geometry LOD and texture LOD.
|
/// @brief Terrain implementation that loads cells into a Quad Tree, with geometry LOD and texture LOD.
|
||||||
class QuadTreeWorld : public TerrainGrid // note: derived from TerrainGrid is only to render default cells (see loadCell)
|
class QuadTreeWorld : public TerrainGrid // note: derived from TerrainGrid is only to render default cells (see loadCell)
|
||||||
|
@ -48,6 +49,7 @@ namespace Terrain
|
||||||
osg::ref_ptr<RootNode> mRootNode;
|
osg::ref_ptr<RootNode> mRootNode;
|
||||||
|
|
||||||
osg::ref_ptr<ViewDataMap> mViewDataMap;
|
osg::ref_ptr<ViewDataMap> mViewDataMap;
|
||||||
|
osg::ref_ptr<LodCallback> mLodCallback;
|
||||||
|
|
||||||
OpenThreads::Mutex mQuadTreeMutex;
|
OpenThreads::Mutex mQuadTreeMutex;
|
||||||
bool mQuadTreeBuilt;
|
bool mQuadTreeBuilt;
|
||||||
|
|
|
@ -4,13 +4,11 @@
|
||||||
|
|
||||||
#include <components/sceneutil/lightmanager.hpp>
|
#include <components/sceneutil/lightmanager.hpp>
|
||||||
|
|
||||||
|
#include "compositemaprenderer.hpp"
|
||||||
|
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
|
||||||
TerrainDrawable::TerrainDrawable()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
TerrainDrawable::TerrainDrawable(const TerrainDrawable ©, const osg::CopyOp ©op)
|
TerrainDrawable::TerrainDrawable(const TerrainDrawable ©, const osg::CopyOp ©op)
|
||||||
: osg::Geometry(copy, copyop)
|
: osg::Geometry(copy, copyop)
|
||||||
, mPasses(copy.mPasses)
|
, mPasses(copy.mPasses)
|
||||||
|
@ -63,6 +61,12 @@ void TerrainDrawable::cull(osgUtil::CullVisitor *cv)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mCompositeMap)
|
||||||
|
{
|
||||||
|
mCompositeMapRenderer->setImmediate(mCompositeMap);
|
||||||
|
mCompositeMap = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool pushedLight = mLightListCallback && mLightListCallback->pushLightState(this, cv);
|
bool pushedLight = mLightListCallback && mLightListCallback->pushLightState(this, cv);
|
||||||
|
|
||||||
for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it)
|
for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it)
|
||||||
|
|
|
@ -16,6 +16,9 @@ namespace SceneUtil
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class CompositeMap;
|
||||||
|
class CompositeMapRenderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclass of Geometry that supports built in multi-pass rendering and built in LightListCallback.
|
* Subclass of Geometry that supports built in multi-pass rendering and built in LightListCallback.
|
||||||
*/
|
*/
|
||||||
|
@ -28,7 +31,8 @@ namespace Terrain
|
||||||
virtual const char* className() const { return "TerrainDrawable"; }
|
virtual const char* className() const { return "TerrainDrawable"; }
|
||||||
virtual const char* libraryName() const { return "Terrain"; }
|
virtual const char* libraryName() const { return "Terrain"; }
|
||||||
|
|
||||||
TerrainDrawable();
|
TerrainDrawable() = default;
|
||||||
|
~TerrainDrawable() = default;
|
||||||
TerrainDrawable(const TerrainDrawable& copy, const osg::CopyOp& copyop);
|
TerrainDrawable(const TerrainDrawable& copy, const osg::CopyOp& copyop);
|
||||||
|
|
||||||
virtual void accept(osg::NodeVisitor &nv);
|
virtual void accept(osg::NodeVisitor &nv);
|
||||||
|
@ -41,10 +45,15 @@ namespace Terrain
|
||||||
|
|
||||||
virtual void compileGLObjects(osg::RenderInfo& renderInfo) const;
|
virtual void compileGLObjects(osg::RenderInfo& renderInfo) const;
|
||||||
|
|
||||||
|
void setCompositeMap(CompositeMap* map) { mCompositeMap = map; }
|
||||||
|
void setCompositeMapRenderer(CompositeMapRenderer* renderer) { mCompositeMapRenderer = renderer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PassVector mPasses;
|
PassVector mPasses;
|
||||||
|
|
||||||
osg::ref_ptr<SceneUtil::LightListCallback> mLightListCallback;
|
osg::ref_ptr<SceneUtil::LightListCallback> mLightListCallback;
|
||||||
|
osg::ref_ptr<CompositeMap> mCompositeMap;
|
||||||
|
osg::ref_ptr<CompositeMapRenderer> mCompositeMapRenderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,11 +61,6 @@ osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chu
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (parent)
|
if (parent)
|
||||||
parent->addChild(node);
|
parent->addChild(node);
|
||||||
|
|
||||||
osg::UserDataContainer* udc = node->getUserDataContainer();
|
|
||||||
if (udc && udc->getUserData())
|
|
||||||
mCompositeMapRenderer->setImmediate(static_cast<CompositeMap*>(udc->getUserData()));
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ void ViewData::copyFrom(const ViewData& other)
|
||||||
mViewPoint = other.mViewPoint;
|
mViewPoint = other.mViewPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewData::add(QuadTreeNode *node, bool visible)
|
void ViewData::add(QuadTreeNode *node)
|
||||||
{
|
{
|
||||||
unsigned int index = mNumEntries++;
|
unsigned int index = mNumEntries++;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ void ViewData::add(QuadTreeNode *node, bool visible)
|
||||||
mEntries.resize(index+1);
|
mEntries.resize(index+1);
|
||||||
|
|
||||||
Entry& entry = mEntries[index];
|
Entry& entry = mEntries[index];
|
||||||
if (entry.set(node, visible))
|
if (entry.set(node))
|
||||||
mChanged = true;
|
mChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ void ViewData::reset()
|
||||||
{
|
{
|
||||||
// clear any unused entries
|
// clear any unused entries
|
||||||
for (unsigned int i=mNumEntries; i<mEntries.size(); ++i)
|
for (unsigned int i=mNumEntries; i<mEntries.size(); ++i)
|
||||||
mEntries[i].set(nullptr, false);
|
mEntries[i].set(nullptr);
|
||||||
|
|
||||||
// reset index for next frame
|
// reset index for next frame
|
||||||
mNumEntries = 0;
|
mNumEntries = 0;
|
||||||
|
@ -83,7 +83,7 @@ void ViewData::reset()
|
||||||
void ViewData::clear()
|
void ViewData::clear()
|
||||||
{
|
{
|
||||||
for (unsigned int i=0; i<mEntries.size(); ++i)
|
for (unsigned int i=0; i<mEntries.size(); ++i)
|
||||||
mEntries[i].set(nullptr, false);
|
mEntries[i].set(nullptr);
|
||||||
mNumEntries = 0;
|
mNumEntries = 0;
|
||||||
mLastUsageTimeStamp = 0;
|
mLastUsageTimeStamp = 0;
|
||||||
mChanged = false;
|
mChanged = false;
|
||||||
|
@ -100,15 +100,13 @@ bool ViewData::contains(QuadTreeNode *node)
|
||||||
|
|
||||||
ViewData::Entry::Entry()
|
ViewData::Entry::Entry()
|
||||||
: mNode(nullptr)
|
: mNode(nullptr)
|
||||||
, mVisible(true)
|
|
||||||
, mLodFlags(0)
|
, mLodFlags(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ViewData::Entry::set(QuadTreeNode *node, bool visible)
|
bool ViewData::Entry::set(QuadTreeNode *node)
|
||||||
{
|
{
|
||||||
mVisible = visible;
|
|
||||||
if (node == mNode)
|
if (node == mNode)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Terrain
|
||||||
ViewData();
|
ViewData();
|
||||||
~ViewData();
|
~ViewData();
|
||||||
|
|
||||||
void add(QuadTreeNode* node, bool visible);
|
void add(QuadTreeNode* node);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
@ -33,10 +33,9 @@ namespace Terrain
|
||||||
{
|
{
|
||||||
Entry();
|
Entry();
|
||||||
|
|
||||||
bool set(QuadTreeNode* node, bool visible);
|
bool set(QuadTreeNode* node);
|
||||||
|
|
||||||
QuadTreeNode* mNode;
|
QuadTreeNode* mNode;
|
||||||
bool mVisible;
|
|
||||||
|
|
||||||
unsigned int mLodFlags;
|
unsigned int mLodFlags;
|
||||||
osg::ref_ptr<osg::Node> mRenderingNode;
|
osg::ref_ptr<osg::Node> mRenderingNode;
|
||||||
|
|
Loading…
Reference in a new issue