1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 29 #ifndef __Ogre_TerrainQuadTreeNode_H__ 30 #define __Ogre_TerrainQuadTreeNode_H__ 31 32 #include "OgreTerrainPrerequisites.h" 33 #include "OgreCommon.h" 34 #include "OgreMovableObject.h" 35 #include "OgreRenderable.h" 36 37 namespace Ogre 38 { 39 /** \addtogroup Optional 40 * @{ 41 */ 42 /** \addtogroup Terrain 43 * Some details on the terrain component 44 * @{ 45 */ 46 47 48 /** A node in a quad tree used to store a patch of terrain. 49 @remarks 50 <b>Algorithm overview:</b> 51 @par 52 Our goal is to perform traditional chunked LOD with geomorphing. But, 53 instead of just dividing the terrain into tiles, we will divide them into 54 a hierarchy of tiles, a quadtree, where any level of the quadtree can 55 be a rendered tile (to the exclusion of its children). The idea is to 56 collect together children into a larger batch with their siblings as LOD 57 decreases, to improve performance. 58 @par 59 The minBatchSize and maxBatchSize parameters on Terrain a key to 60 defining this behaviour. Both values are expressed in vertices down one axis. 61 maxBatchSize determines the number of tiles on one side of the terrain, 62 which is numTiles = (terrainSize-1) / (maxBatchSize-1). This in turn determines the depth 63 of the quad tree, which is sqrt(numTiles). The minBatchSize determines 64 the 'floor' of how low the number of vertices can go in a tile before it 65 has to be grouped together with its siblings to drop any lower. We also do not group 66 a tile with its siblings unless all of them are at this minimum batch size, 67 rather than trying to group them when they all end up on the same 'middle' LOD; 68 this is for several reasons; firstly, tiles hitting the same 'middle' LOD is 69 less likely and more transient if they have different levels of 'roughness', 70 and secondly since we're sharing a vertex / index pool between all tiles, 71 only grouping at the min level means that the number of combinations of 72 buffer sizes for any one tile is greatly simplified, making it easier to 73 pool data. To be more specific, any tile / quadtree node can only have 74 log2(maxBatchSize-1) - log2(minBatchSize-1) + 1 LOD levels (and if you set them 75 to the same value, LOD can only change by going up/down the quadtree). 76 The numbers of vertices / indices in each of these levels is constant for 77 the same (relative) LOD index no matter where you are in the tree, therefore 78 buffers can potentially be reused more easily. 79 */ 80 class _OgreTerrainExport TerrainQuadTreeNode : public TerrainAlloc 81 { 82 public: 83 /** Constructor. 84 @param terrain The ultimate parent terrain 85 @param parent Optional parent node (in which case xoff, yoff are 0 and size must be entire terrain) 86 @param xoff, yoff Offsets from the start of the terrain data in 2D 87 @param size The size of the node in vertices at the highest LOD 88 @param lod The base LOD level 89 @param depth The depth that this node is at in the tree (or convenience) 90 @param quadrant The index of the quadrant (0, 1, 2, 3) 91 */ 92 TerrainQuadTreeNode(Terrain* terrain, TerrainQuadTreeNode* parent, 93 uint16 xoff, uint16 yoff, uint16 size, uint16 lod, uint16 depth, uint16 quadrant); 94 virtual ~TerrainQuadTreeNode(); 95 96 /// Get the horizontal offset into the main terrain data of this node getXOffset()97 uint16 getXOffset() const { return mOffsetX; } 98 /// Get the vertical offset into the main terrain data of this node getYOffset()99 uint16 getYOffset() const { return mOffsetY; } 100 /// Is this a leaf node (no children) 101 bool isLeaf() const; 102 /// Get the base LOD level this node starts at (the highest LOD it handles) getBaseLod()103 uint16 getBaseLod() const { return mBaseLod; } 104 /// Get the number of LOD levels this node can represent itself (only > 1 for leaf nodes) 105 uint16 getLodCount() const; 106 /// Get child node 107 TerrainQuadTreeNode* getChild(unsigned short child) const; 108 /// Get parent node 109 TerrainQuadTreeNode* getParent() const; 110 /// Get ultimate parent terrain 111 Terrain* getTerrain() const; 112 113 /// Prepare node and children (perform CPU tasks, may be background thread) 114 void prepare(); 115 /// Prepare node from a stream 116 void prepare(StreamSerialiser& stream); 117 /// Load node and children (perform GPU tasks, will be render thread) 118 void load(); 119 /// Load node and children in a depth range (perform GPU tasks, will be render thread) 120 void load(uint16 depthStart, uint16 depthEnd); 121 void loadSelf(); 122 /// Unload node and children (perform GPU tasks, will be render thread) 123 void unload(); 124 /// Unload node and children in a depth range (perform GPU tasks, will be render thread) 125 void unload(uint16 depthStart, uint16 depthEnd); 126 /// Unprepare node and children (perform CPU tasks, may be background thread) 127 void unprepare(); 128 /// Save node to a stream 129 void save(StreamSerialiser& stream); 130 131 struct _OgreTerrainExport LodLevel : public TerrainAlloc 132 { 133 /// Number of vertices rendered down one side (not including skirts) 134 uint16 batchSize; 135 /// Index data on the gpu 136 IndexData* gpuIndexData; 137 /// Maximum delta height between this and the next lower lod 138 Real maxHeightDelta; 139 /// Temp calc area for max height delta 140 Real calcMaxHeightDelta; 141 /// The most recently calculated transition distance 142 Real lastTransitionDist; 143 /// The cFactor value used to calculate transitionDist 144 Real lastCFactor; 145 LodLevelLodLevel146 LodLevel() : batchSize(0), gpuIndexData(0), maxHeightDelta(0), calcMaxHeightDelta(0), 147 lastTransitionDist(0), lastCFactor(0) {} 148 }; 149 typedef std::vector<LodLevel*> LodLevelList; 150 151 /** Get the LodLevel information for a given lod. 152 @param lod The lod level index relative to this classes own list; if you 153 want to use a global lod level, subtract getBaseLod() first. Higher 154 LOD levels are lower detail. 155 */ 156 const LodLevel* getLodLevel(uint16 lod); 157 158 /** Notify the node (and children) that deltas are going to be calculated for a given range. 159 @remarks 160 Based on this call, we can know whether or not to reset the max height. 161 */ 162 void preDeltaCalculation(const Rect& rect); 163 164 /** Notify the node (and children) of a height delta value. */ 165 void notifyDelta(uint16 x, uint16 y, uint16 lod, Real delta); 166 167 /** Notify the node (and children) that deltas have finished being calculated. 168 */ 169 void postDeltaCalculation(const Rect& rect); 170 171 /** Promote the delta values calculated to the runtime ones (this must 172 be called in the main thread). 173 */ 174 void finaliseDeltaValues(const Rect& rect); 175 176 /** Assign vertex data to the tree, from a depth and at a given resolution. 177 @param treeDepthStart The first depth of tree that should use this data, owns the data 178 @param treeDepthEnd The end of the depth that should use this data (exclusive) 179 @param resolution The resolution of the data to use (compared to full terrain) 180 @param sz The size of the data along one edge 181 */ 182 void assignVertexData(uint16 treeDepthStart, uint16 treeDepthEnd, uint16 resolution, uint sz); 183 184 /** Tell a node that it should use an anscestor's vertex data. 185 @param treeDepthEnd The end of the depth that should use this data (exclusive) 186 @param resolution The resolution of the data to use 187 */ 188 void useAncestorVertexData(TerrainQuadTreeNode* owner, uint16 treeDepthEnd, uint16 resolution); 189 190 /** Tell the node to update its vertex data for a given region. 191 */ 192 void updateVertexData(bool positions, bool deltas, const Rect& rect, bool cpuData); 193 194 195 196 /** Merge a point (relative to terrain node) into the local bounds, 197 and that of children if applicable. 198 @param x,y The point on the terrain to which this position corresponds 199 (affects which nodes update their bounds) 200 @param pos The position relative to the terrain centre 201 */ 202 void mergeIntoBounds(long x, long y, const Vector3& pos); 203 /** Reset the bounds of this node and all its children for the region given. 204 @param rect The region for which bounds should be reset, in top-level terrain coords 205 */ 206 void resetBounds(const Rect& rect); 207 208 /** Returns true if the given rectangle overlaps the terrain area that 209 this node references. 210 @param rect The region in top-level terrain coords 211 */ 212 bool rectIntersectsNode(const Rect& rect); 213 /** Returns true if the given rectangle completely contains the terrain area that 214 this node references. 215 @param rect The region in top-level terrain coords 216 */ 217 bool rectContainsNode(const Rect& rect); 218 /** Returns true if the given point is in the terrain area that 219 this node references. 220 @param x,y The point in top-level terrain coords 221 */ 222 bool pointIntersectsNode(long x, long y); 223 224 /// Get the AABB (local coords) of this node 225 const AxisAlignedBox& getAABB() const; 226 /// Get the bounding radius of this node 227 Real getBoundingRadius() const; 228 /// Get the local centre of this node, relative to parent terrain centre getLocalCentre()229 const Vector3& getLocalCentre() const { return mLocalCentre; } 230 /// Get the minimum height of the node 231 Real getMinHeight() const; 232 /// Get the maximum height of the node 233 Real getMaxHeight() const; 234 235 /** Calculate appropriate LOD for this node and children 236 @param cam The camera to be used (this should already be the LOD camera) 237 @param cFactor The cFactor which incorporates the viewport size, max pixel error and lod bias 238 @return true if this node or any of its children were selected for rendering 239 */ 240 bool calculateCurrentLod(const Camera* cam, Real cFactor); 241 242 /// Get the current LOD index (only valid after calculateCurrentLod) getCurrentLod()243 int getCurrentLod() const { return mCurrentLod; } 244 /// Returns whether this node is rendering itself at the current LOD level 245 bool isRenderedAtCurrentLod() const; 246 /// Returns whether this node or its children are being rendered at the current LOD level 247 bool isSelfOrChildRenderedAtCurrentLod() const; 248 /// Manually set the current LOD, intended for internal use only 249 void setCurrentLod(int lod); 250 /// Get the transition state between the current LOD and the next lower one (only valid after calculateCurrentLod) getLodTransition()251 float getLodTransition() const { return mLodTransition; } 252 /// Manually set the current LOD transition state, intended for internal use only 253 void setLodTransition(float t); 254 255 /// Buffer binding used for holding positions 256 static unsigned short POSITION_BUFFER; 257 /// Buffer binding used for holding delta values 258 static unsigned short DELTA_BUFFER; 259 260 /// Returns the internal renderable object for this node 261 Renderable *_getRenderable(); 262 protected: 263 Terrain* mTerrain; 264 TerrainQuadTreeNode* mParent; 265 TerrainQuadTreeNode* mChildren[4]; 266 LodLevelList mLodLevels; 267 268 uint16 mOffsetX, mOffsetY; 269 uint16 mBoundaryX, mBoundaryY; 270 /// The number of vertices at the original terrain resolution this node encompasses 271 uint16 mSize; 272 uint16 mBaseLod; 273 uint16 mDepth; 274 uint16 mQuadrant; 275 Vector3 mLocalCentre; /// Relative to terrain centre 276 AxisAlignedBox mAABB; /// Relative to mLocalCentre 277 Real mBoundingRadius; /// Relative to mLocalCentre 278 int mCurrentLod; /// -1 = none (do not render) 279 unsigned short mMaterialLodIndex; 280 float mLodTransition; /// 0-1 transition to lower LOD 281 /// The child with the largest height delta 282 TerrainQuadTreeNode* mChildWithMaxHeightDelta; 283 bool mSelfOrChildRendered; 284 285 struct VertexDataRecord : public TerrainAlloc 286 { 287 VertexData* cpuVertexData; 288 VertexData* gpuVertexData; 289 /// Resolution of the data compared to the base terrain data (NOT number of vertices!) 290 uint16 resolution; 291 /// Size of the data along one edge 292 uint16 size; 293 /// Number of quadtree levels (including this one) this data applies to 294 uint16 treeLevels; 295 /// Number of rows and columns of skirts 296 uint16 numSkirtRowsCols; 297 /// The number of rows / cols to skip in between skirts 298 uint16 skirtRowColSkip; 299 /// Is the GPU vertex data out of date? 300 bool gpuVertexDataDirty; 301 VertexDataRecordVertexDataRecord302 VertexDataRecord(uint16 res, uint16 sz, uint16 lvls) 303 : cpuVertexData(0), gpuVertexData(0), resolution(res), size(sz), 304 treeLevels(lvls), numSkirtRowsCols(0), 305 skirtRowColSkip(0), gpuVertexDataDirty(false) {} 306 }; 307 308 TerrainQuadTreeNode* mNodeWithVertexData; 309 VertexDataRecord* mVertexDataRecord; 310 311 /** MovableObject implementation to provide the hook to the scene. 312 @remarks 313 In one sense, it would be most convenient to have a single MovableObject 314 to represent the whole Terrain object, and then internally perform 315 some quadtree frustum culling to narrow down which specific tiles are rendered. 316 However, the one major flaw with that is that exposing the bounds to 317 the SceneManager at that level prevents it from doing anything smarter 318 in terms of culling - for example a portal or occlusion culling SceneManager 319 would have no opportunity to process the leaf nodes in those terms, and 320 a simple frustum cull may give significantly poorer results. 321 @par 322 Therefore, we in fact register a MovableObject at every node, and 323 use the LOD factor to determine which one is currently active. LODs 324 must be mutually exclusive and to deal with precision errors, we really 325 need to evaluate them all at once, rather than as part of the 326 _notifyCurrentCamera function. Therefore the root Terrain registers 327 a SceneManager::Listener to precalculate which nodes will be displayed 328 when it comes to purely a LOD basis. 329 */ 330 class _OgreTerrainExport Movable : public MovableObject 331 { 332 protected: 333 TerrainQuadTreeNode* mParent; 334 public: 335 Movable(TerrainQuadTreeNode* parent); 336 virtual ~Movable(); 337 338 // necessary overrides 339 const String& getMovableType(void) const; 340 const AxisAlignedBox& getBoundingBox(void) const; 341 Real getBoundingRadius(void) const; 342 void _updateRenderQueue(RenderQueue* queue); 343 void visitRenderables(Renderable::Visitor* visitor, bool debugRenderables = false); 344 bool isVisible(void) const; 345 uint32 getVisibilityFlags(void) const; 346 uint32 getQueryFlags(void) const; 347 bool getCastShadows(void) const; 348 349 }; 350 Movable* mMovable; 351 friend class Movable; 352 SceneNode* mLocalNode; 353 354 /// Hook to the render queue 355 class _OgreTerrainExport Rend : public Renderable, public TerrainAlloc 356 { 357 protected: 358 TerrainQuadTreeNode* mParent; 359 public: 360 Rend(TerrainQuadTreeNode* parent); 361 virtual ~Rend(); 362 363 const MaterialPtr& getMaterial(void) const; 364 Technique* getTechnique(void) const; 365 void getRenderOperation(RenderOperation& op); 366 void getWorldTransforms(Matrix4* xform) const; 367 Real getSquaredViewDepth(const Camera* cam) const; 368 const LightList& getLights(void) const; 369 bool getCastsShadows(void) const; 370 371 }; 372 Rend* mRend; 373 friend class Rend; 374 375 // actual implementation of MovableObject methods 376 void updateRenderQueue(RenderQueue* queue); 377 void visitRenderables(Renderable::Visitor* visitor, bool debugRenderables = false); 378 // actual implementations of Renderable methods 379 const MaterialPtr& getMaterial(void) const; 380 Technique* getTechnique(void) const; 381 void getRenderOperation(RenderOperation& op); 382 void getWorldTransforms(Matrix4* xform) const; 383 Real getSquaredViewDepth(const Camera* cam) const; 384 const LightList& getLights(void) const; 385 bool getCastsShadows(void) const; 386 387 388 const VertexDataRecord* getVertexDataRecord() const; 389 void createCpuVertexData(); 390 /* Update the vertex buffers - the rect in question is relative to the whole terrain, 391 not the local vertex data (which may use a subset) 392 */ 393 void updateVertexBuffer(HardwareVertexBufferSharedPtr& posbuf, HardwareVertexBufferSharedPtr& deltabuf, const Rect& rect); 394 void destroyCpuVertexData(); 395 396 void createGpuVertexData(); 397 void destroyGpuVertexData(); 398 void updateGpuVertexData(); 399 void createGpuIndexData(); 400 void destroyGpuIndexData(); 401 402 void populateIndexData(uint16 batchSize, IndexData* destData); 403 void writePosVertex(bool compress, uint16 x, uint16 y, float height, const Vector3& pos, float uvScale, float** ppPos); 404 void writeDeltaVertex(bool compress, uint16 x, uint16 y, float delta, float deltaThresh, float** ppDelta); 405 406 uint16 calcSkirtVertexIndex(uint16 mainIndex, bool isCol); 407 408 }; 409 410 /** @} */ 411 /** @} */ 412 } 413 414 #endif 415