/src/ogre/Components/Terrain/include/OgreTerrainQuadTreeNode.h
Line | Count | Source (jump to first uncovered line) |
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 | | |
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 : private Renderable, private MovableObject |
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 | | */ |
91 | | TerrainQuadTreeNode(Terrain* terrain, TerrainQuadTreeNode* parent, |
92 | | uint16 xoff, uint16 yoff, uint16 size, uint16 lod, uint16 depth); |
93 | | virtual ~TerrainQuadTreeNode(); |
94 | | |
95 | | /// Get the horizontal offset into the main terrain data of this node |
96 | 0 | uint16 getXOffset() const { return mOffsetX; } |
97 | | /// Get the vertical offset into the main terrain data of this node |
98 | 0 | uint16 getYOffset() const { return mOffsetY; } |
99 | | /// Is this a leaf node (no children) |
100 | | bool isLeaf() const; |
101 | | /// Get the base LOD level this node starts at (the highest LOD it handles) |
102 | 0 | uint16 getBaseLod() const { return mBaseLod; } |
103 | | /// Get the number of LOD levels this node can represent itself (only > 1 for leaf nodes) |
104 | | uint16 getLodCount() const; |
105 | | /// Get child node |
106 | | TerrainQuadTreeNode* getChild(unsigned short child) const; |
107 | | /// Get parent node |
108 | | TerrainQuadTreeNode* getParent() const; |
109 | | /// Get ultimate parent terrain |
110 | | Terrain* getTerrain() const; |
111 | | |
112 | | /// Prepare node and children (perform CPU tasks, may be background thread) |
113 | | void prepare(); |
114 | | /// Prepare node from a stream |
115 | | void prepare(StreamSerialiser& stream); |
116 | | /// Load node and children (perform GPU tasks, will be render thread) |
117 | | void load(); |
118 | | /// Load node and children in a depth range (perform GPU tasks, will be render thread) |
119 | | void load(uint16 depthStart, uint16 depthEnd); |
120 | | void loadSelf(); |
121 | | /// Unload node and children (perform GPU tasks, will be render thread) |
122 | | void unload(); |
123 | | /// Unload node and children in a depth range (perform GPU tasks, will be render thread) |
124 | | void unload(uint16 depthStart, uint16 depthEnd); |
125 | | /// Unprepare node and children (perform CPU tasks, may be background thread) |
126 | | void unprepare(); |
127 | | /// Save node to a stream |
128 | | void save(StreamSerialiser& stream); |
129 | | |
130 | | struct _OgreTerrainExport LodLevel : public TerrainAlloc |
131 | | { |
132 | | /// Number of vertices rendered down one side (not including skirts) |
133 | | uint16 batchSize; |
134 | | /// Index data on the gpu |
135 | | IndexData* gpuIndexData; |
136 | | /// Maximum delta height between this and the next lower lod |
137 | | Real maxHeightDelta; |
138 | | /// Temp calc area for max height delta |
139 | | Real calcMaxHeightDelta; |
140 | | /// The most recently calculated transition distance |
141 | | Real lastTransitionDist; |
142 | | /// The cFactor value used to calculate transitionDist |
143 | | Real lastCFactor; |
144 | | |
145 | 0 | LodLevel() : batchSize(0), gpuIndexData(0), maxHeightDelta(0), calcMaxHeightDelta(0), |
146 | 0 | lastTransitionDist(0), lastCFactor(0) {} |
147 | | }; |
148 | | typedef std::vector<LodLevel*> LodLevelList; |
149 | | |
150 | | /** Get the LodLevel information for a given lod. |
151 | | @param lod The lod level index relative to this classes own list; if you |
152 | | want to use a global lod level, subtract getBaseLod() first. Higher |
153 | | LOD levels are lower detail. |
154 | | */ |
155 | | const LodLevel* getLodLevel(uint16 lod); |
156 | | |
157 | | /** Notify the node (and children) that deltas are going to be calculated for a given range. |
158 | | |
159 | | Based on this call, we can know whether or not to reset the max height. |
160 | | */ |
161 | | void preDeltaCalculation(const Rect& rect); |
162 | | |
163 | | /** Notify the node (and children) of a height delta value. */ |
164 | | void notifyDelta(uint16 x, uint16 y, uint16 lod, Real delta); |
165 | | |
166 | | /** Notify the node (and children) that deltas have finished being calculated. |
167 | | */ |
168 | | void postDeltaCalculation(const Rect& rect); |
169 | | |
170 | | /** Promote the delta values calculated to the runtime ones (this must |
171 | | be called in the main thread). |
172 | | */ |
173 | | void finaliseDeltaValues(const Rect& rect); |
174 | | |
175 | | /** Assign vertex data to the tree, from a depth and at a given resolution. |
176 | | @param treeDepthStart The first depth of tree that should use this data, owns the data |
177 | | @param treeDepthEnd The end of the depth that should use this data (exclusive) |
178 | | @param resolution The resolution of the data to use (compared to full terrain) |
179 | | @param sz The size of the data along one edge |
180 | | */ |
181 | | void assignVertexData(uint16 treeDepthStart, uint16 treeDepthEnd, uint16 resolution, uint sz); |
182 | | |
183 | | /** Tell a node that it should use an anscestor's vertex data. |
184 | | @param owner |
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 | 0 | const AxisAlignedBox& getBoundingBox(void) const override { return mAABB; } |
226 | | |
227 | | /// Get the bounding radius of this node |
228 | | Real getBoundingRadius() const override; |
229 | | /// Get the local centre of this node, relative to parent terrain centre |
230 | 0 | const Vector3& getLocalCentre() const { return mLocalCentre; } |
231 | | /// Get the minimum height of the node |
232 | | Real getMinHeight() const; |
233 | | /// Get the maximum height of the node |
234 | | Real getMaxHeight() const; |
235 | | |
236 | | /** Calculate appropriate LOD for this node and children |
237 | | @param cam The camera to be used (this should already be the LOD camera) |
238 | | @param cFactor The cFactor which incorporates the viewport size, max pixel error and lod bias |
239 | | @return true if this node or any of its children were selected for rendering |
240 | | */ |
241 | | bool calculateCurrentLod(const Camera* cam, Real cFactor); |
242 | | |
243 | | /// Get the current LOD index (only valid after calculateCurrentLod) |
244 | 0 | int getCurrentLod() const { return mCurrentLod; } |
245 | | /// Returns whether this node is rendering itself at the current LOD level |
246 | | bool isRenderedAtCurrentLod() const; |
247 | | /// Returns whether this node or its children are being rendered at the current LOD level |
248 | | bool isSelfOrChildRenderedAtCurrentLod() const; |
249 | | /// Manually set the current LOD, intended for internal use only |
250 | | void setCurrentLod(int lod); |
251 | | /// Get the transition state between the current LOD and the next lower one (only valid after calculateCurrentLod) |
252 | 0 | float getLodTransition() const { return mLodTransition; } |
253 | | /// Manually set the current LOD transition state, intended for internal use only |
254 | | void setLodTransition(float t); |
255 | | |
256 | | /// Buffer binding used for holding positions |
257 | | static unsigned short POSITION_BUFFER; |
258 | | /// Buffer binding used for holding delta values |
259 | | static unsigned short DELTA_BUFFER; |
260 | | |
261 | | private: |
262 | | Terrain* mTerrain; |
263 | | TerrainQuadTreeNode* mParent; |
264 | | TerrainQuadTreeNode* mChildren[4]; |
265 | | LodLevelList mLodLevels; |
266 | | |
267 | | uint16 mOffsetX, mOffsetY; |
268 | | uint16 mBoundaryX, mBoundaryY; |
269 | | /// The number of vertices at the original terrain resolution this node encompasses |
270 | | uint16 mSize; |
271 | | uint16 mBaseLod; |
272 | | uint16 mDepth; |
273 | | Vector3 mLocalCentre; /// Relative to terrain centre |
274 | | AxisAlignedBox mAABB; /// Relative to mLocalCentre |
275 | | Real mBoundingRadius; /// Relative to mLocalCentre |
276 | | int mCurrentLod; /// -1 = none (do not render) |
277 | | float mLodTransition; /// 0-1 transition to lower LOD |
278 | | /// The child with the largest height delta |
279 | | TerrainQuadTreeNode* mChildWithMaxHeightDelta; |
280 | | bool mSelfOrChildRendered; |
281 | | |
282 | | struct VertexDataRecord : public TerrainAlloc |
283 | | { |
284 | | VertexData* cpuVertexData; |
285 | | VertexData* gpuVertexData; |
286 | | /// Resolution of the data compared to the base terrain data (NOT number of vertices!) |
287 | | uint16 resolution; |
288 | | /// Size of the data along one edge |
289 | | uint16 size; |
290 | | /// Number of quadtree levels (including this one) this data applies to |
291 | | uint16 treeLevels; |
292 | | /// Number of rows and columns of skirts |
293 | | uint16 numSkirtRowsCols; |
294 | | /// The number of rows / cols to skip in between skirts |
295 | | uint16 skirtRowColSkip; |
296 | | /// Is the GPU vertex data out of date? |
297 | | bool gpuVertexDataDirty; |
298 | | |
299 | | VertexDataRecord(uint16 res, uint16 sz, uint16 lvls) |
300 | 0 | : cpuVertexData(0), gpuVertexData(0), resolution(res), size(sz), |
301 | 0 | treeLevels(lvls), numSkirtRowsCols(0), |
302 | 0 | skirtRowColSkip(0), gpuVertexDataDirty(false) {} |
303 | | }; |
304 | | |
305 | | TerrainQuadTreeNode* mNodeWithVertexData; |
306 | | VertexDataRecord* mVertexDataRecord; |
307 | | |
308 | | /** MovableObject implementation to provide the hook to the scene. |
309 | | |
310 | | In one sense, it would be most convenient to have a single MovableObject |
311 | | to represent the whole Terrain object, and then internally perform |
312 | | some quadtree frustum culling to narrow down which specific tiles are rendered. |
313 | | However, the one major flaw with that is that exposing the bounds to |
314 | | the SceneManager at that level prevents it from doing anything smarter |
315 | | in terms of culling - for example a portal or occlusion culling SceneManager |
316 | | would have no opportunity to process the leaf nodes in those terms, and |
317 | | a simple frustum cull may give significantly poorer results. |
318 | | @par |
319 | | Therefore, we in fact register a MovableObject at every node, and |
320 | | use the LOD factor to determine which one is currently active. LODs |
321 | | must be mutually exclusive and to deal with precision errors, we really |
322 | | need to evaluate them all at once, rather than as part of the |
323 | | _notifyCurrentCamera function. Therefore the root Terrain registers |
324 | | a SceneManager::Listener to precalculate which nodes will be displayed |
325 | | when it comes to purely a LOD basis. |
326 | | */ |
327 | | SceneNode* mLocalNode; |
328 | | |
329 | | // actual implementation of MovableObject methods |
330 | | bool isVisible(void) const override; |
331 | | const String& getMovableType(void) const override; |
332 | | void _updateRenderQueue(RenderQueue* queue) override; |
333 | | void visitRenderables(Renderable::Visitor* visitor, bool debugRenderables = false) override; |
334 | | // actual implementations of Renderable methods |
335 | | const MaterialPtr& getMaterial(void) const override; |
336 | | Technique* getTechnique(void) const override; |
337 | | void getRenderOperation(RenderOperation& op) override; |
338 | | void getWorldTransforms(Matrix4* xform) const override; |
339 | | Real getSquaredViewDepth(const Camera* cam) const override; |
340 | | const LightList& getLights(void) const override; |
341 | | bool getCastShadows(void) const override; |
342 | | /// @deprecated will be private in 14 |
343 | 0 | bool getCastsShadows(void) const override { return getCastShadows(); } |
344 | | |
345 | | |
346 | | const VertexDataRecord* getVertexDataRecord() const; |
347 | | void createCpuVertexData(); |
348 | | /* Update the vertex buffers - the rect in question is relative to the whole terrain, |
349 | | not the local vertex data (which may use a subset) |
350 | | */ |
351 | | void updateVertexBuffer(const HardwareVertexBufferPtr& posbuf, const HardwareVertexBufferPtr& deltabuf, const Rect& rect); |
352 | | void destroyCpuVertexData(); |
353 | | |
354 | | void createGpuVertexData(); |
355 | | void destroyGpuVertexData(); |
356 | | void updateGpuVertexData(); |
357 | | void createGpuIndexData(); |
358 | | void destroyGpuIndexData(); |
359 | | |
360 | | void populateIndexData(uint16 batchSize, IndexData* destData); |
361 | | void writePosVertex(bool compress, uint16 x, uint16 y, float height, const Vector3& pos, float uvScale, float** ppPos); |
362 | | void writeDeltaVertex(bool compress, uint16 x, uint16 y, float delta, float deltaThresh, float** ppDelta); |
363 | | |
364 | | uint16 calcSkirtVertexIndex(uint16 mainIndex, bool isCol); |
365 | | |
366 | | }; |
367 | | |
368 | | /** @} */ |
369 | | /** @} */ |
370 | | } |
371 | | |
372 | | #endif |