mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-03 21:49:41 +00:00
Merge pull request #2190 from akortunov/terrain
Make Distant Terrain configurable
This commit is contained in:
commit
cd70354f34
8 changed files with 186 additions and 35 deletions
|
@ -47,6 +47,7 @@
|
||||||
Feature #4812: Support NiSwitchNode
|
Feature #4812: Support NiSwitchNode
|
||||||
Feature #4836: Daytime node switch
|
Feature #4836: Daytime node switch
|
||||||
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
|
||||||
Task #4686: Upgrade media decoder to a more current FFmpeg API
|
Task #4686: Upgrade media decoder to a more current FFmpeg API
|
||||||
|
|
||||||
0.45.0
|
0.45.0
|
||||||
|
|
|
@ -283,12 +283,29 @@ namespace MWRender
|
||||||
|
|
||||||
mDistantFog = Settings::Manager::getBool("use distant fog", "Fog");
|
mDistantFog = Settings::Manager::getBool("use distant fog", "Fog");
|
||||||
mDistantTerrain = Settings::Manager::getBool("distant terrain", "Terrain");
|
mDistantTerrain = Settings::Manager::getBool("distant terrain", "Terrain");
|
||||||
mTerrainStorage = new TerrainStorage(mResourceSystem, Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getString("normal height map pattern", "Shaders"),
|
|
||||||
Settings::Manager::getBool("auto use terrain normal maps", "Shaders"), Settings::Manager::getString("terrain specular map pattern", "Shaders"),
|
const std::string normalMapPattern = Settings::Manager::getString("normal map pattern", "Shaders");
|
||||||
Settings::Manager::getBool("auto use terrain specular maps", "Shaders"));
|
const std::string heightMapPattern = Settings::Manager::getString("normal height map pattern", "Shaders");
|
||||||
|
const std::string specularMapPattern = Settings::Manager::getString("terrain specular map pattern", "Shaders");
|
||||||
|
const bool useTerrainNormalMaps = Settings::Manager::getBool("auto use terrain normal maps", "Shaders");
|
||||||
|
const bool useTerrainSpecularMaps = Settings::Manager::getBool("auto use terrain specular maps", "Shaders");
|
||||||
|
|
||||||
|
mTerrainStorage = new TerrainStorage(mResourceSystem, normalMapPattern, heightMapPattern, useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps);
|
||||||
|
|
||||||
if (mDistantTerrain)
|
if (mDistantTerrain)
|
||||||
mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug));
|
{
|
||||||
|
const int compMapResolution = Settings::Manager::getInt("composite map resolution", "Terrain");
|
||||||
|
int compMapPower = Settings::Manager::getInt("composite map level", "Terrain");
|
||||||
|
compMapPower = std::max(-3, compMapPower);
|
||||||
|
float compMapLevel = pow(2, compMapPower);
|
||||||
|
const float lodFactor = Settings::Manager::getFloat("lod factor", "Terrain");
|
||||||
|
const int vertexLodMod = Settings::Manager::getInt("vertex lod mod", "Terrain");
|
||||||
|
float maxCompGeometrySize = Settings::Manager::getFloat("max composite geometry size", "Terrain");
|
||||||
|
maxCompGeometrySize = std::max(maxCompGeometrySize, 1.f);
|
||||||
|
mTerrain.reset(new Terrain::QuadTreeWorld(
|
||||||
|
sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug,
|
||||||
|
compMapResolution, compMapLevel, lodFactor, vertexLodMod, maxCompGeometrySize));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug));
|
mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug));
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T
|
||||||
, mTextureManager(textureManager)
|
, mTextureManager(textureManager)
|
||||||
, mCompositeMapRenderer(renderer)
|
, mCompositeMapRenderer(renderer)
|
||||||
, mCompositeMapSize(512)
|
, mCompositeMapSize(512)
|
||||||
|
, mCompositeMapLevel(1.f)
|
||||||
|
, mMaxCompGeometrySize(1.f)
|
||||||
, mCullingActive(true)
|
, mCullingActive(true)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -68,11 +70,6 @@ void ChunkManager::releaseGLObjects(osg::State *state)
|
||||||
mBufferCache.releaseGLObjects(state);
|
mBufferCache.releaseGLObjects(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkManager::setCullingActive(bool active)
|
|
||||||
{
|
|
||||||
mCullingActive = active;
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> ChunkManager::createCompositeMapRTT()
|
osg::ref_ptr<osg::Texture2D> ChunkManager::createCompositeMapRTT()
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
|
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
|
||||||
|
@ -89,7 +86,7 @@ osg::ref_ptr<osg::Texture2D> ChunkManager::createCompositeMapRTT()
|
||||||
|
|
||||||
void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& compositeMap)
|
void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& compositeMap)
|
||||||
{
|
{
|
||||||
if (chunkSize > 1.f)
|
if (chunkSize > mMaxCompGeometrySize)
|
||||||
{
|
{
|
||||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap);
|
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap);
|
||||||
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap);
|
createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap);
|
||||||
|
@ -199,7 +196,7 @@ osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Ve
|
||||||
|
|
||||||
geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, lodFlags));
|
geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, lodFlags));
|
||||||
|
|
||||||
bool useCompositeMap = chunkSize >= 1.f;
|
bool useCompositeMap = chunkSize >= mCompositeMapLevel;
|
||||||
unsigned int numUvSets = useCompositeMap ? 1 : 2;
|
unsigned int numUvSets = useCompositeMap ? 1 : 2;
|
||||||
|
|
||||||
for (unsigned int i=0; i<numUvSets; ++i)
|
for (unsigned int i=0; i<numUvSets; ++i)
|
||||||
|
|
|
@ -32,14 +32,17 @@ namespace Terrain
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> getChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags);
|
osg::ref_ptr<osg::Node> getChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags);
|
||||||
|
|
||||||
|
void setCullingActive(bool active) { mCullingActive = active; }
|
||||||
|
void setCompositeMapSize(unsigned int size) { mCompositeMapSize = size; }
|
||||||
|
void setCompositeMapLevel(float level) { mCompositeMapLevel = level; }
|
||||||
|
void setMaxCompositeGeometrySize(float maxCompGeometrySize) { mMaxCompGeometrySize = maxCompGeometrySize; }
|
||||||
|
|
||||||
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
|
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
|
||||||
|
|
||||||
void clearCache() override;
|
void clearCache() override;
|
||||||
|
|
||||||
void releaseGLObjects(osg::State* state) override;
|
void releaseGLObjects(osg::State* state) override;
|
||||||
|
|
||||||
void setCullingActive(bool active);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags);
|
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags);
|
||||||
|
|
||||||
|
@ -56,6 +59,8 @@ namespace Terrain
|
||||||
BufferCache mBufferCache;
|
BufferCache mBufferCache;
|
||||||
|
|
||||||
unsigned int mCompositeMapSize;
|
unsigned int mCompositeMapSize;
|
||||||
|
float mCompositeMapLevel;
|
||||||
|
float mMaxCompGeometrySize;
|
||||||
|
|
||||||
bool mCullingActive;
|
bool mCullingActive;
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,8 +75,9 @@ namespace Terrain
|
||||||
class DefaultLodCallback : public LodCallback
|
class DefaultLodCallback : public LodCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DefaultLodCallback(float minSize)
|
DefaultLodCallback(float factor, float minSize)
|
||||||
: mMinSize(minSize)
|
: mFactor(factor)
|
||||||
|
, mMinSize(minSize)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,12 +85,13 @@ public:
|
||||||
{
|
{
|
||||||
float dist = distanceToBox(node->getBoundingBox(), eyePoint);
|
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)));
|
int lodLevel = Log2(static_cast<unsigned int>(dist/(Constants::CellSizeInUnits*mMinSize*mFactor)));
|
||||||
|
|
||||||
return nativeLodLevel <= lodLevel;
|
return nativeLodLevel <= lodLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
float mFactor;
|
||||||
float mMinSize;
|
float mMinSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -123,8 +125,9 @@ private:
|
||||||
class QuadTreeBuilder
|
class QuadTreeBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QuadTreeBuilder(Terrain::Storage* storage, ViewDataMap* viewDataMap, float minSize)
|
QuadTreeBuilder(Terrain::Storage* storage, ViewDataMap* viewDataMap, float lodFactor, 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)
|
, mViewDataMap(viewDataMap)
|
||||||
|
@ -146,7 +149,7 @@ public:
|
||||||
|
|
||||||
mRootNode = new RootNode(size, osg::Vec2f(centerX, centerY));
|
mRootNode = new RootNode(size, osg::Vec2f(centerX, centerY));
|
||||||
mRootNode->setViewDataMap(mViewDataMap);
|
mRootNode->setViewDataMap(mViewDataMap);
|
||||||
mRootNode->setLodCallback(new DefaultLodCallback(mMinSize));
|
mRootNode->setLodCallback(new DefaultLodCallback(mLodFactor, mMinSize));
|
||||||
addChildren(mRootNode);
|
addChildren(mRootNode);
|
||||||
|
|
||||||
mRootNode->initNeighbours();
|
mRootNode->initNeighbours();
|
||||||
|
@ -224,6 +227,7 @@ public:
|
||||||
private:
|
private:
|
||||||
Terrain::Storage* mStorage;
|
Terrain::Storage* mStorage;
|
||||||
|
|
||||||
|
float mLodFactor;
|
||||||
float mMinX, mMaxX, mMinY, mMaxY;
|
float mMinX, mMaxX, mMinY, mMaxY;
|
||||||
float mMinSize;
|
float mMinSize;
|
||||||
ViewDataMap* mViewDataMap;
|
ViewDataMap* mViewDataMap;
|
||||||
|
@ -231,13 +235,19 @@ private:
|
||||||
osg::ref_ptr<RootNode> mRootNode;
|
osg::ref_ptr<RootNode> mRootNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask)
|
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)
|
: World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask)
|
||||||
, mViewDataMap(new ViewDataMap)
|
, mViewDataMap(new ViewDataMap)
|
||||||
, mQuadTreeBuilt(false)
|
, mQuadTreeBuilt(false)
|
||||||
|
, mLodFactor(lodFactor)
|
||||||
|
, mVertexLodMod(vertexLodMod)
|
||||||
{
|
{
|
||||||
// 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);
|
||||||
|
|
||||||
|
mChunkManager->setCompositeMapSize(compMapResolution);
|
||||||
|
mChunkManager->setCompositeMapLevel(compMapLevel);
|
||||||
|
mChunkManager->setMaxCompositeGeometrySize(maxCompGeometrySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
QuadTreeWorld::~QuadTreeWorld()
|
QuadTreeWorld::~QuadTreeWorld()
|
||||||
|
@ -287,7 +297,30 @@ void traverseToCell(QuadTreeNode* node, ViewData* vd, int cellX, int cellY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd)
|
/// 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)
|
||||||
|
{
|
||||||
|
int lod = Log2(int(node->getSize()));
|
||||||
|
if (vertexLodMod > 0)
|
||||||
|
{
|
||||||
|
lod = std::max(0, lod-vertexLodMod);
|
||||||
|
}
|
||||||
|
else if (vertexLodMod < 0)
|
||||||
|
{
|
||||||
|
float size = node->getSize();
|
||||||
|
// Stop to simplify at this level since with size = 1 the node already covers the whole cell and has getCellVertices() vertices.
|
||||||
|
while (size < 1)
|
||||||
|
{
|
||||||
|
size *= 2;
|
||||||
|
vertexLodMod = std::min(0, vertexLodMod+1);
|
||||||
|
}
|
||||||
|
lod += std::abs(vertexLodMod);
|
||||||
|
}
|
||||||
|
return lod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get the flags to use for stitching in the index buffer so that chunks of different LOD connect seamlessly
|
||||||
|
unsigned int getLodFlags(QuadTreeNode* node, int ourLod, int vertexLodMod, ViewData* vd)
|
||||||
{
|
{
|
||||||
unsigned int lodFlags = 0;
|
unsigned int lodFlags = 0;
|
||||||
for (unsigned int i=0; i<4; ++i)
|
for (unsigned int i=0; i<4; ++i)
|
||||||
|
@ -302,7 +335,7 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd)
|
||||||
neighbour = neighbour->getParent();
|
neighbour = neighbour->getParent();
|
||||||
int lod = 0;
|
int lod = 0;
|
||||||
if (neighbour)
|
if (neighbour)
|
||||||
lod = Log2(int(neighbour->getSize()));
|
lod = getVertexLod(neighbour, vertexLodMod);
|
||||||
|
|
||||||
if (lod <= ourLod) // We only need to worry about neighbours less detailed than we are -
|
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
|
lod = 0; // neighbours with more detail will do the stitching themselves
|
||||||
|
@ -315,13 +348,17 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd)
|
||||||
return lodFlags;
|
return lodFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunkManager)
|
void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, ChunkManager* chunkManager)
|
||||||
{
|
{
|
||||||
|
if (!vd->hasChanged() && entry.mRenderingNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int ourLod = getVertexLod(entry.mNode, vertexLodMod);
|
||||||
|
|
||||||
if (vd->hasChanged())
|
if (vd->hasChanged())
|
||||||
{
|
{
|
||||||
// have to recompute the lodFlags in case a neighbour has changed LOD.
|
// have to recompute the lodFlags in case a neighbour has changed LOD.
|
||||||
int ourLod = Log2(int(entry.mNode->getSize()));
|
unsigned int lodFlags = getLodFlags(entry.mNode, ourLod, vertexLodMod, vd);
|
||||||
unsigned int lodFlags = getLodFlags(entry.mNode, ourLod, vd);
|
|
||||||
if (lodFlags != entry.mLodFlags)
|
if (lodFlags != entry.mLodFlags)
|
||||||
{
|
{
|
||||||
entry.mRenderingNode = nullptr;
|
entry.mRenderingNode = nullptr;
|
||||||
|
@ -330,10 +367,7 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entry.mRenderingNode)
|
if (!entry.mRenderingNode)
|
||||||
{
|
|
||||||
int ourLod = Log2(int(entry.mNode->getSize()));
|
|
||||||
entry.mRenderingNode = chunkManager->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags);
|
entry.mRenderingNode = chunkManager->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuadTreeWorld::accept(osg::NodeVisitor &nv)
|
void QuadTreeWorld::accept(osg::NodeVisitor &nv)
|
||||||
|
@ -378,7 +412,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
|
||||||
{
|
{
|
||||||
ViewData::Entry& entry = vd->getEntry(i);
|
ViewData::Entry& entry = vd->getEntry(i);
|
||||||
|
|
||||||
loadRenderingNode(entry, vd, mChunkManager.get());
|
loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get());
|
||||||
|
|
||||||
if (entry.mVisible)
|
if (entry.mVisible)
|
||||||
{
|
{
|
||||||
|
@ -404,7 +438,7 @@ void QuadTreeWorld::ensureQuadTreeBuilt()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const float minSize = 1/8.f;
|
const float minSize = 1/8.f;
|
||||||
QuadTreeBuilder builder(mStorage, mViewDataMap.get(), minSize);
|
QuadTreeBuilder builder(mStorage, mViewDataMap.get(), mLodFactor, minSize);
|
||||||
builder.build();
|
builder.build();
|
||||||
|
|
||||||
mRootNode = builder.getRootNode();
|
mRootNode = builder.getRootNode();
|
||||||
|
@ -435,7 +469,7 @@ void QuadTreeWorld::cacheCell(View *view, int x, int y)
|
||||||
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
|
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
|
||||||
{
|
{
|
||||||
ViewData::Entry& entry = vd->getEntry(i);
|
ViewData::Entry& entry = vd->getEntry(i);
|
||||||
loadRenderingNode(entry, vd, mChunkManager.get());
|
loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +488,7 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint)
|
||||||
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
|
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
|
||||||
{
|
{
|
||||||
ViewData::Entry& entry = vd->getEntry(i);
|
ViewData::Entry& entry = vd->getEntry(i);
|
||||||
loadRenderingNode(entry, vd, mChunkManager.get());
|
loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ namespace Terrain
|
||||||
class QuadTreeWorld : public Terrain::World
|
class QuadTreeWorld : public Terrain::World
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask=~0, int borderMask=0);
|
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();
|
~QuadTreeWorld();
|
||||||
|
|
||||||
void accept(osg::NodeVisitor& nv);
|
void accept(osg::NodeVisitor& nv);
|
||||||
|
@ -44,6 +45,8 @@ namespace Terrain
|
||||||
|
|
||||||
OpenThreads::Mutex mQuadTreeMutex;
|
OpenThreads::Mutex mQuadTreeMutex;
|
||||||
bool mQuadTreeBuilt;
|
bool mQuadTreeBuilt;
|
||||||
|
float mLodFactor;
|
||||||
|
int mVertexLodMod;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,3 +23,81 @@ will still be controlled by cell preloading settings.
|
||||||
The distant terrain engine is currently considered experimental
|
The distant terrain engine is currently considered experimental
|
||||||
and may receive updates and/or further configuration options in the future.
|
and may receive updates and/or further configuration options in the future.
|
||||||
The glaring omission of non-terrain objects in the distance somewhat limits this setting's usefulness.
|
The glaring omission of non-terrain objects in the distance somewhat limits this setting's usefulness.
|
||||||
|
|
||||||
|
vertex lod mod
|
||||||
|
--------------
|
||||||
|
|
||||||
|
:Type: integer
|
||||||
|
:Range: any
|
||||||
|
:Default: 0
|
||||||
|
|
||||||
|
Controls only the Vertex LOD of the terrain. The amount of terrain chunks and the detail of composite maps is left unchanged.
|
||||||
|
|
||||||
|
Must be changed in increments of 1. Each increment will double (for positive values) or halve (for negative values) the number of vertices rendered.
|
||||||
|
For example: -2 means 4x reduced detail, +3 means 8x increased detail.
|
||||||
|
|
||||||
|
Note this setting will typically not affect near terrain. When set to increase detail, the detail of near terrain can not be increased
|
||||||
|
because the detail is simply not there in the data files, and when set to reduce detail,
|
||||||
|
the detail of near terrain will not be reduced because it was already less detailed than the far terrain (in view relative terms) to begin with.
|
||||||
|
|
||||||
|
lod factor
|
||||||
|
----------
|
||||||
|
|
||||||
|
:Type: float
|
||||||
|
:Range: >0
|
||||||
|
:Default: 1.0
|
||||||
|
|
||||||
|
Controls the level of detail if distant terrain is enabled.
|
||||||
|
Higher values increase detail at the cost of performance, lower values reduce detail but increase performance.
|
||||||
|
|
||||||
|
Note: it also changes how the Quad Tree is split.
|
||||||
|
Increasing detail with this setting results in the visible terrain being divided into more chunks,
|
||||||
|
where as reducing detail with this setting would reduce the number of chunks.
|
||||||
|
|
||||||
|
Fewer terrain chunks is faster for rendering, but on the other hand a larger proportion of the entire terrain
|
||||||
|
must be rebuilt when LOD levels change as the camera moves.
|
||||||
|
This could result in frame drops if moving across the map at high speed.
|
||||||
|
|
||||||
|
For this reason, it is not recommended to change this setting if you want to change the LOD.
|
||||||
|
If you want to do that, first try using the 'vertex lod mod' setting to configure the detail of the terrain outlines
|
||||||
|
to your liking and then use 'composite map resolution' to configure the texture detail to your liking.
|
||||||
|
But these settings can only be changed in multiples of two, so you may want to adjust 'lod factor' afterwards for even more fine-tuning.
|
||||||
|
|
||||||
|
composite map level
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
:Type: integer
|
||||||
|
:Range: >= -3
|
||||||
|
:Default: 0
|
||||||
|
|
||||||
|
Controls at which minimum size (in 2^value cell units) terrain chunks will start to use a composite map instead of the high-detail textures.
|
||||||
|
With value -3 composite maps are used everywhere.
|
||||||
|
|
||||||
|
A composite map is a pre-rendered texture that contains all the texture layers combined.
|
||||||
|
Note that resolution of composite maps is currently always fixed at 'composite map resolution',
|
||||||
|
regardless of the resolution of the underlying terrain textures.
|
||||||
|
If high-detail texture replacers are used, probably it is worth to increase 'composite map resolution' setting value.
|
||||||
|
|
||||||
|
composite map resolution
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
:Type: integer
|
||||||
|
:Range: >0
|
||||||
|
:Default: 512
|
||||||
|
|
||||||
|
Controls the resolution of composite maps. Larger values result in increased detail,
|
||||||
|
but may take longer to prepare and thus could result in longer loading times and an increased chance of frame drops during play.
|
||||||
|
As with most other texture resolution settings, it's most efficient to use values that are powers of two.
|
||||||
|
|
||||||
|
An easy way to observe changes to loading time is to load a save in an interior next to an exterior door
|
||||||
|
(so it will start preloding terrain) and watch how long it takes for the 'Composite' counter on the F4 panel to fall to zero.
|
||||||
|
|
||||||
|
max composite geometry size
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
:Type: float
|
||||||
|
:Range: >=1.0
|
||||||
|
:Default: 4.0
|
||||||
|
|
||||||
|
Controls the maximum size of simple composite geometry chunk in cell units. With small values there will more draw calls and small textures,
|
||||||
|
but higher values create more overdraw (not every texture layer is used everywhere).
|
||||||
|
|
|
@ -90,6 +90,22 @@ pointers cache size = 40
|
||||||
# If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells
|
# If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells
|
||||||
distant terrain = false
|
distant terrain = false
|
||||||
|
|
||||||
|
# Controls how the Quad Tree is split. This affects Vertex LOD, Texture LOD and load times. Values > 1 increase detail, values < 1 reduce detail.
|
||||||
|
lod factor = 1.0
|
||||||
|
|
||||||
|
# Controls only the Vertex LOD. Change in increments of 1, each change doubles (or halves) the number of vertices. Values > 0 increase detail, values < 0 reduce detail.
|
||||||
|
vertex lod mod = 0
|
||||||
|
|
||||||
|
# Controls when the distant terrain will flip to composited textures instead of high-detail textures, should be >= -3.
|
||||||
|
# Higher value is more detailed textures.
|
||||||
|
composite map level = 0
|
||||||
|
|
||||||
|
# Controls the resolution of composite maps.
|
||||||
|
composite map resolution = 512
|
||||||
|
|
||||||
|
# Controls the maximum size of composite geometry, should be >= 1.0. With low values there will be many small chunks, with high values - lesser count of bigger chunks.
|
||||||
|
max composite geometry size = 4.0
|
||||||
|
|
||||||
[Fog]
|
[Fog]
|
||||||
|
|
||||||
# If true, use extended fog parameters for distant terrain not controlled by
|
# If true, use extended fog parameters for distant terrain not controlled by
|
||||||
|
|
Loading…
Reference in a new issue