mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 09:26:38 +00:00 
			
		
		
		
	This PR aims to solve all issues with `Groundcover` view distance handling in a satisfying way while preserving other optimisations that benefit other features. The main idea here is not to rely on `ViewData` updates for distance culling calculations because we can not accurately determine distance against lazily updated views. Instead, we perform an accurate measurement in a cull callback we can run every frame in `Groundcover` itself. While we do have to add some code to handle this feature, it is quite loosely coupled code that could be useful elsewhere in the future. These changes should address a performance regression @akortunov experienced.
		
			
				
	
	
		
			117 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef OPENMW_COMPONENTS_TERRAIN_VIEWDATA_H
 | |
| #define OPENMW_COMPONENTS_TERRAIN_VIEWDATA_H
 | |
| 
 | |
| #include <vector>
 | |
| #include <deque>
 | |
| 
 | |
| #include <osg/Node>
 | |
| 
 | |
| #include "world.hpp"
 | |
| 
 | |
| namespace Terrain
 | |
| {
 | |
| 
 | |
|     class QuadTreeNode;
 | |
| 
 | |
|     struct ViewDataEntry
 | |
|     {
 | |
|         ViewDataEntry();
 | |
| 
 | |
|         bool set(QuadTreeNode* node);
 | |
| 
 | |
|         QuadTreeNode* mNode;
 | |
| 
 | |
|         unsigned int mLodFlags;
 | |
|         osg::ref_ptr<osg::Node> mRenderingNode;
 | |
|     };
 | |
| 
 | |
|     class ViewData : public View
 | |
|     {
 | |
|     public:
 | |
|         ViewData();
 | |
|         ~ViewData();
 | |
| 
 | |
|         void add(QuadTreeNode* node);
 | |
| 
 | |
|         void reset() override;
 | |
| 
 | |
|         bool suitableToUse(const osg::Vec4i& activeGrid) const;
 | |
| 
 | |
|         void clear();
 | |
| 
 | |
|         bool contains(QuadTreeNode* node) const;
 | |
| 
 | |
|         void copyFrom(const ViewData& other);
 | |
| 
 | |
|         unsigned int getNumEntries() const { return mNumEntries; }
 | |
|         ViewDataEntry& getEntry(unsigned int i) { return mEntries[i]; }
 | |
| 
 | |
|         double getLastUsageTimeStamp() const { return mLastUsageTimeStamp; }
 | |
|         void setLastUsageTimeStamp(double timeStamp) { mLastUsageTimeStamp = timeStamp; }
 | |
| 
 | |
|         /// Indicates at least one mNode of mEntries has changed.
 | |
|         /// @note Such changes may necessitate a revalidation of cached mRenderingNodes elsewhere depending
 | |
|         /// on the parameters that affect the creation of mRenderingNode.
 | |
|         bool hasChanged() const { return mChanged; }
 | |
|         void setChanged(bool changed) { mChanged = changed; }
 | |
| 
 | |
|         bool hasViewPoint() const { return mHasViewPoint; }
 | |
| 
 | |
|         void setViewPoint(const osg::Vec3f& viewPoint);
 | |
|         const osg::Vec3f& getViewPoint() const { return mViewPoint; }
 | |
| 
 | |
|         void setActiveGrid(const osg::Vec4i &grid) { if (grid != mActiveGrid) {mActiveGrid = grid;mEntries.clear();mNumEntries=0;} }
 | |
|         const osg::Vec4i &getActiveGrid() const { return mActiveGrid;}
 | |
| 
 | |
|         unsigned int getWorldUpdateRevision() const { return mWorldUpdateRevision; }
 | |
|         void setWorldUpdateRevision(int updateRevision) { mWorldUpdateRevision = updateRevision; }
 | |
| 
 | |
|     private:
 | |
|         std::vector<ViewDataEntry> mEntries;
 | |
|         unsigned int mNumEntries;
 | |
|         double mLastUsageTimeStamp;
 | |
|         bool mChanged;
 | |
|         osg::Vec3f mViewPoint;
 | |
|         bool mHasViewPoint;
 | |
|         osg::Vec4i mActiveGrid;
 | |
|         unsigned int mWorldUpdateRevision;
 | |
|     };
 | |
| 
 | |
|     class ViewDataMap : public osg::Referenced
 | |
|     {
 | |
|     public:
 | |
|         ViewDataMap()
 | |
|             : mReuseDistance(150) // large value should be safe because the visibility of each node is still updated individually for each camera even if the base view was reused.
 | |
|                                   // this value also serves as a threshold for when a newly loaded LOD gets unloaded again so that if you hover around an LOD transition point the LODs won't keep loading and unloading all the time.
 | |
|             , mExpiryDelay(1.f)
 | |
|             , mWorldUpdateRevision(0)
 | |
|         {}
 | |
| 
 | |
|         ViewData* getViewData(osg::Object* viewer, const osg::Vec3f& viewPoint, const osg::Vec4i &activeGrid, bool& needsUpdate);
 | |
| 
 | |
|         ViewData* createOrReuseView();
 | |
|         ViewData* createIndependentView() const;
 | |
| 
 | |
|         void clearUnusedViews(double referenceTime);
 | |
|         void rebuildViews();
 | |
| 
 | |
|         float getReuseDistance() const { return mReuseDistance; }
 | |
| 
 | |
|     private:
 | |
|         std::list<ViewData> mViewVector;
 | |
| 
 | |
|         typedef std::map<osg::ref_ptr<osg::Object>, ViewData*> ViewerMap;
 | |
|         ViewerMap mViewers;
 | |
| 
 | |
|         float mReuseDistance;
 | |
|         float mExpiryDelay; // time in seconds for unused view to be removed
 | |
| 
 | |
|         unsigned int mWorldUpdateRevision;
 | |
| 
 | |
|         std::deque<ViewData*> mUsedViews;
 | |
|         std::deque<ViewData*> mUnusedViews;
 | |
|     };
 | |
| 
 | |
| }
 | |
| 
 | |
| #endif
 |