mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 17:39:42 +00:00
Merge pull request #2201 from akortunov/optimize_terrain
Optimize terrain
This commit is contained in:
commit
d56733149c
13 changed files with 139 additions and 55 deletions
|
@ -58,6 +58,7 @@
|
||||||
Feature #4887: Add openmw command option to set initial random seed
|
Feature #4887: Add openmw command option to set initial random seed
|
||||||
Feature #4890: Make Distant Terrain configurable
|
Feature #4890: Make Distant Terrain configurable
|
||||||
Task #4686: Upgrade media decoder to a more current FFmpeg API
|
Task #4686: Upgrade media decoder to a more current FFmpeg API
|
||||||
|
Task #4695: Optimize Distant Terrain memory consumption
|
||||||
|
|
||||||
0.45.0
|
0.45.0
|
||||||
------
|
------
|
||||||
|
|
|
@ -371,8 +371,10 @@ namespace MWRender
|
||||||
|
|
||||||
mNearClip = Settings::Manager::getFloat("near clip", "Camera");
|
mNearClip = Settings::Manager::getFloat("near clip", "Camera");
|
||||||
mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
|
mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||||
mFieldOfView = Settings::Manager::getFloat("field of view", "Camera");
|
float fov = Settings::Manager::getFloat("field of view", "Camera");
|
||||||
mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera");
|
mFieldOfView = std::min(std::max(1.f, fov), 179.f);
|
||||||
|
float firstPersonFov = Settings::Manager::getFloat("first person field of view", "Camera");
|
||||||
|
mFirstPersonFieldOfView = std::min(std::max(1.f, firstPersonFov), 179.f);
|
||||||
mStateUpdater->setFogEnd(mViewDistance);
|
mStateUpdater->setFogEnd(mViewDistance);
|
||||||
|
|
||||||
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip));
|
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip));
|
||||||
|
@ -1198,6 +1200,12 @@ namespace MWRender
|
||||||
|
|
||||||
mUniformNear->set(mNearClip);
|
mUniformNear->set(mNearClip);
|
||||||
mUniformFar->set(mViewDistance);
|
mUniformFar->set(mViewDistance);
|
||||||
|
|
||||||
|
// Since our fog is not radial yet, we should take FOV in account, otherwise terrain near viewing distance may disappear.
|
||||||
|
// Limit FOV here just for sure, otherwise viewing distance can be too high.
|
||||||
|
fov = std::min(mFieldOfView, 140.f);
|
||||||
|
float distanceMult = std::cos(osg::DegreesToRadians(fov)/2.f);
|
||||||
|
mTerrain->setViewDistance(mViewDistance * (distanceMult ? 1.f/distanceMult : 1.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::updateTextureFiltering()
|
void RenderingManager::updateTextureFiltering()
|
||||||
|
|
|
@ -22,6 +22,15 @@ namespace MWRender
|
||||||
mResourceSystem->removeResourceManager(mLandManager.get());
|
mResourceSystem->removeResourceManager(mLandManager.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TerrainStorage::hasData(int cellX, int cellY)
|
||||||
|
{
|
||||||
|
const MWWorld::ESMStore &esmStore =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
|
const ESM::Land* land = esmStore.get<ESM::Land>().search(cellX, cellY);
|
||||||
|
return land != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void TerrainStorage::getBounds(float& minX, float& maxX, float& minY, float& maxY)
|
void TerrainStorage::getBounds(float& minX, float& maxX, float& minY, float& maxY)
|
||||||
{
|
{
|
||||||
minX = 0, minY = 0, maxX = 0, maxY = 0;
|
minX = 0, minY = 0, maxX = 0, maxY = 0;
|
||||||
|
|
|
@ -23,6 +23,8 @@ namespace MWRender
|
||||||
virtual osg::ref_ptr<const ESMTerrain::LandObject> getLand (int cellX, int cellY);
|
virtual osg::ref_ptr<const ESMTerrain::LandObject> getLand (int cellX, int cellY);
|
||||||
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
|
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
|
||||||
|
|
||||||
|
virtual bool hasData(int cellX, int cellY) override;
|
||||||
|
|
||||||
/// Get bounds of the whole terrain in cell units
|
/// Get bounds of the whole terrain in cell units
|
||||||
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);
|
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,7 @@ osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Ve
|
||||||
geometry->setUseDisplayList(false);
|
geometry->setUseDisplayList(false);
|
||||||
geometry->setUseVertexBufferObjects(true);
|
geometry->setUseVertexBufferObjects(true);
|
||||||
|
|
||||||
if (chunkSize <= 2.f)
|
if (chunkSize <= 1.f)
|
||||||
geometry->setLightListCallback(new SceneUtil::LightListCallback);
|
geometry->setLightListCallback(new SceneUtil::LightListCallback);
|
||||||
|
|
||||||
unsigned int numVerts = (mStorage->getCellVertices()-1) * chunkSize / (1 << lod) + 1;
|
unsigned int numVerts = (mStorage->getCellVertices()-1) * chunkSize / (1 << lod) + 1;
|
||||||
|
|
|
@ -76,6 +76,30 @@ QuadTreeNode *QuadTreeNode::getNeighbour(Direction dir)
|
||||||
return mNeighbours[dir];
|
return mNeighbours[dir];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float QuadTreeNode::distance(const osg::Vec3f& v) const
|
||||||
|
{
|
||||||
|
const osg::BoundingBox& box = getBoundingBox();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QuadTreeNode::initNeighbours()
|
void QuadTreeNode::initNeighbours()
|
||||||
{
|
{
|
||||||
for (int i=0; i<4; ++i)
|
for (int i=0; i<4; ++i)
|
||||||
|
@ -92,7 +116,7 @@ void QuadTreeNode::traverse(osg::NodeVisitor &nv)
|
||||||
|
|
||||||
ViewData* vd = getView(nv);
|
ViewData* vd = getView(nv);
|
||||||
|
|
||||||
if ((mLodCallback && mLodCallback->isSufficientDetail(this, vd->getEyePoint())) || !getNumChildren())
|
if ((mLodCallback && mLodCallback->isSufficientDetail(this, distance(vd->getEyePoint()))) || !getNumChildren())
|
||||||
vd->add(this, true);
|
vd->add(this, true);
|
||||||
else
|
else
|
||||||
osg::Group::traverse(nv);
|
osg::Group::traverse(nv);
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Terrain
|
||||||
public:
|
public:
|
||||||
virtual ~LodCallback() {}
|
virtual ~LodCallback() {}
|
||||||
|
|
||||||
virtual bool isSufficientDetail(QuadTreeNode *node, const osg::Vec3f& eyePoint) = 0;
|
virtual bool isSufficientDetail(QuadTreeNode *node, float dist) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ViewDataMap;
|
class ViewDataMap;
|
||||||
|
@ -49,6 +49,8 @@ namespace Terrain
|
||||||
child->addParent(this);
|
child->addParent(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
float distance(const osg::Vec3f& v) const;
|
||||||
|
|
||||||
/// Returns our direction relative to the parent node, or Root if we are the root node.
|
/// Returns our direction relative to the parent node, or Root if we are the root node.
|
||||||
ChildDirection getDirection() { return mDirection; }
|
ChildDirection getDirection() { return mDirection; }
|
||||||
|
|
||||||
|
|
|
@ -40,33 +40,6 @@ namespace
|
||||||
return targetlevel;
|
return targetlevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
float distanceToBox(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
|
||||||
|
@ -81,9 +54,8 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool isSufficientDetail(QuadTreeNode* node, const osg::Vec3f& eyePoint)
|
virtual bool isSufficientDetail(QuadTreeNode* node, float dist)
|
||||||
{
|
{
|
||||||
float dist = distanceToBox(node->getBoundingBox(), eyePoint);
|
|
||||||
int nativeLodLevel = Log2(static_cast<unsigned int>(node->getSize()/mMinSize));
|
int nativeLodLevel = Log2(static_cast<unsigned int>(node->getSize()/mMinSize));
|
||||||
int lodLevel = Log2(static_cast<unsigned int>(dist/(Constants::CellSizeInUnits*mMinSize*mFactor)));
|
int lodLevel = Log2(static_cast<unsigned int>(dist/(Constants::CellSizeInUnits*mMinSize*mFactor)));
|
||||||
|
|
||||||
|
@ -201,22 +173,40 @@ public:
|
||||||
node->setLodCallback(parent->getLodCallback());
|
node->setLodCallback(parent->getLodCallback());
|
||||||
node->setViewDataMap(mViewDataMap);
|
node->setViewDataMap(mViewDataMap);
|
||||||
|
|
||||||
if (node->getSize() > mMinSize)
|
if (center.x() - halfSize > mMaxX
|
||||||
|
|| center.x() + halfSize < mMinX
|
||||||
|
|| center.y() - halfSize > mMaxY
|
||||||
|
|| center.y() + halfSize < mMinY )
|
||||||
|
// Out of bounds of the actual terrain - this will happen because
|
||||||
|
// we rounded the size up to the next power of two
|
||||||
|
{
|
||||||
|
// Still create and return an empty node so as to not break the assumption that each QuadTreeNode has either 4 or 0 children.
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not add child nodes for default cells without data.
|
||||||
|
// size = 1 means that the single shape covers the whole cell.
|
||||||
|
if (node->getSize() == 1 && !mStorage->hasData(center.x()-0.5, center.y()-0.5))
|
||||||
|
return node;
|
||||||
|
|
||||||
|
if (node->getSize() <= mMinSize)
|
||||||
|
{
|
||||||
|
// We arrived at a leaf
|
||||||
|
float minZ,maxZ;
|
||||||
|
if (mStorage->getMinMaxHeights(size, center, minZ, maxZ))
|
||||||
|
{
|
||||||
|
float cellWorldSize = mStorage->getCellWorldSize();
|
||||||
|
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));
|
||||||
|
node->setBoundingBox(boundingBox);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
addChildren(node);
|
addChildren(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We arrived at a leaf
|
|
||||||
float minZ, maxZ;
|
|
||||||
mStorage->getMinMaxHeights(size, center, minZ, maxZ);
|
|
||||||
|
|
||||||
float cellWorldSize = mStorage->getCellWorldSize();
|
|
||||||
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));
|
|
||||||
node->setBoundingBox(boundingBox);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<RootNode> getRootNode()
|
osg::ref_ptr<RootNode> getRootNode()
|
||||||
|
@ -236,11 +226,12 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
||||||
: World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask)
|
: TerrainGrid(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask)
|
||||||
, mViewDataMap(new ViewDataMap)
|
, mViewDataMap(new ViewDataMap)
|
||||||
, mQuadTreeBuilt(false)
|
, mQuadTreeBuilt(false)
|
||||||
, mLodFactor(lodFactor)
|
, mLodFactor(lodFactor)
|
||||||
, mVertexLodMod(vertexLodMod)
|
, mVertexLodMod(vertexLodMod)
|
||||||
|
, mViewDistance(std::numeric_limits<float>::max())
|
||||||
{
|
{
|
||||||
// No need for culling on the Drawable / Transform level as the quad tree performs the culling already.
|
// No need for culling on the Drawable / Transform level as the quad tree performs the culling already.
|
||||||
mChunkManager->setCullingActive(false);
|
mChunkManager->setCullingActive(false);
|
||||||
|
@ -256,7 +247,7 @@ QuadTreeWorld::~QuadTreeWorld()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallback* lodCallback, const osg::Vec3f& eyePoint, bool visible)
|
void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallback* lodCallback, const osg::Vec3f& eyePoint, bool visible, float maxDist)
|
||||||
{
|
{
|
||||||
if (!node->hasValidBounds())
|
if (!node->hasValidBounds())
|
||||||
return;
|
return;
|
||||||
|
@ -264,14 +255,18 @@ void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallbac
|
||||||
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
||||||
visible = visible && !static_cast<osgUtil::CullVisitor*>(nv)->isCulled(node->getBoundingBox());
|
visible = visible && !static_cast<osgUtil::CullVisitor*>(nv)->isCulled(node->getBoundingBox());
|
||||||
|
|
||||||
bool stopTraversal = (lodCallback && lodCallback->isSufficientDetail(node, eyePoint)) || !node->getNumChildren();
|
float dist = node->distance(eyePoint);
|
||||||
|
if (dist > maxDist)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool stopTraversal = (lodCallback && lodCallback->isSufficientDetail(node, dist)) || !node->getNumChildren();
|
||||||
|
|
||||||
if (stopTraversal)
|
if (stopTraversal)
|
||||||
vd->add(node, visible);
|
vd->add(node, visible);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (unsigned int i=0; i<node->getNumChildren(); ++i)
|
for (unsigned int i=0; i<node->getNumChildren(); ++i)
|
||||||
traverse(node->getChild(i), vd, nv, lodCallback, eyePoint, visible);
|
traverse(node->getChild(i), vd, nv, lodCallback, eyePoint, visible, maxDist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,7 +398,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
|
||||||
traverseToCell(mRootNode.get(), vd, x,y);
|
traverseToCell(mRootNode.get(), vd, x,y);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getViewPoint(), true);
|
traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getViewPoint(), true, mViewDistance);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mRootNode->traverse(nv);
|
mRootNode->traverse(nv);
|
||||||
|
@ -483,7 +478,7 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint, std::atomic<
|
||||||
ensureQuadTreeBuilt();
|
ensureQuadTreeBuilt();
|
||||||
|
|
||||||
ViewData* vd = static_cast<ViewData*>(view);
|
ViewData* vd = static_cast<ViewData*>(view);
|
||||||
traverse(mRootNode.get(), vd, nullptr, mRootNode->getLodCallback(), eyePoint, false);
|
traverse(mRootNode.get(), vd, nullptr, mRootNode->getLodCallback(), eyePoint, false, mViewDistance);
|
||||||
|
|
||||||
for (unsigned int i=0; i<vd->getNumEntries() && !abort; ++i)
|
for (unsigned int i=0; i<vd->getNumEntries() && !abort; ++i)
|
||||||
{
|
{
|
||||||
|
@ -502,5 +497,25 @@ void QuadTreeWorld::setDefaultViewer(osg::Object *obj)
|
||||||
mViewDataMap->setDefaultViewer(obj);
|
mViewDataMap->setDefaultViewer(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QuadTreeWorld::loadCell(int x, int y)
|
||||||
|
{
|
||||||
|
// fallback behavior only for undefined cells (every other is already handled in quadtree)
|
||||||
|
float dummy;
|
||||||
|
if (!mStorage->getMinMaxHeights(1, osg::Vec2f(x+0.5, y+0.5), dummy, dummy))
|
||||||
|
TerrainGrid::loadCell(x,y);
|
||||||
|
else
|
||||||
|
World::loadCell(x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuadTreeWorld::unloadCell(int x, int y)
|
||||||
|
{
|
||||||
|
// fallback behavior only for undefined cells (every other is already handled in quadtree)
|
||||||
|
float dummy;
|
||||||
|
if (!mStorage->getMinMaxHeights(1, osg::Vec2f(x+0.5, y+0.5), dummy, dummy))
|
||||||
|
TerrainGrid::unloadCell(x,y);
|
||||||
|
else
|
||||||
|
World::unloadCell(x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define COMPONENTS_TERRAIN_QUADTREEWORLD_H
|
#define COMPONENTS_TERRAIN_QUADTREEWORLD_H
|
||||||
|
|
||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
|
#include "terraingrid.hpp"
|
||||||
|
|
||||||
#include <OpenThreads/Mutex>
|
#include <OpenThreads/Mutex>
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ namespace Terrain
|
||||||
class ViewDataMap;
|
class ViewDataMap;
|
||||||
|
|
||||||
/// @brief Terrain implementation that loads cells into a Quad Tree, with geometry LOD and texture LOD. The entire world is displayed at all times.
|
/// @brief Terrain implementation that loads cells into a Quad Tree, with geometry LOD and texture LOD. The entire world is displayed at all times.
|
||||||
class QuadTreeWorld : public Terrain::World
|
class QuadTreeWorld : public TerrainGrid // note: derived from TerrainGrid is only to render default cells (see loadCell)
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize);
|
QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize);
|
||||||
|
@ -27,7 +28,13 @@ namespace Terrain
|
||||||
|
|
||||||
virtual void enable(bool enabled);
|
virtual void enable(bool enabled);
|
||||||
|
|
||||||
|
virtual void setViewDistance(float distance) { mViewDistance = distance; }
|
||||||
|
|
||||||
void cacheCell(View *view, int x, int y);
|
void cacheCell(View *view, int x, int y);
|
||||||
|
/// @note Not thread safe.
|
||||||
|
virtual void loadCell(int x, int y);
|
||||||
|
/// @note Not thread safe.
|
||||||
|
virtual void unloadCell(int x, int y);
|
||||||
|
|
||||||
View* createView();
|
View* createView();
|
||||||
void preload(View* view, const osg::Vec3f& eyePoint, std::atomic<bool>& abort);
|
void preload(View* view, const osg::Vec3f& eyePoint, std::atomic<bool>& abort);
|
||||||
|
@ -47,6 +54,7 @@ namespace Terrain
|
||||||
bool mQuadTreeBuilt;
|
bool mQuadTreeBuilt;
|
||||||
float mLodFactor;
|
float mLodFactor;
|
||||||
int mVertexLodMod;
|
int mVertexLodMod;
|
||||||
|
float mViewDistance;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,14 @@ namespace Terrain
|
||||||
/// Get bounds of the whole terrain in cell units
|
/// Get bounds of the whole terrain in cell units
|
||||||
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0;
|
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0;
|
||||||
|
|
||||||
|
/// Return true if there is land data for this cell
|
||||||
|
/// May be overriden for a faster implementation
|
||||||
|
virtual bool hasData(int cellX, int cellY)
|
||||||
|
{
|
||||||
|
float dummy;
|
||||||
|
return getMinMaxHeights(1, osg::Vec2f(cellX+0.5, cellY+0.5), dummy, dummy);
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the minimum and maximum heights of a terrain region.
|
/// Get the minimum and maximum heights of a terrain region.
|
||||||
/// @note Will only be called for chunks with size = minBatchSize, i.e. leafs of the quad tree.
|
/// @note Will only be called for chunks with size = minBatchSize, i.e. leafs of the quad tree.
|
||||||
/// Larger chunks can simply merge AABB of children.
|
/// Larger chunks can simply merge AABB of children.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
|
|
||||||
#include "chunkmanager.hpp"
|
#include "chunkmanager.hpp"
|
||||||
|
#include "compositemaprenderer.hpp"
|
||||||
|
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
@ -61,6 +62,10 @@ osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chu
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,8 @@ namespace Terrain
|
||||||
/// Set the default viewer (usually a Camera), used as viewpoint for any viewers that don't use their own viewpoint.
|
/// Set the default viewer (usually a Camera), used as viewpoint for any viewers that don't use their own viewpoint.
|
||||||
virtual void setDefaultViewer(osg::Object* obj) {}
|
virtual void setDefaultViewer(osg::Object* obj) {}
|
||||||
|
|
||||||
|
virtual void setViewDistance(float distance) {}
|
||||||
|
|
||||||
Storage* getStorage() { return mStorage; }
|
Storage* getStorage() { return mStorage; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -94,7 +94,7 @@ field of view
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
:Type: floating point
|
:Type: floating point
|
||||||
:Range: 0-360
|
:Range: 1-179
|
||||||
:Default: 55.0
|
:Default: 55.0
|
||||||
|
|
||||||
Sets the camera field of view in degrees. Recommended values range from 30 degrees to 110 degrees.
|
Sets the camera field of view in degrees. Recommended values range from 30 degrees to 110 degrees.
|
||||||
|
@ -109,7 +109,7 @@ first person field of view
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
:Type: floating point
|
:Type: floating point
|
||||||
:Range: 0-360
|
:Range: 1-179
|
||||||
:Default: 55.0
|
:Default: 55.0
|
||||||
|
|
||||||
This setting controls the field of view for first person meshes such as the player's hands and held objects.
|
This setting controls the field of view for first person meshes such as the player's hands and held objects.
|
||||||
|
|
Loading…
Reference in a new issue