From fd94d7f7ff3aae7ba200dd135b96644316f69f37 Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 27 Feb 2019 19:41:07 +0400 Subject: [PATCH 1/3] Make Distant Terrain more configurable (feature #4890) --- CHANGELOG.md | 1 + apps/openmw/mwrender/renderingmanager.cpp | 22 +++++++++--- components/terrain/chunkmanager.cpp | 8 ++--- components/terrain/chunkmanager.hpp | 7 ++-- components/terrain/quadtreeworld.cpp | 22 ++++++++---- components/terrain/quadtreeworld.hpp | 3 +- .../reference/modding/settings/terrain.rst | 35 ++++++++++++++++++- files/settings-default.cfg | 12 ++++++- 8 files changed, 87 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fac0b4ac0..fad734ec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Feature #4812: Support NiSwitchNode Feature #4836: Daytime node switch 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 0.45.0 diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c1f2b390f..4a9696064 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -244,7 +244,7 @@ namespace MWRender int indoorShadowCastingTraversalMask = shadowCastingTraversalMask; if (Settings::Manager::getBool("object shadows", "Shadows")) shadowCastingTraversalMask |= Mask_Object; - + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); @@ -283,12 +283,24 @@ namespace MWRender mDistantFog = Settings::Manager::getBool("use distant fog", "Fog"); 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"), - Settings::Manager::getBool("auto use terrain specular maps", "Shaders")); + + const std::string normalMapPattern = Settings::Manager::getString("normal map pattern", "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) - 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 mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug)); diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index b23b0b76c..9e31b9a20 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -28,6 +28,7 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T , mTextureManager(textureManager) , mCompositeMapRenderer(renderer) , mCompositeMapSize(512) + , mCompositeMapLevel(1.f) , mCullingActive(true) { @@ -68,11 +69,6 @@ void ChunkManager::releaseGLObjects(osg::State *state) mBufferCache.releaseGLObjects(state); } -void ChunkManager::setCullingActive(bool active) -{ - mCullingActive = active; -} - osg::ref_ptr ChunkManager::createCompositeMapRTT() { osg::ref_ptr texture = new osg::Texture2D; @@ -199,7 +195,7 @@ osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Ve geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, lodFlags)); - bool useCompositeMap = chunkSize >= 1.f; + bool useCompositeMap = chunkSize >= mCompositeMapLevel; unsigned int numUvSets = useCompositeMap ? 1 : 2; for (unsigned int i=0; i 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 clearCache() override; void releaseGLObjects(osg::State* state) override; - void setCullingActive(bool active); - private: osg::ref_ptr createChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); @@ -56,6 +58,7 @@ namespace Terrain BufferCache mBufferCache; unsigned int mCompositeMapSize; + float mCompositeMapLevel; bool mCullingActive; }; diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 594b2b755..f531e241f 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -75,8 +75,9 @@ namespace Terrain class DefaultLodCallback : public LodCallback { public: - DefaultLodCallback(float minSize) - : mMinSize(minSize) + DefaultLodCallback(float factor, float minSize) + : mFactor(factor) + , mMinSize(minSize) { } @@ -84,12 +85,13 @@ public: { float dist = distanceToBox(node->getBoundingBox(), eyePoint); int nativeLodLevel = Log2(static_cast(node->getSize()/mMinSize)); - int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize))); + int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize*mFactor))); return nativeLodLevel <= lodLevel; } private: + float mFactor; float mMinSize; }; @@ -123,8 +125,9 @@ private: class QuadTreeBuilder { public: - QuadTreeBuilder(Terrain::Storage* storage, ViewDataMap* viewDataMap, float minSize) + QuadTreeBuilder(Terrain::Storage* storage, ViewDataMap* viewDataMap, float lodFactor, float minSize) : mStorage(storage) + , mLodFactor(lodFactor) , mMinX(0.f), mMaxX(0.f), mMinY(0.f), mMaxY(0.f) , mMinSize(minSize) , mViewDataMap(viewDataMap) @@ -146,7 +149,7 @@ public: mRootNode = new RootNode(size, osg::Vec2f(centerX, centerY)); mRootNode->setViewDataMap(mViewDataMap); - mRootNode->setLodCallback(new DefaultLodCallback(mMinSize)); + mRootNode->setLodCallback(new DefaultLodCallback(mLodFactor, mMinSize)); addChildren(mRootNode); mRootNode->initNeighbours(); @@ -222,6 +225,7 @@ public: private: Terrain::Storage* mStorage; + float mLodFactor; float mMinX, mMaxX, mMinY, mMaxY; float mMinSize; ViewDataMap* mViewDataMap; @@ -229,13 +233,17 @@ private: osg::ref_ptr 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) , mViewDataMap(new ViewDataMap) , mQuadTreeBuilt(false) + , mLodFactor(lodFactor) { // No need for culling on the Drawable / Transform level as the quad tree performs the culling already. mChunkManager->setCullingActive(false); + + mChunkManager->setCompositeMapSize(compMapResolution); + mChunkManager->setCompositeMapLevel(compMapLevel); } QuadTreeWorld::~QuadTreeWorld() @@ -402,7 +410,7 @@ void QuadTreeWorld::ensureQuadTreeBuilt() return; const float minSize = 1/8.f; - QuadTreeBuilder builder(mStorage, mViewDataMap.get(), minSize); + QuadTreeBuilder builder(mStorage, mViewDataMap.get(), mLodFactor, minSize); builder.build(); mRootNode = builder.getRootNode(); diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index c166a9cb1..9c47057c4 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -19,7 +19,7 @@ namespace Terrain class QuadTreeWorld : public Terrain::World { 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(); void accept(osg::NodeVisitor& nv); @@ -44,6 +44,7 @@ namespace Terrain OpenThreads::Mutex mQuadTreeMutex; bool mQuadTreeBuilt; + float mLodFactor; }; } diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index 687f55e5e..9d4ac9379 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -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. .. 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. 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 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. + +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. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index db3d7e75b..99d4a4eb5 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -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 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] # 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. # (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 # Render holstered weapons (with quivers and scabbards), requires modded assets From 9d44e18af63d63e8959f7afec0b8ad1edf93abdc Mon Sep 17 00:00:00 2001 From: bzzt Date: Wed, 20 Feb 2019 13:37:00 +0000 Subject: [PATCH 2/3] Allow to configure terrain vertex LOD --- apps/openmw/mwrender/renderingmanager.cpp | 3 +- components/terrain/quadtreeworld.cpp | 49 ++++++++++++++----- components/terrain/quadtreeworld.hpp | 4 +- .../reference/modding/settings/terrain.rst | 19 +++++++ files/settings-default.cfg | 5 +- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4a9696064..a14039d21 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -299,7 +299,8 @@ namespace MWRender 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)); + const int vertexLodMod = Settings::Manager::getInt("vertex lod mod", "Terrain"); + mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug, compMapResolution, compMapLevel, lodFactor, vertexLodMod)); } else mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug)); diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index f531e241f..a0c353a73 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -233,11 +233,12 @@ private: osg::ref_ptr mRootNode; }; -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) +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) : World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask) , mViewDataMap(new ViewDataMap) , mQuadTreeBuilt(false) , mLodFactor(lodFactor) + , mVertexLodMod(vertexLodMod) { // No need for culling on the Drawable / Transform level as the quad tree performs the culling already. mChunkManager->setCullingActive(false); @@ -293,7 +294,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; for (unsigned int i=0; i<4; ++i) @@ -308,7 +332,7 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd) neighbour = neighbour->getParent(); int lod = 0; 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 - lod = 0; // neighbours with more detail will do the stitching themselves @@ -321,13 +345,17 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd) 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()) { // 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, vd); + unsigned int lodFlags = getLodFlags(entry.mNode, ourLod, vertexLodMod, vd); if (lodFlags != entry.mLodFlags) { entry.mRenderingNode = nullptr; @@ -336,10 +364,7 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunk } if (!entry.mRenderingNode) - { - int ourLod = Log2(int(entry.mNode->getSize())); entry.mRenderingNode = chunkManager->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags); - } } void QuadTreeWorld::accept(osg::NodeVisitor &nv) @@ -384,7 +409,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mChunkManager.get()); + loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); if (entry.mVisible) { @@ -441,7 +466,7 @@ void QuadTreeWorld::cacheCell(View *view, int x, int y) for (unsigned int i=0; igetNumEntries(); ++i) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mChunkManager.get()); + loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); } } @@ -460,7 +485,7 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint) for (unsigned int i=0; igetNumEntries(); ++i) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mChunkManager.get()); + loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); } } diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index 9c47057c4..252f930fa 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -19,7 +19,8 @@ namespace Terrain class QuadTreeWorld : public Terrain::World { 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); + 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); + ~QuadTreeWorld(); void accept(osg::NodeVisitor& nv); @@ -45,6 +46,7 @@ namespace Terrain OpenThreads::Mutex mQuadTreeMutex; bool mQuadTreeBuilt; float mLodFactor; + int mVertexLodMod; }; } diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index 9d4ac9379..e14bb1e62 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -24,6 +24,19 @@ The distant terrain engine is currently considered experimental 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. +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 ---------- @@ -33,6 +46,12 @@ lod factor 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 this 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 ------------------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 99d4a4eb5..92b76146d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -90,9 +90,12 @@ 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 distant terrain = false -# Controls the level of detail for distant terrain. Lower values = less detail, higher = more detail, should be > 0 +# 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 From 56fea4b062ce393959d51aefcb6ae3e9756b8930 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 28 Feb 2019 12:48:04 +0400 Subject: [PATCH 3/3] Add setting to control composite geometry size --- apps/openmw/mwrender/renderingmanager.cpp | 6 ++- components/terrain/chunkmanager.cpp | 3 +- components/terrain/chunkmanager.hpp | 2 + components/terrain/quadtreeworld.cpp | 3 +- components/terrain/quadtreeworld.hpp | 2 +- .../reference/modding/settings/terrain.rst | 48 ++++++++++++++----- files/settings-default.cfg | 3 ++ 7 files changed, 52 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a14039d21..1bbed3740 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -300,7 +300,11 @@ namespace MWRender float compMapLevel = pow(2, compMapPower); const float lodFactor = Settings::Manager::getFloat("lod factor", "Terrain"); const int vertexLodMod = Settings::Manager::getInt("vertex lod mod", "Terrain"); - mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug, compMapResolution, compMapLevel, lodFactor, vertexLodMod)); + 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 mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug)); diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 9e31b9a20..27d87b031 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -29,6 +29,7 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T , mCompositeMapRenderer(renderer) , mCompositeMapSize(512) , mCompositeMapLevel(1.f) + , mMaxCompGeometrySize(1.f) , mCullingActive(true) { @@ -85,7 +86,7 @@ osg::ref_ptr ChunkManager::createCompositeMapRTT() 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.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap); diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 83182cf46..27201864f 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -35,6 +35,7 @@ namespace Terrain 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; @@ -59,6 +60,7 @@ namespace Terrain unsigned int mCompositeMapSize; float mCompositeMapLevel; + float mMaxCompGeometrySize; bool mCullingActive; }; diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index a0c353a73..e324672ff 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -233,7 +233,7 @@ private: osg::ref_ptr mRootNode; }; -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) +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) , mViewDataMap(new ViewDataMap) , mQuadTreeBuilt(false) @@ -245,6 +245,7 @@ QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resour mChunkManager->setCompositeMapSize(compMapResolution); mChunkManager->setCompositeMapLevel(compMapLevel); + mChunkManager->setMaxCompositeGeometrySize(maxCompGeometrySize); } QuadTreeWorld::~QuadTreeWorld() diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index 252f930fa..f724c44b1 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -19,7 +19,7 @@ namespace Terrain class QuadTreeWorld : public Terrain::World { 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); + 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(); diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index e14bb1e62..e15a0035d 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -33,9 +33,12 @@ vertex lod mod 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. +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. +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 ---------- @@ -44,13 +47,21 @@ lod factor :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. +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 this 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. +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. +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. +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 ------------------- @@ -59,11 +70,13 @@ composite map level :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. +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. -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. +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 ------------------------ @@ -72,6 +85,19 @@ composite map resolution :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. +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. +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). diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 92b76146d..d3f5c6a2e 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -103,6 +103,9 @@ 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] # If true, use extended fog parameters for distant terrain not controlled by