mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 09:45:36 +00:00
Use a proper node hierarchy; disconnect the root when entering interior
This commit is contained in:
parent
3bf3bd4b8c
commit
ce5ea6d7d2
5 changed files with 71 additions and 33 deletions
|
@ -988,7 +988,7 @@ void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, con
|
|||
|
||||
void RenderingManager::frameStarted(float dt, bool paused)
|
||||
{
|
||||
if (mTerrain && mTerrain->getVisible())
|
||||
if (mTerrain)
|
||||
mTerrain->update(mRendering.getCamera()->getRealPosition());
|
||||
|
||||
if (!paused)
|
||||
|
|
|
@ -151,8 +151,15 @@ QuadTreeNode::QuadTreeNode(Terrain* terrain, ChildDirection dir, float size, con
|
|||
for (int i=0; i<4; ++i)
|
||||
mNeighbours[i] = NULL;
|
||||
|
||||
mSceneNode = mTerrain->getSceneManager()->getRootSceneNode()->createChildSceneNode(
|
||||
Ogre::Vector3(mCenter.x*8192, mCenter.y*8192, 0));
|
||||
if (mDirection == Root)
|
||||
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);
|
||||
|
||||
|
@ -221,13 +228,12 @@ void QuadTreeNode::update(const Ogre::Vector3 &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)
|
||||
{
|
||||
destroyChunks();
|
||||
return;
|
||||
}
|
||||
mParent->getSceneNode()->addChild(mSceneNode);
|
||||
}
|
||||
|
||||
/// \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)
|
||||
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)
|
||||
{
|
||||
bool hadChunk = hasChunk();
|
||||
// Wanted LOD is small enough to render this node in one chunk
|
||||
if (!mChunk)
|
||||
{
|
||||
|
@ -297,32 +316,36 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
|
|||
|
||||
if (!hadChunk && hasChildren())
|
||||
{
|
||||
for (int i=0; i<4; ++i)
|
||||
mChildren[i]->hideChunks();
|
||||
// Make sure child scene nodes are detached
|
||||
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
|
||||
{
|
||||
// Wanted LOD is too detailed to be rendered in one chunk,
|
||||
// so split it up by delegating to child nodes
|
||||
if (mChunk)
|
||||
mChunk->setVisible(false);
|
||||
if (hadChunk)
|
||||
{
|
||||
// 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");
|
||||
for (int i=0; i<4; ++i)
|
||||
mChildren[i]->update(cameraPos);
|
||||
}
|
||||
}
|
||||
|
||||
void QuadTreeNode::hideChunks()
|
||||
{
|
||||
if (mChunk)
|
||||
mChunk->setVisible(false);
|
||||
else if (hasChildren())
|
||||
for (int i=0; i<4; ++i)
|
||||
mChildren[i]->hideChunks();
|
||||
}
|
||||
|
||||
void QuadTreeNode::destroyChunks()
|
||||
void QuadTreeNode::destroyChunks(bool children)
|
||||
{
|
||||
if (mChunk)
|
||||
{
|
||||
|
@ -348,9 +371,9 @@ void QuadTreeNode::destroyChunks()
|
|||
mCompositeMap.setNull();
|
||||
}
|
||||
}
|
||||
else if (hasChildren())
|
||||
else if (children && hasChildren())
|
||||
for (int i=0; i<4; ++i)
|
||||
mChildren[i]->destroyChunks();
|
||||
mChildren[i]->destroyChunks(true);
|
||||
}
|
||||
|
||||
void QuadTreeNode::updateIndexBuffers()
|
||||
|
@ -366,7 +389,7 @@ void QuadTreeNode::updateIndexBuffers()
|
|||
|
||||
bool QuadTreeNode::hasChunk()
|
||||
{
|
||||
return mChunk && mChunk->getVisible();
|
||||
return mSceneNode->isInSceneGraph() && mChunk && mChunk->getVisible();
|
||||
}
|
||||
|
||||
size_t QuadTreeNode::getActualLodLevel()
|
||||
|
|
|
@ -72,6 +72,8 @@ namespace Terrain
|
|||
|
||||
QuadTreeNode* getParent() { return mParent; }
|
||||
|
||||
Ogre::SceneNode* getSceneNode() { return mSceneNode; }
|
||||
|
||||
int getSize() { return mSize; }
|
||||
Ogre::Vector2 getCenter() { return mCenter; }
|
||||
|
||||
|
@ -100,11 +102,8 @@ namespace Terrain
|
|||
/// Call after QuadTreeNode::update!
|
||||
void updateIndexBuffers();
|
||||
|
||||
/// Hide chunks rendered by this node and all its children
|
||||
void hideChunks();
|
||||
|
||||
/// Destroy chunks rendered by this node and all its children
|
||||
void destroyChunks();
|
||||
/// Destroy chunks rendered by this node *and* its children (if param is true)
|
||||
void destroyChunks(bool children);
|
||||
|
||||
/// Get the effective LOD level if this node was rendered in one chunk
|
||||
/// with ESM::Land::LAND_SIZE^2 vertices
|
||||
|
@ -127,6 +126,10 @@ namespace Terrain
|
|||
// Stored here for convenience in case we need layer list again
|
||||
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;
|
||||
float mSize;
|
||||
size_t mLodLevel; // LOD if we were to render this node in one chunk
|
||||
|
|
|
@ -59,6 +59,7 @@ namespace Terrain
|
|||
, mVisibilityFlags(visibilityFlags)
|
||||
, mDistantLand(distantLand)
|
||||
, mShaders(shaders)
|
||||
, mVisible(true)
|
||||
{
|
||||
mCompositeMapSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
|
||||
|
||||
|
@ -81,6 +82,8 @@ namespace Terrain
|
|||
// Adjust the center according to the new size
|
||||
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);
|
||||
buildQuadTree(mRootNode);
|
||||
mRootNode->initAabb();
|
||||
|
@ -142,6 +145,8 @@ namespace Terrain
|
|||
|
||||
void Terrain::update(const Ogre::Vector3& cameraPos)
|
||||
{
|
||||
if (!mVisible)
|
||||
return;
|
||||
mRootNode->update(cameraPos);
|
||||
mRootNode->updateIndexBuffers();
|
||||
}
|
||||
|
@ -379,8 +384,12 @@ namespace Terrain
|
|||
|
||||
void Terrain::setVisible(bool visible)
|
||||
{
|
||||
if (visible && !mVisible)
|
||||
mSceneMgr->getRootSceneNode()->addChild(mRootSceneNode);
|
||||
else if (!visible && mVisible)
|
||||
mSceneMgr->getRootSceneNode()->removeChild(mRootSceneNode);
|
||||
|
||||
mVisible = visible;
|
||||
mRootNode->setVisible(visible);
|
||||
}
|
||||
|
||||
bool Terrain::getVisible()
|
||||
|
|
|
@ -55,6 +55,8 @@ namespace Terrain
|
|||
|
||||
Ogre::SceneManager* getSceneManager() { return mSceneMgr; }
|
||||
|
||||
Ogre::SceneNode* getRootSceneNode() { return mRootSceneNode; }
|
||||
|
||||
Storage* getStorage() { return mStorage; }
|
||||
|
||||
/// Show or hide the whole terrain
|
||||
|
@ -83,6 +85,7 @@ namespace Terrain
|
|||
bool mVisible;
|
||||
|
||||
QuadTreeNode* mRootNode;
|
||||
Ogre::SceneNode* mRootSceneNode;
|
||||
Storage* mStorage;
|
||||
|
||||
int mVisibilityFlags;
|
||||
|
|
Loading…
Reference in a new issue