Make Distant Terrain more configurable (feature #4890)

pull/541/head
bzzt 6 years ago committed by Andrei Kortunov
parent 12cef51122
commit fd94d7f7ff

@ -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

@ -244,7 +244,7 @@ namespace MWRender
int indoorShadowCastingTraversalMask = shadowCastingTraversalMask; int indoorShadowCastingTraversalMask = shadowCastingTraversalMask;
if (Settings::Manager::getBool("object shadows", "Shadows")) if (Settings::Manager::getBool("object shadows", "Shadows"))
shadowCastingTraversalMask |= Mask_Object; shadowCastingTraversalMask |= Mask_Object;
mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager()));
Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines();
@ -283,12 +283,24 @@ 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");
mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug, compMapResolution, compMapLevel, lodFactor));
}
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,7 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T
, mTextureManager(textureManager) , mTextureManager(textureManager)
, mCompositeMapRenderer(renderer) , mCompositeMapRenderer(renderer)
, mCompositeMapSize(512) , mCompositeMapSize(512)
, mCompositeMapLevel(1.f)
, mCullingActive(true) , mCullingActive(true)
{ {
@ -68,11 +69,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;
@ -199,7 +195,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,16 @@ 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 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 +58,7 @@ namespace Terrain
BufferCache mBufferCache; BufferCache mBufferCache;
unsigned int mCompositeMapSize; unsigned int mCompositeMapSize;
float mCompositeMapLevel;
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();
@ -222,6 +225,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;
@ -229,13 +233,17 @@ 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)
: 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)
{ {
// 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);
} }
QuadTreeWorld::~QuadTreeWorld() QuadTreeWorld::~QuadTreeWorld()
@ -402,7 +410,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();

@ -19,7 +19,7 @@ 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);
~QuadTreeWorld(); ~QuadTreeWorld();
void accept(osg::NodeVisitor& nv); void accept(osg::NodeVisitor& nv);
@ -44,6 +44,7 @@ namespace Terrain
OpenThreads::Mutex mQuadTreeMutex; OpenThreads::Mutex mQuadTreeMutex;
bool mQuadTreeBuilt; bool mQuadTreeBuilt;
float mLodFactor;
}; };
} }

@ -12,7 +12,7 @@ Controls whether the engine will use paging and LOD algorithms to load the terra
Otherwise, only the terrain of the surrounding cells is loaded. Otherwise, only the terrain of the surrounding cells is loaded.
.. note:: .. note::
When enabling distant terrain, make sure the 'viewing distance' in the camera section is set to a larger value so When enabling distant terrain, make sure the 'viewing distance' in the camera section is set to a larger value so
that you can actually see the additional terrain. that you can actually see the additional terrain.
To avoid frame drops as the player moves around, nearby terrain pages are always preloaded in the background, To avoid frame drops as the player moves around, nearby terrain pages are always preloaded in the background,
@ -23,3 +23,36 @@ 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.
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.
composite map level
-------------------
:Type: integer
:Range: >= -3
:Default: 0
Controls at what 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.
With value >= 1 the map window will not use composited textures.
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.

@ -90,6 +90,16 @@ 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 the level of detail for distant terrain. Lower values = less detail, higher = more detail, should be > 0
lod factor = 1.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
[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
@ -236,7 +246,7 @@ barter disposition change is permanent = false
# Uses the MCP formula (damage * (strength / 40)) to factor Strength into hand-to-hand combat. # Uses the MCP formula (damage * (strength / 40)) to factor Strength into hand-to-hand combat.
# (0 means it does not factor it in, 1 means it factors into werewolves damage calculation and # (0 means it does not factor it in, 1 means it factors into werewolves damage calculation and
# 2 means werewolves are ignored) # 2 means werewolves are ignored)
strength influences hand to hand = 0 strength influences hand to hand = 0
# Render holstered weapons (with quivers and scabbards), requires modded assets # Render holstered weapons (with quivers and scabbards), requires modded assets

Loading…
Cancel
Save