1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-21 10:53:51 +00:00

Use a proper node hierarchy; disconnect the root when entering interior

This commit is contained in:
scrawl 2013-08-20 16:42:24 +02:00
parent 3bf3bd4b8c
commit ce5ea6d7d2
5 changed files with 71 additions and 33 deletions

View file

@ -988,7 +988,7 @@ void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, con
void RenderingManager::frameStarted(float dt, bool paused) void RenderingManager::frameStarted(float dt, bool paused)
{ {
if (mTerrain && mTerrain->getVisible()) if (mTerrain)
mTerrain->update(mRendering.getCamera()->getRealPosition()); mTerrain->update(mRendering.getCamera()->getRealPosition());
if (!paused) if (!paused)

View file

@ -151,8 +151,15 @@ QuadTreeNode::QuadTreeNode(Terrain* terrain, ChildDirection dir, float size, con
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
mNeighbours[i] = NULL; mNeighbours[i] = NULL;
mSceneNode = mTerrain->getSceneManager()->getRootSceneNode()->createChildSceneNode( if (mDirection == Root)
Ogre::Vector3(mCenter.x*8192, mCenter.y*8192, 0)); mSceneNode = mTerrain->getRootSceneNode();
else
mSceneNode = mTerrain->getSceneManager()->createSceneNode();
Ogre::Vector2 pos (0,0);
if (mParent)
pos = mParent->getCenter();
pos = mCenter - pos;
mSceneNode->setPosition(Ogre::Vector3(pos.x*8192, pos.y*8192, 0));
mLodLevel = log2(mSize); mLodLevel = log2(mSize);
@ -221,13 +228,12 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
float dist = distance(mWorldBounds, cameraPos); float dist = distance(mWorldBounds, cameraPos);
if (!mTerrain->getDistantLandEnabled()) bool distantLand = mTerrain->getDistantLandEnabled();
// Make sure our scene node is attached
if (!mSceneNode->isInSceneGraph())
{ {
if (dist > 8192*2) mParent->getSceneNode()->addChild(mSceneNode);
{
destroyChunks();
return;
}
} }
/// \todo implement error metrics or some other means of not using arbitrary values /// \todo implement error metrics or some other means of not using arbitrary values
@ -246,9 +252,22 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
if (dist > 8192*64) if (dist > 8192*64)
wantedLod = 6; wantedLod = 6;
bool hadChunk = hasChunk();
if (!distantLand && dist > 8192*2)
{
if (mIsActive)
{
destroyChunks(true);
mIsActive = false;
}
return;
}
mIsActive = true;
if (mSize <= mTerrain->getMaxBatchSize() && mLodLevel <= wantedLod) if (mSize <= mTerrain->getMaxBatchSize() && mLodLevel <= wantedLod)
{ {
bool hadChunk = hasChunk();
// Wanted LOD is small enough to render this node in one chunk // Wanted LOD is small enough to render this node in one chunk
if (!mChunk) if (!mChunk)
{ {
@ -297,32 +316,36 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
if (!hadChunk && hasChildren()) if (!hadChunk && hasChildren())
{ {
for (int i=0; i<4; ++i) // Make sure child scene nodes are detached
mChildren[i]->hideChunks(); mSceneNode->removeAllChildren();
// If distant land is enabled, keep the chunks around in case we need them again,
// otherwise, prefer low memory usage
if (!distantLand)
for (int i=0; i<4; ++i)
mChildren[i]->destroyChunks(true);
} }
} }
else else
{ {
// Wanted LOD is too detailed to be rendered in one chunk, // Wanted LOD is too detailed to be rendered in one chunk,
// so split it up by delegating to child nodes // so split it up by delegating to child nodes
if (mChunk) if (hadChunk)
mChunk->setVisible(false); {
// If distant land is enabled, keep the chunks around in case we need them again,
// otherwise, prefer low memory usage
if (!distantLand)
destroyChunks(false);
else if (mChunk)
mChunk->setVisible(false);
}
assert(hasChildren() && "Leaf node's LOD needs to be 0"); assert(hasChildren() && "Leaf node's LOD needs to be 0");
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
mChildren[i]->update(cameraPos); mChildren[i]->update(cameraPos);
} }
} }
void QuadTreeNode::hideChunks() void QuadTreeNode::destroyChunks(bool children)
{
if (mChunk)
mChunk->setVisible(false);
else if (hasChildren())
for (int i=0; i<4; ++i)
mChildren[i]->hideChunks();
}
void QuadTreeNode::destroyChunks()
{ {
if (mChunk) if (mChunk)
{ {
@ -348,9 +371,9 @@ void QuadTreeNode::destroyChunks()
mCompositeMap.setNull(); mCompositeMap.setNull();
} }
} }
else if (hasChildren()) else if (children && hasChildren())
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
mChildren[i]->destroyChunks(); mChildren[i]->destroyChunks(true);
} }
void QuadTreeNode::updateIndexBuffers() void QuadTreeNode::updateIndexBuffers()
@ -366,7 +389,7 @@ void QuadTreeNode::updateIndexBuffers()
bool QuadTreeNode::hasChunk() bool QuadTreeNode::hasChunk()
{ {
return mChunk && mChunk->getVisible(); return mSceneNode->isInSceneGraph() && mChunk && mChunk->getVisible();
} }
size_t QuadTreeNode::getActualLodLevel() size_t QuadTreeNode::getActualLodLevel()

View file

@ -72,6 +72,8 @@ namespace Terrain
QuadTreeNode* getParent() { return mParent; } QuadTreeNode* getParent() { return mParent; }
Ogre::SceneNode* getSceneNode() { return mSceneNode; }
int getSize() { return mSize; } int getSize() { return mSize; }
Ogre::Vector2 getCenter() { return mCenter; } Ogre::Vector2 getCenter() { return mCenter; }
@ -100,11 +102,8 @@ namespace Terrain
/// Call after QuadTreeNode::update! /// Call after QuadTreeNode::update!
void updateIndexBuffers(); void updateIndexBuffers();
/// Hide chunks rendered by this node and all its children /// Destroy chunks rendered by this node *and* its children (if param is true)
void hideChunks(); void destroyChunks(bool children);
/// Destroy chunks rendered by this node and all its children
void destroyChunks();
/// Get the effective LOD level if this node was rendered in one chunk /// Get the effective LOD level if this node was rendered in one chunk
/// with ESM::Land::LAND_SIZE^2 vertices /// with ESM::Land::LAND_SIZE^2 vertices
@ -127,6 +126,10 @@ namespace Terrain
// Stored here for convenience in case we need layer list again // Stored here for convenience in case we need layer list again
MaterialGenerator* mMaterialGenerator; MaterialGenerator* mMaterialGenerator;
/// Is this node (or any of its child nodes) currently configured to render itself?
/// (only relevant when distant land is disabled, otherwise whole terrain is always rendered)
bool mIsActive;
bool mIsDummy; bool mIsDummy;
float mSize; float mSize;
size_t mLodLevel; // LOD if we were to render this node in one chunk size_t mLodLevel; // LOD if we were to render this node in one chunk

View file

@ -59,6 +59,7 @@ namespace Terrain
, mVisibilityFlags(visibilityFlags) , mVisibilityFlags(visibilityFlags)
, mDistantLand(distantLand) , mDistantLand(distantLand)
, mShaders(shaders) , mShaders(shaders)
, mVisible(true)
{ {
mCompositeMapSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); mCompositeMapSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
@ -81,6 +82,8 @@ namespace Terrain
// Adjust the center according to the new size // Adjust the center according to the new size
Ogre::Vector3 center = mBounds.getCenter() + Ogre::Vector3((size-origSizeX)/2.f, (size-origSizeY)/2.f, 0); Ogre::Vector3 center = mBounds.getCenter() + Ogre::Vector3((size-origSizeX)/2.f, (size-origSizeY)/2.f, 0);
mRootSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
mRootNode = new QuadTreeNode(this, Root, size, Ogre::Vector2(center.x, center.y), NULL); mRootNode = new QuadTreeNode(this, Root, size, Ogre::Vector2(center.x, center.y), NULL);
buildQuadTree(mRootNode); buildQuadTree(mRootNode);
mRootNode->initAabb(); mRootNode->initAabb();
@ -142,6 +145,8 @@ namespace Terrain
void Terrain::update(const Ogre::Vector3& cameraPos) void Terrain::update(const Ogre::Vector3& cameraPos)
{ {
if (!mVisible)
return;
mRootNode->update(cameraPos); mRootNode->update(cameraPos);
mRootNode->updateIndexBuffers(); mRootNode->updateIndexBuffers();
} }
@ -379,8 +384,12 @@ namespace Terrain
void Terrain::setVisible(bool visible) void Terrain::setVisible(bool visible)
{ {
if (visible && !mVisible)
mSceneMgr->getRootSceneNode()->addChild(mRootSceneNode);
else if (!visible && mVisible)
mSceneMgr->getRootSceneNode()->removeChild(mRootSceneNode);
mVisible = visible; mVisible = visible;
mRootNode->setVisible(visible);
} }
bool Terrain::getVisible() bool Terrain::getVisible()

View file

@ -55,6 +55,8 @@ namespace Terrain
Ogre::SceneManager* getSceneManager() { return mSceneMgr; } Ogre::SceneManager* getSceneManager() { return mSceneMgr; }
Ogre::SceneNode* getRootSceneNode() { return mRootSceneNode; }
Storage* getStorage() { return mStorage; } Storage* getStorage() { return mStorage; }
/// Show or hide the whole terrain /// Show or hide the whole terrain
@ -83,6 +85,7 @@ namespace Terrain
bool mVisible; bool mVisible;
QuadTreeNode* mRootNode; QuadTreeNode* mRootNode;
Ogre::SceneNode* mRootSceneNode;
Storage* mStorage; Storage* mStorage;
int mVisibilityFlags; int mVisibilityFlags;