diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 5f6a83376..08b7c1300 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -31,10 +31,10 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T } -osg::ref_ptr ChunkManager::getChunk(float size, const osg::Vec2f ¢er, int lod) +osg::ref_ptr ChunkManager::getChunk(float size, const osg::Vec2f ¢er, int lod, unsigned int lodFlags) { std::ostringstream stream; - stream << size << " " << center.x() << " " << center.y(); + stream << size << " " << center.x() << " " << center.y() << " " << lod << " " << lodFlags; std::string id = stream.str(); osg::ref_ptr obj = mCache->getRefFromObjectCache(id); @@ -42,7 +42,7 @@ osg::ref_ptr ChunkManager::getChunk(float size, const osg::Vec2f &cen return obj->asNode(); else { - osg::ref_ptr node = createChunk(size, center, lod); + osg::ref_ptr node = createChunk(size, center, lod, lodFlags); mCache->addEntryToObjectCache(id, node.get()); return node; } @@ -156,7 +156,7 @@ std::vector > ChunkManager::createPasses(float chunk mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale); } -osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, int lod) +osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, int lod, unsigned int lodFlags) { osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); osg::ref_ptr transform (new SceneUtil::PositionAttitudeTransform); @@ -182,7 +182,7 @@ osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Ve unsigned int numVerts = (mStorage->getCellVertices()-1) * chunkSize / (1 << lod) + 1; - geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, 0)); + geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, lodFlags)); geometry->getBound(); diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 382e4a6b0..c7c1566a8 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -34,12 +34,12 @@ namespace Terrain public: ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager, CompositeMapRenderer* renderer); - osg::ref_ptr getChunk(float size, const osg::Vec2f& center, int lod); + osg::ref_ptr getChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; private: - osg::ref_ptr createChunk(float size, const osg::Vec2f& center, int lod); + osg::ref_ptr createChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); osg::ref_ptr createCompositeMapRTT(osg::ref_ptr& texture); diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index d556bb4fe..caf967e22 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -80,6 +80,11 @@ QuadTreeNode *QuadTreeNode::getChild(unsigned int i) return static_cast(Group::getChild(i)); } +QuadTreeNode *QuadTreeNode::getNeighbour(Direction dir) +{ + return mNeighbours[dir]; +} + void QuadTreeNode::initNeighbours() { for (int i=0; i<4; ++i) diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 9c27fa1ad..74e9fd512 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -255,6 +255,34 @@ void traverse(QuadTreeNode* node, ViewData* vd, osgUtil::CullVisitor* cv, bool v } } +unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd) +{ + unsigned int lodFlags = 0; + for (unsigned int i=0; i<4; ++i) + { + QuadTreeNode* neighbour = node->getNeighbour(static_cast(i)); + + // If the neighbour isn't currently rendering itself, + // go up until we find one. NOTE: We don't need to go down, + // because in that case neighbour's detail would be higher than + // our detail and the neighbour would handle stitching by itself. + while (neighbour && !vd->contains(neighbour)) + neighbour = neighbour->getParent(); + int lod = 0; + if (neighbour) + lod = Log2(int(neighbour->getSize())); + + if (lod <= ourLod) // We only need to worry about neighbours less detailed than we are - + lod = 0; // neighbours with more detail will do the stitching themselves + // Use 4 bits for each LOD delta + if (lod > 0) + { + lodFlags |= static_cast(lod - ourLod) << (4*i); + } + } + return lodFlags; +} + void QuadTreeWorld::accept(osg::NodeVisitor &nv) { if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR)// && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR) @@ -275,8 +303,9 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) 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); + int ourLod = Log2(int(entry.mNode->getSize())); + unsigned int lodFlags = getLodFlags(entry.mNode, ourLod, vd); + entry.mRenderingNode = mChunkManager->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, lodFlags); } if (entry.mVisible) diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index bb6020dd8..04b29e169 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -47,7 +47,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu } else { - osg::ref_ptr node = mChunkManager->getChunk(chunkSize, chunkCenter, 0); + osg::ref_ptr node = mChunkManager->getChunk(chunkSize, chunkCenter, 0, 0); if (!node) return NULL; if (parent) diff --git a/components/terrain/viewdata.cpp b/components/terrain/viewdata.cpp index 71768bd7c..bc8448b0e 100644 --- a/components/terrain/viewdata.cpp +++ b/components/terrain/viewdata.cpp @@ -54,6 +54,14 @@ void ViewData::clear() mFrameLastUsed = 0; } +bool ViewData::contains(QuadTreeNode *node) +{ + for (unsigned int i=0; i