Terrain LOD work
[ogre3d.git] / Components / Terrain / src / OgreTerrain.cpp
blobd44e3f1542540f9b01a893417ea98e044c88dbe7
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/
7 Copyright (c) 2000-2009 Torus Knot Software Ltd
8 Also see acknowledgements in Readme.html
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22 http://www.gnu.org/copyleft/lesser.txt.
24 You may alternatively use this source under the terms of a specific version of
25 the OGRE Unrestricted License provided you have obtained such a license from
26 Torus Knot Software Ltd.
27 -----------------------------------------------------------------------------
29 #include "OgreTerrain.h"
30 #include "OgreTerrainQuadTreeNode.h"
31 #include "OgreStreamSerialiser.h"
32 #include "OgreMath.h"
33 #include "OgreImage.h"
34 #include "OgrePixelFormat.h"
35 #include "OgreSceneManager.h"
36 #include "OgreSceneNode.h"
37 #include "OgreException.h"
38 #include "OgreBitwise.h"
39 #include "OgreStringConverter.h"
40 #include "OgreViewport.h"
42 namespace Ogre
44 //---------------------------------------------------------------------
45 const uint32 Terrain::TERRAIN_CHUNK_ID = StreamSerialiser::makeIdentifier("TERR");
46 const uint16 Terrain::TERRAIN_CHUNK_VERSION = 1;
47 // since 129^2 is the greatest power we can address in 16-bit index
48 const uint16 Terrain::TERRAIN_MAX_BATCH_SIZE = 129;
49 //---------------------------------------------------------------------
50 //---------------------------------------------------------------------
51 bool TerrainGlobalOptions::msUseTriangleStrips = true;
52 bool TerrainGlobalOptions::msUseLodMorph = true;
53 Real TerrainGlobalOptions::msSkirtSize = 10;
54 bool TerrainGlobalOptions::msGenerateVertexNormals = false;
55 bool TerrainGlobalOptions::msGenerateNormalMap = true;
56 bool TerrainGlobalOptions::msGenerateShadowMap = false;
57 Vector3 TerrainGlobalOptions::msShadowMapDir = Vector3(1, -1, 0).normalisedCopy();
58 bool TerrainGlobalOptions::msGenerateHorizonMap = false;
59 Radian TerrainGlobalOptions::msHorizonMapAzimuth = Radian(0);
60 Radian TerrainGlobalOptions::msHorizonMapZenith = Radian(0);
61 Real TerrainGlobalOptions::msMaxPixelError = 3.0;
62 //---------------------------------------------------------------------
63 Terrain::Terrain(SceneManager* sm)
64 : mSceneMgr(sm)
65 , mHeightData(0)
66 , mDeltaData(0)
67 , mPos(Vector3::ZERO)
68 , mQuadTree(0)
69 , mNumLodLevels(0)
70 , mNumLodLevelsPerLeafNode(0)
71 , mTreeDepth(0)
73 mRootNode = sm->getRootSceneNode()->createChildSceneNode();
74 sm->addListener(this);
76 //---------------------------------------------------------------------
77 Terrain::~Terrain()
79 freeGPUResources();
80 freeCPUResources();
81 if (mSceneMgr)
83 mSceneMgr->destroySceneNode(mRootNode);
84 mSceneMgr->removeListener(this);
87 //---------------------------------------------------------------------
88 const AxisAlignedBox& Terrain::getAABB() const
90 if (!mQuadTree)
91 return AxisAlignedBox::BOX_NULL;
92 else
93 return mQuadTree->getAABB();
95 //---------------------------------------------------------------------
96 Real Terrain::getBoundingRadius() const
98 if (!mQuadTree)
99 return 0;
100 else
101 return mQuadTree->getBoundingRadius();
103 //---------------------------------------------------------------------
104 void Terrain::save(StreamSerialiser& stream)
106 stream.writeChunkBegin(TERRAIN_CHUNK_ID, TERRAIN_CHUNK_VERSION);
108 uint8 align = (uint8)mAlign;
109 stream.write(&align);
111 stream.write(&mSize);
112 stream.write(&mWorldSize);
113 uint16 splatDimCount;
114 if (mSplatTextureWorldSize.empty())
116 splatDimCount = 1;
117 Real dim = getSplatTextureWorldSize(0);
118 stream.write(&splatDimCount);
119 stream.write(&dim);
121 else
123 splatDimCount = static_cast<uint16>(mSplatTextureWorldSize.size());
124 stream.write(&splatDimCount);
125 stream.write(&mSplatTextureWorldSize[0], mSplatTextureWorldSize.size());
127 stream.write(&mMaxBatchSize);
128 stream.write(&mMinBatchSize);
129 stream.write(&mPos);
130 stream.write(mHeightData, mSize * mSize);
132 stream.writeChunkEnd(TERRAIN_CHUNK_ID);
134 //---------------------------------------------------------------------
135 bool Terrain::prepare(StreamSerialiser& stream)
137 freeCPUResources();
139 // get settings
140 mUseTriangleStrips = TerrainGlobalOptions::getUseTriangleStrips();
141 mUseLodMorph = TerrainGlobalOptions::getUseLodMorph();
142 mSkirtSize = TerrainGlobalOptions::getSkirtSize();
144 if (!stream.readChunkBegin(TERRAIN_CHUNK_ID, TERRAIN_CHUNK_VERSION))
145 return false;
147 uint8 align;
148 stream.read(&align);
149 mAlign = (Alignment)align;
150 stream.read(&mWorldSize);
151 uint16 splatDimCount;
152 stream.read(&splatDimCount);
153 for (uint16 i = 0; i < splatDimCount; ++i)
155 Real dim;
156 stream.read(&dim);
157 setSplatTextureWorldSize(i, dim);
159 stream.read(&mMaxBatchSize);
160 stream.read(&mMinBatchSize);
161 stream.read(&mPos);
162 updateBaseScale();
163 determineLodLevels();
166 size_t numVertices = mSize * mSize;
167 mHeightData = OGRE_ALLOC_T(float, numVertices, MEMCATEGORY_GEOMETRY);
168 stream.read(mHeightData, numVertices);
170 stream.readChunkEnd(TERRAIN_CHUNK_ID);
172 mQuadTree = OGRE_NEW TerrainQuadTreeNode(this, 0, 0, 0, mSize, mNumLodLevels - 1, 0, 0);
173 mQuadTree->prepare();
175 mDeltaData = OGRE_ALLOC_T(float, numVertices, MEMCATEGORY_GEOMETRY);
176 // calculate entire terrain
177 Rect rect;
178 rect.top = 0; rect.bottom = mSize;
179 rect.left = 0; rect.right = mSize;
180 calculateHeightDeltas(rect);
182 return true;
184 //---------------------------------------------------------------------
185 bool Terrain::prepare(const ImportData& importData)
187 freeCPUResources();
189 // validate
190 if (!(Bitwise::isPO2(importData.terrainSize - 1) && Bitwise::isPO2(importData.minBatchSize - 1)
191 && Bitwise::isPO2(importData.maxBatchSize - 1)))
193 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
194 "terrainSise, minBatchSize and maxBatchSize must all be n^2 + 1",
195 "Terrain::prepare");
198 if (importData.minBatchSize > importData.maxBatchSize)
200 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
201 "minBatchSize must be less than or equal to maxBatchSize",
202 "Terrain::prepare");
205 if (importData.maxBatchSize > TERRAIN_MAX_BATCH_SIZE)
207 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
208 "maxBatchSize must be no larger than " +
209 StringConverter::toString(TERRAIN_MAX_BATCH_SIZE),
210 "Terrain::prepare");
213 // get settings
214 mUseTriangleStrips = TerrainGlobalOptions::getUseTriangleStrips();
215 mUseLodMorph = TerrainGlobalOptions::getUseLodMorph();
216 mSkirtSize = TerrainGlobalOptions::getSkirtSize();
217 mGenerateVertexNormals = TerrainGlobalOptions::getGenerateVertexNormals();
218 mGenerateNormalMap = TerrainGlobalOptions::getGenerateNormalMap();
219 mGenerateShadowMap = TerrainGlobalOptions::getGenerateShadowMap();
220 mGenerateHorizonMap = TerrainGlobalOptions::getGenerateHorizonMap();
222 mAlign = importData.terrainAlign;
223 mSize = importData.terrainSize;
224 mWorldSize = importData.worldSize;
225 for (uint16 i = 0; i < importData.splatTextureWorldSizeList.size(); ++i)
227 setSplatTextureWorldSize(i, importData.splatTextureWorldSizeList[i]);
229 mMaxBatchSize = importData.maxBatchSize;
230 mMinBatchSize = importData.minBatchSize;
231 mPos = importData.pos;
232 updateBaseScale();
233 determineLodLevels();
235 size_t numVertices = mSize * mSize;
237 mHeightData = OGRE_ALLOC_T(float, numVertices, MEMCATEGORY_GEOMETRY);
239 if (importData.inputFloat)
241 if (Math::RealEqual(importData.inputBias, 0.0) && Math::RealEqual(importData.inputScale, 1.0))
243 // straight copy
244 memcpy(mHeightData, importData.inputFloat, sizeof(float) * numVertices);
246 else
248 // scale & bias
249 float* src = importData.inputFloat;
250 float* dst = mHeightData;
251 for (size_t i = 0; i < numVertices; ++i)
252 *dst++ = (*src++ * importData.inputScale) + importData.inputBias;
255 else if (importData.inputImage)
257 Image* img = importData.inputImage;
259 if (img->getWidth() != mSize || img->getHeight() != mSize)
260 img->resize(mSize, mSize);
262 // convert image data to floats
263 PixelBox destBox(mSize, mSize, 1, PF_FLOAT32_R, mHeightData);
264 PixelUtil::bulkPixelConversion(img->getPixelBox(), destBox);
266 if (!Math::RealEqual(importData.inputBias, 0.0) || !Math::RealEqual(importData.inputScale, 1.0))
268 float* pAdj = mHeightData;
269 for (size_t i = 0; i < numVertices; ++i)
271 *pAdj = (*pAdj * importData.inputScale) + importData.inputBias;
272 ++pAdj;
277 else
279 // start with flat terrain
280 memset(mHeightData, 0, sizeof(float) * mSize * mSize);
283 mDeltaData = OGRE_ALLOC_T(float, numVertices, MEMCATEGORY_GEOMETRY);
286 mQuadTree = OGRE_NEW TerrainQuadTreeNode(this, 0, 0, 0, mSize, mNumLodLevels - 1, 0, 0);
287 mQuadTree->prepare();
289 // calculate entire terrain
290 Rect rect;
291 rect.top = 0; rect.bottom = mSize;
292 rect.left = 0; rect.right = mSize;
293 calculateHeightDeltas(rect);
296 return true;
299 //---------------------------------------------------------------------
300 void Terrain::determineLodLevels()
302 /* On a leaf-node basis, LOD can vary from maxBatch to minBatch in
303 number of vertices. After that, nodes will be gathered into parent
304 nodes with the same number of vertices, but they are combined with
305 3 of their siblings. In practice, the number of LOD levels overall
307 LODlevels = log2(size - 1) - log2(minBatch - 1) + 1
308 TreeDepth = log2((size - 1) / (maxBatch - 1)) + 1
310 .. it's just that at the max LOD, the terrain is divided into
311 (size - 1) / (maxBatch - 1) tiles each of maxBatch vertices, and
312 at the lowest LOD the terrain is made up of one single tile of
313 minBatch vertices.
315 Example: size = 257, minBatch = 17, maxBatch = 33
317 LODlevels = log2(257 - 1) - log2(17 - 1) + 1 = 8 - 4 + 1 = 5
318 TreeDepth = log2((size - 1) / (maxBatch - 1)) + 1 = 4
320 LOD list - this assumes everything changes at once, which rarely happens of course
321 in fact except where groupings must occur, tiles can change independently
322 LOD 0: 257 vertices, 8 x 33 vertex tiles (tree depth 3)
323 LOD 1: 129 vertices, 8 x 17 vertex tiles (tree depth 3)
324 LOD 2: 65 vertices, 4 x 17 vertex tiles (tree depth 2)
325 LOD 3: 33 vertices, 2 x 17 vertex tiles (tree depth 1)
326 LOD 4: 17 vertices, 1 x 17 vertex tiles (tree depth 0)
328 Notice how we only have 2 sizes of index buffer to be concerned about,
329 17 vertices (per side) or 33. This makes buffer re-use much easier while
330 still giving the full range of LODs.
332 mNumLodLevelsPerLeafNode = Math::Log2(mMaxBatchSize - 1) - Math::Log2(mMinBatchSize - 1) + 1;
333 mNumLodLevels = Math::Log2(mSize - 1) - Math::Log2(mMinBatchSize - 1) + 1;
334 mTreeDepth = Math::Log2(mMaxBatchSize - 1) - Math::Log2(mMinBatchSize - 1) + 2;
336 /* Now we need to figure out how to distribute vertex data. We want to
337 use 16-bit indexes for compatibility, which means that the maximum patch
338 size that we can address (even sparsely for lower LODs) is 129x129
339 (the next one up, 257x257 is too big).
341 So we need to split the vertex data into chunks of 129. The number of
342 primary tiles this creates also indicates the point above which in
343 the node tree that we can no longer merge tiles at lower LODs without
344 using different vertex data. For example, using the 257x257 input example
345 above, the vertex data would have to be split in 2 (in each dimension)
346 in order to fit within the 129x129 range. This data could be shared by
347 all tree depths from 1 onwards, it's just that LODs 3-1 would sample
348 the 129x129 data sparsely. LOD 0 would sample all of the vertices.
350 LOD 4 however, the lowest LOD, could not work with the same vertex data
351 because it needs to cover the entire terrain. There are 2 choices here:
352 create another set of vertex data at 17x17 which is only used by LOD 4,
353 or make LOD 4 occur at tree depth 1 instead (ie still split up, and
354 rendered as 2x9 along each edge instead.
356 Since rendering very small batches is not desirable, and the vertex counts
357 are inherently not going to be large, creating a separate vertex set is
358 preferable. This will also be more efficient on the vertex cache with
359 distant terrains.
361 We probably need a larger example, because in this case only 1 level (LOD 0)
362 needs to use this separate vertex data. Higher detail terrains will need
363 it for multiple levels, here's a 2049x2049 example with 65 / 33 batch settings:
365 LODlevels = log2(2049 - 1) - log2(33 - 1) + 1 = 11 - 5 + 1 = 7
366 TreeDepth = log2((2049 - 1) / (65 - 1)) + 1 = 6
367 Number of vertex data splits at most detailed level:
368 (size - 1) / (TERRAIN_MAX_BATCH_SIZE - 1) = 2048 / 128 = 16
370 LOD 0: 2049 vertices, 32 x 65 vertex tiles (tree depth 5) vdata 0-15 [129x16]
371 LOD 1: 1025 vertices, 32 x 33 vertex tiles (tree depth 5) vdata 0-15 [129x16]
372 LOD 2: 513 vertices, 16 x 33 vertex tiles (tree depth 4) vdata 0-15 [129x16]
373 LOD 3: 257 vertices, 8 x 33 vertex tiles (tree depth 3) vdata 16-17 [129x2]
374 LOD 4: 129 vertices, 4 x 33 vertex tiles (tree depth 2) vdata 16-17 [129x2]
375 LOD 5: 65 vertices, 2 x 33 vertex tiles (tree depth 1) vdata 16-17 [129x2]
376 LOD 6: 33 vertices, 1 x 33 vertex tiles (tree depth 0) vdata 18 [33]
378 All the vertex counts are to be squared, they are just along one edge.
379 So as you can see, we need to have 3 levels of vertex data to satisy this
380 (admittedly quite extreme) case, and a total of 19 sets of vertex data.
381 The full detail geometry, which is 16(x16) sets of 129(x129), used by
382 LODs 0-2. LOD 3 can't use this set because it needs to group across them,
383 because it has only 8 tiles, so we make another set which satisfies this
384 at a maximum of 129 vertices per vertex data section. In this case LOD
385 3 needs 257(x257) total vertices so we still split into 2(x2) sets of 129.
386 This set is good up to and including LOD 5, but LOD 6 needs a single
387 contiguous set of vertices, so we make a 33x33 vertex set for it.
389 In terms of vertex data stored, this means that while our primary data is:
390 2049^2 = 4198401 vertices
391 our final stored vertex data is
392 (16 * 129)^2 + (2 * 129)^2 + 33^2 = 4327749 vertices
394 That equals a 3% premium, but it's both necessary and worth it for the
395 reduction in batch count resulting from the grouping. In addition, at
396 LODs 3 and 6 (or rather tree depth 3 and 0) there is the opportunity
397 to free up the vertex data used by more detailed LODs, which is
398 important when dealing with large terrains. For example, if we
399 freed the (GPU) vertex data for LOD 0-2 in the medium distance,
400 we would save 98% of the memory overhead for this terrain.
404 uint16 depth = mTreeDepth;
405 uint16 prevdepth = depth;
406 uint16 currresolution = mSize;
407 uint16 bakedresolution = mSize;
408 uint16 targetSplits = (bakedresolution - 1) / (TERRAIN_MAX_BATCH_SIZE - 1);
409 while(depth-- && targetSplits)
411 uint splits = 1 << depth;
412 if (splits == targetSplits)
414 // vertex data goes at this level, at bakedresolution
415 // applies to all lower levels (except those with a closer vertex data)
416 mQuadTree->assignVertexData(depth, prevdepth, bakedresolution);
418 // next set to look for
419 bakedresolution = ((currresolution - 1) >> 1) + 1;
420 targetSplits = (bakedresolution - 1) / (TERRAIN_MAX_BATCH_SIZE - 1);
421 prevdepth = depth;
425 currresolution = ((currresolution - 1) >> 1) + 1;
430 // Always assign vertex data to the top of the tree
431 mQuadTree->assignVertexData(0, prevdepth, bakedresolution);
434 //---------------------------------------------------------------------
435 void Terrain::load()
437 if (mQuadTree)
438 mQuadTree->load();
440 //---------------------------------------------------------------------
441 void Terrain::unload()
443 if (mQuadTree)
444 mQuadTree->unload();
446 //---------------------------------------------------------------------
447 void Terrain::unprepare()
449 if (mQuadTree)
450 mQuadTree->unprepare();
452 //---------------------------------------------------------------------
453 float* Terrain::getHeightData()
455 return mHeightData;
457 //---------------------------------------------------------------------
458 float* Terrain::getHeightData(long x, long y)
460 assert (x >= 0 && x < mSize && y >= 0 && y < mSize);
461 return &mHeightData[y * mSize + x];
463 //---------------------------------------------------------------------
464 float Terrain::getHeight(long x, long y)
466 return *getHeightData(x, y);
468 //---------------------------------------------------------------------
469 const float* Terrain::getDeltaData()
471 return mDeltaData;
473 //---------------------------------------------------------------------
474 const float* Terrain::getDeltaData(long x, long y)
476 assert (x >= 0 && x < mSize && y >= 0 && y < mSize);
477 return &mDeltaData[y * mSize + x];
479 //---------------------------------------------------------------------
480 void Terrain::getPoint(long x, long y, Vector3* outpos)
482 getPointAlign(x, y, mAlign, outpos);
484 //---------------------------------------------------------------------
485 void Terrain::getPoint(long x, long y, float height, Vector3* outpos)
487 getPointAlign(x, y, height, mAlign, outpos);
489 //---------------------------------------------------------------------
490 void Terrain::getPointAlign(long x, long y, Alignment align, Vector3* outpos)
492 getPointAlign(x, y, *getHeightData(x, y), align, outpos);
494 //---------------------------------------------------------------------
495 void Terrain::getPointAlign(long x, long y, float height, Alignment align, Vector3* outpos)
497 switch(align)
499 case ALIGN_X_Z:
500 outpos->y = height;
501 outpos->x = x * mScale + mBase;
502 outpos->z = y * mScale + mBase;
503 break;
504 case ALIGN_Y_Z:
505 outpos->x = height;
506 outpos->y = x * mScale + mBase;
507 outpos->z = y * mScale + mBase;
508 break;
509 case ALIGN_X_Y:
510 outpos->z = height;
511 outpos->x = x * mScale + mBase;
512 outpos->y = y * mScale + mBase;
513 break;
517 //---------------------------------------------------------------------
518 void Terrain::getVector(const Vector3& inVec, Vector3* outVec)
520 getVectorAlign(inVec.x, inVec.y, inVec.z, mAlign, outVec);
522 //---------------------------------------------------------------------
523 void Terrain::getVector(Real x, Real y, Real z, Vector3* outVec)
525 getVectorAlign(x, y, z, mAlign, outVec);
527 //---------------------------------------------------------------------
528 void Terrain::getVectorAlign(const Vector3& inVec, Alignment align, Vector3* outVec)
530 getVectorAlign(inVec.x, inVec.y, inVec.z, align, outVec);
532 //---------------------------------------------------------------------
533 void Terrain::getVectorAlign(Real x, Real y, Real z, Alignment align, Vector3* outVec)
536 switch(align)
538 case ALIGN_X_Z:
539 outVec->y = z;
540 outVec->x = x;
541 outVec->z = y;
542 break;
543 case ALIGN_Y_Z:
544 outVec->x = z;
545 outVec->y = x;
546 outVec->z = y;
547 break;
548 case ALIGN_X_Y:
549 outVec->x = x;
550 outVec->y = y;
551 outVec->z = z;
552 break;
556 //---------------------------------------------------------------------
557 Terrain::Alignment Terrain::getAlignment() const
559 return mAlign;
561 //---------------------------------------------------------------------
562 uint16 Terrain::getSize() const
564 return mSize;
566 //---------------------------------------------------------------------
567 uint16 Terrain::getMaxBatchSize() const
569 return mMaxBatchSize;
571 //---------------------------------------------------------------------
572 uint16 Terrain::getMinBatchSize() const
574 return mMinBatchSize;
576 //---------------------------------------------------------------------
577 Real Terrain::getWorldSize() const
579 return mWorldSize;
581 //---------------------------------------------------------------------
582 Real Terrain::getSplatTextureWorldSize(uint16 index) const
584 if (index < mSplatTextureWorldSize.size())
586 return mSplatTextureWorldSize[index];
588 else if (!mSplatTextureWorldSize.empty())
590 return mSplatTextureWorldSize[0];
592 else
594 // default to tile 100 times
595 return mWorldSize * 0.01;
598 //---------------------------------------------------------------------
599 void Terrain::setSplatTextureWorldSize(uint16 index, Real size)
601 if (index >= mSplatTextureWorldSize.size())
603 mSplatTextureWorldSize.resize(index + 1);
604 mSplatTextureUVMultiplier.resize(index + 1);
607 mSplatTextureWorldSize[index] = size;
608 mSplatTextureUVMultiplier[index] = mWorldSize / size;
610 //---------------------------------------------------------------------
611 Real Terrain::getSplatTextureUVMultipler(uint16 index) const
613 if (index < mSplatTextureUVMultiplier.size())
615 return mSplatTextureUVMultiplier[index];
617 else if (!mSplatTextureUVMultiplier.empty())
619 return mSplatTextureUVMultiplier[0];
621 else
623 // default to tile 100 times
624 return 100;
627 //---------------------------------------------------------------------
628 void Terrain::setPosition(const Vector3& pos)
630 mPos = pos;
631 mRootNode->setPosition(pos);
632 updateBaseScale();
634 //---------------------------------------------------------------------
635 void Terrain::updateBaseScale()
637 // centre the terrain on local origin
638 mBase = -mWorldSize * 0.5;
639 // scale determines what 1 unit on the grid becomes in world space
640 mScale = mWorldSize / (Real)mSize;
642 //---------------------------------------------------------------------
643 void Terrain::dirty()
645 // TODO - geometry
647 // calculate entire terrain
648 Rect rect;
649 rect.top = 0; rect.bottom = mSize;
650 rect.left = 0; rect.right = mSize;
651 calculateHeightDeltas(rect);
653 //---------------------------------------------------------------------
654 void Terrain::dirtyRect(const Rect& rect)
656 // TODO - geometry
658 calculateHeightDeltas(rect);
661 //---------------------------------------------------------------------
662 void Terrain::freeCPUResources()
664 OGRE_FREE(mHeightData, MEMCATEGORY_GEOMETRY);
665 mHeightData = 0;
667 OGRE_FREE(mDeltaData, MEMCATEGORY_GEOMETRY);
668 mHeightData = 0;
670 OGRE_DELETE mQuadTree;
671 mQuadTree = 0;
676 //---------------------------------------------------------------------
677 void Terrain::freeGPUResources()
679 // delete batched geometry
681 // SHARE geometry between Terrain instances!
684 //---------------------------------------------------------------------
685 void Terrain::calculateHeightDeltas(const Rect& rect)
687 Rect clampedRect(rect);
688 clampedRect.left = std::max(0L, clampedRect.left);
689 clampedRect.top = std::max(0L, clampedRect.top);
690 clampedRect.right = std::min((long)mSize, clampedRect.right);
691 clampedRect.bottom = std::min((long)mSize, clampedRect.bottom);
693 mQuadTree->preDeltaCalculation(clampedRect);
695 /// Iterate over target levels,
696 for (int targetLevel = 1; targetLevel < mNumLodLevels; ++targetLevel)
698 int sourceLevel = targetLevel - 1;
699 int step = 1 << targetLevel;
700 // The step of the next higher LOD
701 int higherstep = step >> 1;
703 // round the rectangle at this level so that it starts & ends on
704 // the step boundaries
705 Rect lodRect(clampedRect);
706 lodRect.left -= lodRect.left % step;
707 lodRect.top -= lodRect.top % step;
708 if (lodRect.right % step)
709 lodRect.right += step - (lodRect.right % step);
710 if (lodRect.bottom % step)
711 lodRect.bottom += step - (lodRect.bottom % step);
713 for (int j = lodRect.top; j < lodRect.bottom - step; j += step )
715 for (int i = lodRect.left; i < lodRect.right - step; i += step )
717 // Form planes relating to the lower detail tris to be produced
718 // For tri lists and even tri strip rows, they are this shape:
719 // x---x
720 // | / |
721 // x---x
722 // For odd tri strip rows, they are this shape:
723 // x---x
724 // | \ |
725 // x---x
727 Vector3 v1, v2, v3, v4;
728 getPointAlign(i, j, ALIGN_X_Z, &v1);
729 getPointAlign(i + step, j, ALIGN_X_Z, &v2);
730 getPointAlign(i, j + step, ALIGN_X_Z, &v3);
731 getPointAlign(i + step, j + step, ALIGN_X_Z, &v4);
733 Plane t1, t2;
734 bool backwardTri = false;
735 if (!mUseTriangleStrips || j % 2 == 0)
737 t1.redefine(v1, v3, v2);
738 t2.redefine(v2, v3, v4);
740 else
742 t1.redefine(v1, v3, v4);
743 t2.redefine(v1, v4, v2);
744 backwardTri = true;
747 // include the bottommost row of vertices if this is the last row
748 int zubound = (j == (mSize - step)? step : step - 1);
749 for ( int z = 0; z <= zubound; z++ )
751 // include the rightmost col of vertices if this is the last col
752 int xubound = (i == (mSize - step)? step : step - 1);
753 for ( int x = 0; x <= xubound; x++ )
755 int fulldetailx = i + x;
756 int fulldetailz = j + z;
757 if ( fulldetailx % step == 0 &&
758 fulldetailz % step == 0 )
760 // Skip, this one is a vertex at this level
761 continue;
764 Real zpct = (Real)z / (Real)step;
765 Real xpct = (Real)x / (Real)step;
767 //interpolated height
768 Vector3 actualPos;
769 getPointAlign(fulldetailx, fulldetailz, ALIGN_X_Z, &actualPos);
770 Real interp_h;
771 // Determine which tri we're on
772 if ((xpct + zpct <= 1.0f && !backwardTri) ||
773 (xpct + (1-zpct) <= 1.0f && backwardTri))
775 // Solve for x/z
776 interp_h =
777 (-(t1.normal.x * actualPos.x)
778 - t1.normal.z * actualPos.z
779 - t1.d) / t1.normal.y;
781 else
783 // Second tri
784 interp_h =
785 (-(t2.normal.x * actualPos.x)
786 - t2.normal.z * actualPos.z
787 - t2.d) / t2.normal.y;
790 Real actual_h = actualPos.y;
791 Real delta = interp_h - actual_h;
793 // max(delta) is the worst case scenario at this LOD
794 // compared to the original heightmap
796 // tell the quadtree about this
797 mQuadTree->notifyDelta(fulldetailx, fulldetailz, sourceLevel, delta);
800 // If this vertex is being removed at this LOD,
801 // then save the height difference since that's the move
802 // it will need to make. Vertices to be removed at this LOD
803 // are halfway between the steps
804 if ((fulldetailx % step) == step / 2 || (fulldetailz % step) == step / 2)
806 // Save height difference
807 mDeltaData[fulldetailx + (fulldetailz * mSize)] = delta;
813 } // i
814 } // j
815 } // targetLevel
817 mQuadTree->postDeltaCalculation(clampedRect);
821 //---------------------------------------------------------------------
822 uint16 Terrain::getResolutionAtLod(uint16 lodLevel)
824 return ((mSize - 1) >> lodLevel) + 1;
826 //---------------------------------------------------------------------
827 void Terrain::preFindVisibleObjects(SceneManager* source,
828 SceneManager::IlluminationRenderStage irs, Viewport* v)
830 // only calculate LOD on main render passes
831 if (irs == SceneManager::IRS_NONE)
832 calculateCurrentLod(v);
834 //---------------------------------------------------------------------
835 void Terrain::sceneManagerDestroyed(SceneManager* source)
837 unload();
838 unprepare();
839 if (source == mSceneMgr)
840 mSceneMgr = 0;
842 //---------------------------------------------------------------------
843 void Terrain::calculateCurrentLod(Viewport* vp)
845 if (mQuadTree)
847 // calculate error terms
848 const Camera* cam = vp->getCamera()->getLodCamera();
850 // A = 1 / tan(fovy) (== 1 for fovy=45)
851 Real A = 1.0 / Math::Tan(cam->getFOVy());
852 // T = 2 * maxPixelError / vertRes
853 Real maxPixelError = TerrainGlobalOptions::getMaxPixelError() * cam->_getLodBiasInverse();
854 Real T = 2.0 * maxPixelError / (Real)vp->getActualHeight();
856 // CFactor = A / T
857 Real cFactor = A / T;
860 mQuadTree->calculateCurrentLod(cam, cFactor);
863 //---------------------------------------------------------------------
864 std::pair<bool, Vector3> Terrain::rayIntersects(const Ray& ray)
866 typedef std::pair<bool, Vector3> Result;
867 // first step: convert the ray to a local vertex space
868 // we assume terrain to be in the x-z plane, with the [0,0] vertex
869 // at origin and a plane distance of 1 between vertices.
870 // This makes calculations easier.
871 Vector3 rayOrigin = ray.getOrigin() - getPosition();
872 Vector3 rayDirection = ray.getDirection();
873 // relabel axes (probably wrong? need correct coordinate transformation)
874 switch (getAlignment())
876 case ALIGN_X_Y:
877 std::swap(rayOrigin.y, rayOrigin.z);
878 std::swap(rayDirection.y, rayDirection.z);
879 break;
880 case ALIGN_Y_Z:
881 std::swap(rayOrigin.x, rayOrigin.y);
882 std::swap(rayDirection.x, rayDirection.y);
883 break;
884 case ALIGN_X_Z:
885 break;
887 // readjust coordinate origin
888 rayOrigin.x += mWorldSize/2;
889 rayOrigin.z += mWorldSize/2;
890 // scale down to vertex level
891 rayOrigin.x /= mScale;
892 rayOrigin.z /= mScale;
893 rayDirection.x /= mScale;
894 rayDirection.z /= mScale;
895 rayDirection.normalise();
896 Ray localRay (rayOrigin, rayDirection);
898 // test if the ray actually hits the terrain's bounds
899 // TODO: Replace y values with actual heightmap height limits
900 AxisAlignedBox aabb (Vector3(0, 0, 0), Vector3(mSize, 1000000, mSize));
901 std::pair<bool, Real> aabbTest = localRay.intersects(aabb);
902 if (!aabbTest.first)
903 return Result(false, Vector3());
904 // get intersection point and move inside
905 Vector3 cur = localRay.getPoint(aabbTest.second);
907 // now check every quad the ray touches
908 int quadX = std::min(std::max(static_cast<int>(cur.x), 0), (int)mSize-2);
909 int quadZ = std::min(std::max(static_cast<int>(cur.z), 0), (int)mSize-2);
910 int flipX = (rayDirection.x < 0 ? 0 : 1);
911 int flipZ = (rayDirection.z < 0 ? 0 : 1);
912 int xDir = (rayDirection.x < 0 ? -1 : 1);
913 int zDir = (rayDirection.z < 0 ? -1 : 1);
914 Result result;
915 while (cur.y >= -1 && cur.y <= 2)
917 if (quadX < 0 || quadX >= (int)mSize-1 || quadZ < 0 || quadZ >= (int)mSize-1)
918 break;
920 result = checkQuadIntersection(quadX, quadZ, localRay);
921 if (result.first)
922 break;
924 // determine next quad to test
925 Real xDist = (quadX - cur.x + flipX) / rayDirection.x;
926 Real zDist = (quadZ - cur.z + flipZ) / rayDirection.z;
927 if (xDist < zDist)
929 quadX += xDir;
930 cur += rayDirection * xDist;
932 else
934 quadZ += zDir;
935 cur += rayDirection * zDist;
940 if (result.first)
942 // transform the point of intersection back to world space
943 result.second.x *= mScale;
944 result.second.z *= mScale;
945 result.second.x -= mWorldSize/2;
946 result.second.z -= mWorldSize/2;
947 switch (getAlignment())
949 case ALIGN_X_Y:
950 std::swap(result.second.y, result.second.z);
951 break;
952 case ALIGN_Y_Z:
953 std::swap(result.second.x, result.second.y);
954 break;
955 case ALIGN_X_Z:
956 break;
958 result.second += getPosition();
960 return result;
962 //---------------------------------------------------------------------
963 std::pair<bool, Vector3> Terrain::checkQuadIntersection(int x, int z, const Ray& ray)
965 // build the two planes belonging to the quad's triangles
966 Vector3 v1 (x, *getHeightData(x,z), z);
967 Vector3 v2 (x+1, *getHeightData(x+1,z), z);
968 Vector3 v3 (x, *getHeightData(x,z+1), z+1);
969 Vector3 v4 (x+1, *getHeightData(x+1,z+1), z+1);
970 // TODO: Is this the correct triangle order?
971 Plane p1 (v1, v3, v2);
972 Plane p2 (v3, v4, v2);
974 // Test for intersection with the two planes.
975 // Then test that the intersection points are actually
976 // still inside the triangle (with a small error margin)
977 std::pair<bool, Real> planeInt = ray.intersects(p1);
978 if (planeInt.first)
980 Vector3 where = ray.getPoint(planeInt.second);
981 Vector3 rel = where - v1;
982 if (rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 && rel.x+rel.z <= 1.01)
983 return std::pair<bool, Vector3>(true, where);
985 planeInt = ray.intersects(p2);
986 if (planeInt.first)
988 Vector3 where = ray.getPoint(planeInt.second);
989 Vector3 rel = where - v1;
990 if (rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 && rel.x+rel.z >= 0.99)
991 return std::pair<bool, Vector3>(true, where);
994 return std::pair<bool, Vector3>(false, Vector3());