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 Also see acknowledgements in Readme.html 9 10 You may use this sample code for anything you like, it is not covered by the 11 same license as the rest of the engine. 12 ----------------------------------------------------------------------------- 13 */ 14 #ifndef __Terrain_H__ 15 #define __Terrain_H__ 16 17 //#define PAGING 18 19 #define TERRAIN_PAGE_MIN_X 0 20 #define TERRAIN_PAGE_MIN_Y 0 21 #define TERRAIN_PAGE_MAX_X 0 22 #define TERRAIN_PAGE_MAX_Y 0 23 24 #include "SdkSample.h" 25 #include "OgrePageManager.h" 26 #include "OgreTerrain.h" 27 #include "OgreTerrainGroup.h" 28 #include "OgreTerrainQuadTreeNode.h" 29 #include "OgreTerrainMaterialGeneratorA.h" 30 #include "OgreTerrainPaging.h" 31 32 #define TERRAIN_FILE_PREFIX String("testTerrain") 33 #define TERRAIN_FILE_SUFFIX String("dat") 34 #define TERRAIN_WORLD_SIZE 12000.0f 35 #define TERRAIN_SIZE 513 36 37 using namespace Ogre; 38 using namespace OgreBites; 39 40 class _OgreSampleClassExport Sample_Terrain : public SdkSample 41 { 42 public: 43 Sample_Terrain()44 Sample_Terrain() 45 : mTerrainGlobals(0) 46 , mTerrainGroup(0) 47 , mTerrainPaging(0) 48 , mPageManager(0) 49 , mFly(false) 50 , mFallVelocity(0) 51 , mMode(MODE_NORMAL) 52 , mLayerEdit(1) 53 , mBrushSizeTerrainSpace(0.02) 54 , mHeightUpdateCountDown(0) 55 , mTerrainPos(1000,0,5000) 56 , mTerrainsImported(false) 57 , mKeyPressed(0) 58 59 { 60 mInfo["Title"] = "Terrain"; 61 mInfo["Description"] = "Demonstrates use of the terrain rendering plugin."; 62 mInfo["Thumbnail"] = "thumb_terrain.png"; 63 mInfo["Category"] = "Environment"; 64 mInfo["Help"] = "Left click and drag anywhere in the scene to look around. Let go again to show " 65 "cursor and access widgets. Use WASD keys to move. Use +/- keys when in edit mode to change content."; 66 67 // Update terrain at max 20fps 68 mHeightUpdateRate = 1.0 / 20.0; 69 } 70 testCapabilities(const RenderSystemCapabilities * caps)71 void testCapabilities(const RenderSystemCapabilities* caps) 72 { 73 if (!caps->hasCapability(RSC_VERTEX_PROGRAM) || !caps->hasCapability(RSC_FRAGMENT_PROGRAM)) 74 { 75 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your graphics card does not support vertex or fragment shaders, " 76 "so you cannot run this sample. Sorry!", "Sample_Terrain::testCapabilities"); 77 } 78 } 79 getRequiredPlugins()80 StringVector getRequiredPlugins() 81 { 82 StringVector names; 83 if (!GpuProgramManager::getSingleton().isSyntaxSupported("glsles") && 84 !GpuProgramManager::getSingleton().isSyntaxSupported("glsl") && 85 !GpuProgramManager::getSingleton().isSyntaxSupported("hlsl")) 86 names.push_back("Cg Program Manager"); 87 return names; 88 } 89 doTerrainModify(Terrain * terrain,const Vector3 & centrepos,Real timeElapsed)90 void doTerrainModify(Terrain* terrain, const Vector3& centrepos, Real timeElapsed) 91 { 92 Vector3 tsPos; 93 terrain->getTerrainPosition(centrepos, &tsPos); 94 #if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS 95 if (mKeyPressed == '+' || mKeyPressed == '-' || mKeyPressed == SDLK_KP_PLUS || 96 mKeyPressed == SDLK_KP_MINUS) 97 { 98 switch(mMode) 99 { 100 case MODE_EDIT_HEIGHT: 101 { 102 // we need point coords 103 Real terrainSize = (terrain->getSize() - 1); 104 long startx = (tsPos.x - mBrushSizeTerrainSpace) * terrainSize; 105 long starty = (tsPos.y - mBrushSizeTerrainSpace) * terrainSize; 106 long endx = (tsPos.x + mBrushSizeTerrainSpace) * terrainSize; 107 long endy= (tsPos.y + mBrushSizeTerrainSpace) * terrainSize; 108 startx = std::max(startx, 0L); 109 starty = std::max(starty, 0L); 110 endx = std::min(endx, (long)terrainSize); 111 endy = std::min(endy, (long)terrainSize); 112 for (long y = starty; y <= endy; ++y) 113 { 114 for (long x = startx; x <= endx; ++x) 115 { 116 Real tsXdist = (x / terrainSize) - tsPos.x; 117 Real tsYdist = (y / terrainSize) - tsPos.y; 118 119 Real weight = std::min((Real)1.0, 120 Math::Sqrt(tsYdist * tsYdist + tsXdist * tsXdist) / Real(0.5 * mBrushSizeTerrainSpace)); 121 weight = 1.0 - (weight * weight); 122 123 float addedHeight = weight * 250.0 * timeElapsed; 124 float newheight; 125 if (mKeyPressed == '+' || mKeyPressed == SDLK_KP_PLUS) 126 newheight = terrain->getHeightAtPoint(x, y) + addedHeight; 127 else 128 newheight = terrain->getHeightAtPoint(x, y) - addedHeight; 129 terrain->setHeightAtPoint(x, y, newheight); 130 131 } 132 } 133 if (mHeightUpdateCountDown == 0) 134 mHeightUpdateCountDown = mHeightUpdateRate; 135 } 136 break; 137 case MODE_EDIT_BLEND: 138 { 139 TerrainLayerBlendMap* layer = terrain->getLayerBlendMap(mLayerEdit); 140 // we need image coords 141 Real imgSize = terrain->getLayerBlendMapSize(); 142 long startx = (tsPos.x - mBrushSizeTerrainSpace) * imgSize; 143 long starty = (tsPos.y - mBrushSizeTerrainSpace) * imgSize; 144 long endx = (tsPos.x + mBrushSizeTerrainSpace) * imgSize; 145 long endy= (tsPos.y + mBrushSizeTerrainSpace) * imgSize; 146 startx = std::max(startx, 0L); 147 starty = std::max(starty, 0L); 148 endx = std::min(endx, (long)imgSize); 149 endy = std::min(endy, (long)imgSize); 150 for (long y = starty; y <= endy; ++y) 151 { 152 for (long x = startx; x <= endx; ++x) 153 { 154 Real tsXdist = (x / imgSize) - tsPos.x; 155 Real tsYdist = (y / imgSize) - tsPos.y; 156 157 Real weight = std::min((Real)1.0, 158 Math::Sqrt(tsYdist * tsYdist + tsXdist * tsXdist) / Real(0.5 * mBrushSizeTerrainSpace)); 159 weight = 1.0 - (weight * weight); 160 161 float paint = weight * timeElapsed; 162 size_t imgY = imgSize - y; 163 float val; 164 if (mKeyPressed == '+' || mKeyPressed == SDLK_KP_PLUS) 165 val = layer->getBlendValue(x, imgY) + paint; 166 else 167 val = layer->getBlendValue(x, imgY) - paint; 168 val = Math::Clamp(val, 0.0f, 1.0f); 169 layer->setBlendValue(x, imgY, val); 170 171 } 172 } 173 174 layer->update(); 175 } 176 break; 177 case MODE_NORMAL: 178 case MODE_COUNT: 179 break; 180 }; 181 } 182 #endif 183 184 } frameRenderingQueued(const FrameEvent & evt)185 bool frameRenderingQueued(const FrameEvent& evt) 186 { 187 if (mMode != MODE_NORMAL) 188 { 189 // fire ray 190 Ray ray; 191 //ray = mCamera->getCameraToViewportRay(0.5, 0.5); 192 ray = mTrayMgr->getCursorRay(mCamera); 193 194 TerrainGroup::RayResult rayResult = mTerrainGroup->rayIntersects(ray); 195 if (rayResult.hit) 196 { 197 mEditMarker->setVisible(true); 198 mEditNode->setPosition(rayResult.position); 199 200 // figure out which terrains this affects 201 TerrainGroup::TerrainList terrainList; 202 Real brushSizeWorldSpace = TERRAIN_WORLD_SIZE * mBrushSizeTerrainSpace; 203 Sphere sphere(rayResult.position, brushSizeWorldSpace); 204 mTerrainGroup->sphereIntersects(sphere, &terrainList); 205 206 for (TerrainGroup::TerrainList::iterator ti = terrainList.begin(); 207 ti != terrainList.end(); ++ti) 208 doTerrainModify(*ti, rayResult.position, evt.timeSinceLastFrame); 209 } 210 else 211 { 212 mEditMarker->setVisible(false); 213 } 214 } 215 216 if (!mFly) 217 { 218 // clamp to terrain 219 Vector3 camPos = mCameraNode->getPosition(); 220 Ray ray; 221 ray.setOrigin(Vector3(camPos.x, mTerrainPos.y + 10000, camPos.z)); 222 ray.setDirection(Vector3::NEGATIVE_UNIT_Y); 223 224 TerrainGroup::RayResult rayResult = mTerrainGroup->rayIntersects(ray); 225 Real distanceAboveTerrain = 50; 226 Real fallSpeed = 300; 227 Real newy = camPos.y; 228 if (rayResult.hit) 229 { 230 if (camPos.y > rayResult.position.y + distanceAboveTerrain) 231 { 232 mFallVelocity += evt.timeSinceLastFrame * 20; 233 mFallVelocity = std::min(mFallVelocity, fallSpeed); 234 newy = camPos.y - mFallVelocity * evt.timeSinceLastFrame; 235 236 } 237 newy = std::max(rayResult.position.y + distanceAboveTerrain, newy); 238 mCameraNode->setPosition(camPos.x, newy, camPos.z); 239 240 } 241 242 } 243 244 if (mHeightUpdateCountDown > 0) 245 { 246 mHeightUpdateCountDown -= evt.timeSinceLastFrame; 247 if (mHeightUpdateCountDown <= 0) 248 { 249 mTerrainGroup->update(); 250 mHeightUpdateCountDown = 0; 251 252 } 253 } 254 255 if (mTerrainGroup->isDerivedDataUpdateInProgress()) 256 { 257 mTrayMgr->moveWidgetToTray(mInfoLabel, TL_TOP, 0); 258 mInfoLabel->show(); 259 if (mTerrainsImported) 260 { 261 mInfoLabel->setCaption("Building terrain, please wait..."); 262 } 263 else 264 { 265 mInfoLabel->setCaption("Updating textures, patience..."); 266 } 267 } 268 else 269 { 270 mTrayMgr->removeWidgetFromTray(mInfoLabel); 271 mInfoLabel->hide(); 272 if (mTerrainsImported) 273 { 274 saveTerrains(true); 275 mTerrainsImported = false; 276 } 277 } 278 279 return SdkSample::frameRenderingQueued(evt); // don't forget the parent updates! 280 } 281 saveTerrains(bool onlyIfModified)282 void saveTerrains(bool onlyIfModified) 283 { 284 mTerrainGroup->saveAllTerrains(onlyIfModified); 285 } 286 keyReleased(const KeyboardEvent & evt)287 bool keyReleased(const KeyboardEvent& evt) 288 { 289 mKeyPressed = 0; 290 return SdkSample::keyReleased(evt); 291 } 292 keyPressed(const KeyboardEvent & e)293 bool keyPressed (const KeyboardEvent &e) 294 { 295 #if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS 296 mKeyPressed = e.keysym.sym; 297 298 switch (e.keysym.sym) 299 { 300 case 's': 301 // CTRL-S to save 302 if (e.keysym.mod & KMOD_CTRL) 303 { 304 saveTerrains(true); 305 } 306 else 307 return SdkSample::keyPressed(e); 308 break; 309 case SDLK_F10: 310 // dump 311 { 312 TerrainGroup::TerrainIterator ti = mTerrainGroup->getTerrainIterator(); 313 while (ti.hasMoreElements()) 314 { 315 Ogre::uint32 tkey = ti.peekNextKey(); 316 TerrainGroup::TerrainSlot* ts = ti.getNext(); 317 if (ts->instance && ts->instance->isLoaded()) 318 { 319 ts->instance->_dumpTextures("terrain_" + StringConverter::toString(tkey), ".png"); 320 } 321 } 322 } 323 break; 324 /* 325 case SDLK_F7: 326 // change terrain size 327 if (mTerrainGroup->getTerrainSize() == 513) 328 mTerrainGroup->setTerrainSize(1025); 329 else 330 mTerrainGroup->setTerrainSize(513); 331 break; 332 case SDLK_F8: 333 // change terrain world size 334 if (mTerrainGroup->getTerrainWorldSize() == TERRAIN_WORLD_SIZE) 335 mTerrainGroup->setTerrainWorldSize(TERRAIN_WORLD_SIZE * 2); 336 else 337 mTerrainGroup->setTerrainWorldSize(TERRAIN_WORLD_SIZE); 338 break; 339 */ 340 default: 341 return SdkSample::keyPressed(e); 342 } 343 #endif 344 345 return true; 346 } 347 itemSelected(SelectMenu * menu)348 void itemSelected(SelectMenu* menu) 349 { 350 if (menu == mEditMenu) 351 { 352 mMode = (Mode)mEditMenu->getSelectionIndex(); 353 } 354 else if (menu == mShadowsMenu) 355 { 356 mShadowMode = (ShadowMode)mShadowsMenu->getSelectionIndex(); 357 changeShadows(); 358 } 359 } 360 checkBoxToggled(CheckBox * box)361 void checkBoxToggled(CheckBox* box) 362 { 363 if (box == mFlyBox) 364 { 365 mFly = mFlyBox->isChecked(); 366 } 367 } 368 369 protected: 370 371 TerrainGlobalOptions* mTerrainGlobals; 372 TerrainGroup* mTerrainGroup; 373 bool mPaging; 374 TerrainPaging* mTerrainPaging; 375 PageManager* mPageManager; 376 #ifdef PAGING 377 /// This class just pretends to provide prcedural page content to avoid page loading 378 class DummyPageProvider : public PageProvider 379 { 380 public: prepareProceduralPage(Page * page,PagedWorldSection * section)381 bool prepareProceduralPage(Page* page, PagedWorldSection* section) { return true; } loadProceduralPage(Page * page,PagedWorldSection * section)382 bool loadProceduralPage(Page* page, PagedWorldSection* section) { return true; } unloadProceduralPage(Page * page,PagedWorldSection * section)383 bool unloadProceduralPage(Page* page, PagedWorldSection* section) { return true; } unprepareProceduralPage(Page * page,PagedWorldSection * section)384 bool unprepareProceduralPage(Page* page, PagedWorldSection* section) { return true; } 385 }; 386 DummyPageProvider mDummyPageProvider; 387 #endif 388 bool mFly; 389 Real mFallVelocity; 390 enum Mode 391 { 392 MODE_NORMAL = 0, 393 MODE_EDIT_HEIGHT = 1, 394 MODE_EDIT_BLEND = 2, 395 MODE_COUNT = 3 396 }; 397 enum ShadowMode 398 { 399 SHADOWS_NONE = 0, 400 SHADOWS_COLOUR = 1, 401 SHADOWS_DEPTH = 2, 402 SHADOWS_COUNT = 3 403 }; 404 Mode mMode; 405 ShadowMode mShadowMode; 406 Ogre::uint8 mLayerEdit; 407 Real mBrushSizeTerrainSpace; 408 SceneNode* mEditNode; 409 Entity* mEditMarker; 410 Real mHeightUpdateCountDown; 411 Real mHeightUpdateRate; 412 Vector3 mTerrainPos; 413 SelectMenu* mEditMenu; 414 SelectMenu* mShadowsMenu; 415 CheckBox* mFlyBox; 416 OgreBites::Label* mInfoLabel; 417 bool mTerrainsImported; 418 ShadowCameraSetupPtr mPSSMSetup; 419 420 typedef std::list<Entity*> EntityList; 421 EntityList mHouseList; 422 423 Keycode mKeyPressed; 424 425 void defineTerrain(long x, long y, bool flat = false) 426 { 427 // if a file is available, use it 428 // if not, generate file from import 429 430 // Usually in a real project you'll know whether the compact terrain data is 431 // available or not; I'm doing it this way to save distribution size 432 433 if (flat) 434 { 435 mTerrainGroup->defineTerrain(x, y, 0.0f); 436 } 437 else 438 { 439 String filename = mTerrainGroup->generateFilename(x, y); 440 if (ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(), filename)) 441 { 442 mTerrainGroup->defineTerrain(x, y); 443 } 444 else 445 { 446 Image img; 447 getTerrainImage(x % 2 != 0, y % 2 != 0, img); 448 mTerrainGroup->defineTerrain(x, y, &img); 449 mTerrainsImported = true; 450 } 451 } 452 } 453 getTerrainImage(bool flipX,bool flipY,Image & img)454 void getTerrainImage(bool flipX, bool flipY, Image& img) 455 { 456 img.load("terrain.png", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); 457 if (flipX) 458 img.flipAroundY(); 459 if (flipY) 460 img.flipAroundX(); 461 } 462 initBlendMaps(Terrain * terrain)463 void initBlendMaps(Terrain* terrain) 464 { 465 TerrainLayerBlendMap* blendMap0 = terrain->getLayerBlendMap(1); 466 TerrainLayerBlendMap* blendMap1 = terrain->getLayerBlendMap(2); 467 Real minHeight0 = 70; 468 Real fadeDist0 = 40; 469 Real minHeight1 = 70; 470 Real fadeDist1 = 15; 471 float* pBlend1 = blendMap1->getBlendPointer(); 472 for (Ogre::uint16 y = 0; y < terrain->getLayerBlendMapSize(); ++y) 473 { 474 for (Ogre::uint16 x = 0; x < terrain->getLayerBlendMapSize(); ++x) 475 { 476 Real tx, ty; 477 478 blendMap0->convertImageToTerrainSpace(x, y, &tx, &ty); 479 Real height = terrain->getHeightAtTerrainPosition(tx, ty); 480 Real val = (height - minHeight0) / fadeDist0; 481 Math::Clamp(val, (Real)0, (Real)1); 482 483 val = (height - minHeight1) / fadeDist1; 484 val = Math::Clamp(val, (Real)0, (Real)1); 485 *pBlend1++ = val; 486 487 488 } 489 } 490 blendMap0->dirty(); 491 blendMap1->dirty(); 492 //blendMap0->loadImage("blendmap1.png", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); 493 blendMap0->update(); 494 blendMap1->update(); 495 496 // set up a colour map 497 /* 498 if (!terrain->getGlobalColourMapEnabled()) 499 { 500 terrain->setGlobalColourMapEnabled(true); 501 Image colourMap; 502 colourMap.load("testcolourmap.jpg", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); 503 terrain->getGlobalColourMap()->loadImage(colourMap); 504 } 505 */ 506 } 507 configureTerrainDefaults(Light * l)508 void configureTerrainDefaults(Light* l) 509 { 510 // Configure global 511 mTerrainGlobals->setMaxPixelError(8); 512 // testing composite map 513 mTerrainGlobals->setCompositeMapDistance(3000); 514 //mTerrainGlobals->setUseRayBoxDistanceCalculation(true); 515 //mTerrainGlobals->getDefaultMaterialGenerator()->setDebugLevel(1); 516 //mTerrainGlobals->setLightMapSize(256); 517 518 // Disable the lightmap for OpenGL ES 2.0. The minimum number of samplers allowed is 8(as opposed to 16 on desktop). 519 // Otherwise we will run over the limit by just one. The minimum was raised to 16 in GL ES 3.0. 520 if (Ogre::Root::getSingletonPtr()->getRenderSystem()->getCapabilities()->getNumTextureUnits() < 9) 521 { 522 TerrainMaterialGeneratorA::SM2Profile* matProfile = 523 static_cast<TerrainMaterialGeneratorA::SM2Profile*>(mTerrainGlobals->getDefaultMaterialGenerator()->getActiveProfile()); 524 matProfile->setLightmapEnabled(false); 525 } 526 527 // Important to set these so that the terrain knows what to use for derived (non-realtime) data 528 mTerrainGlobals->setLightMapDirection(l->getDerivedDirection()); 529 mTerrainGlobals->setCompositeMapAmbient(mSceneMgr->getAmbientLight()); 530 //mTerrainGlobals->setCompositeMapAmbient(ColourValue::Red); 531 mTerrainGlobals->setCompositeMapDiffuse(l->getDiffuseColour()); 532 533 // Configure default import settings for if we use imported image 534 Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings(); 535 defaultimp.terrainSize = TERRAIN_SIZE; 536 defaultimp.worldSize = TERRAIN_WORLD_SIZE; 537 defaultimp.inputScale = 600; 538 defaultimp.minBatchSize = 33; 539 defaultimp.maxBatchSize = 65; 540 // textures 541 defaultimp.layerList.resize(3); 542 defaultimp.layerList[0].worldSize = 100; 543 defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_diffusespecular.dds"); 544 defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_normalheight.dds"); 545 defaultimp.layerList[1].worldSize = 30; 546 defaultimp.layerList[1].textureNames.push_back("grass_green-01_diffusespecular.dds"); 547 defaultimp.layerList[1].textureNames.push_back("grass_green-01_normalheight.dds"); 548 defaultimp.layerList[2].worldSize = 200; 549 defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_diffusespecular.dds"); 550 defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_normalheight.dds"); 551 } 552 addTextureShadowDebugOverlay(TrayLocation loc,size_t num)553 void addTextureShadowDebugOverlay(TrayLocation loc, size_t num) 554 { 555 for (size_t i = 0; i < num; ++i) 556 { 557 TexturePtr shadowTex = mSceneMgr->getShadowTexture(i); 558 addTextureDebugOverlay(loc, shadowTex, i); 559 } 560 } 561 buildDepthShadowMaterial(const String & textureName)562 MaterialPtr buildDepthShadowMaterial(const String& textureName) 563 { 564 String matName = "DepthShadows/" + textureName; 565 566 MaterialPtr ret = MaterialManager::getSingleton().getByName(matName); 567 if (!ret) 568 { 569 MaterialPtr baseMat = MaterialManager::getSingleton().getByName("Ogre/shadow/depth/integrated/pssm"); 570 ret = baseMat->clone(matName); 571 Pass* p = ret->getTechnique(0)->getPass(0); 572 p->getTextureUnitState("diffuse")->setTextureName(textureName); 573 574 Vector4 splitPoints; 575 const PSSMShadowCameraSetup::SplitPointList& splitPointList = 576 static_cast<PSSMShadowCameraSetup*>(mPSSMSetup.get())->getSplitPoints(); 577 for (int i = 0; i < 3; ++i) 578 { 579 splitPoints[i] = splitPointList[i]; 580 } 581 p->getFragmentProgramParameters()->setNamedConstant("pssmSplitPoints", splitPoints); 582 } 583 584 return ret; 585 } 586 changeShadows()587 void changeShadows() 588 { 589 configureShadows(mShadowMode != SHADOWS_NONE, mShadowMode == SHADOWS_DEPTH); 590 } 591 configureShadows(bool enabled,bool depthShadows)592 void configureShadows(bool enabled, bool depthShadows) 593 { 594 TerrainMaterialGeneratorA::SM2Profile* matProfile = 595 static_cast<TerrainMaterialGeneratorA::SM2Profile*>(mTerrainGlobals->getDefaultMaterialGenerator()->getActiveProfile()); 596 matProfile->setReceiveDynamicShadowsEnabled(enabled); 597 #ifdef SHADOWS_IN_LOW_LOD_MATERIAL 598 matProfile->setReceiveDynamicShadowsLowLod(true); 599 #else 600 matProfile->setReceiveDynamicShadowsLowLod(false); 601 #endif 602 603 // Default materials 604 for (EntityList::iterator i = mHouseList.begin(); i != mHouseList.end(); ++i) 605 { 606 (*i)->setMaterialName("Examples/TudorHouse"); 607 } 608 609 if (enabled) 610 { 611 // General scene setup 612 mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED); 613 mSceneMgr->setShadowFarDistance(3000); 614 615 // 3 textures per directional light (PSSM) 616 mSceneMgr->setShadowTextureCountPerLightType(Ogre::Light::LT_DIRECTIONAL, 3); 617 618 if (!mPSSMSetup) 619 { 620 // shadow camera setup 621 PSSMShadowCameraSetup* pssmSetup = new PSSMShadowCameraSetup(); 622 pssmSetup->setSplitPadding(mCamera->getNearClipDistance()); 623 pssmSetup->calculateSplitPoints(3, mCamera->getNearClipDistance(), mSceneMgr->getShadowFarDistance()); 624 pssmSetup->setOptimalAdjustFactor(0, 2); 625 pssmSetup->setOptimalAdjustFactor(1, 1); 626 pssmSetup->setOptimalAdjustFactor(2, 0.5); 627 628 mPSSMSetup.reset(pssmSetup); 629 } 630 mSceneMgr->setShadowCameraSetup(mPSSMSetup); 631 632 if (depthShadows) 633 { 634 mSceneMgr->setShadowTextureCount(3); 635 mSceneMgr->setShadowTextureConfig(0, 2048, 2048, PF_FLOAT32_R); 636 mSceneMgr->setShadowTextureConfig(1, 1024, 1024, PF_FLOAT32_R); 637 mSceneMgr->setShadowTextureConfig(2, 1024, 1024, PF_FLOAT32_R); 638 mSceneMgr->setShadowTextureSelfShadow(true); 639 mSceneMgr->setShadowCasterRenderBackFaces(true); 640 641 MaterialPtr houseMat = buildDepthShadowMaterial("fw12b.jpg"); 642 for (EntityList::iterator i = mHouseList.begin(); i != mHouseList.end(); ++i) 643 { 644 (*i)->setMaterial(houseMat); 645 } 646 } 647 else 648 { 649 mSceneMgr->setShadowTextureCount(3); 650 mSceneMgr->setShadowTextureConfig(0, 2048, 2048, PF_X8B8G8R8); 651 mSceneMgr->setShadowTextureConfig(1, 1024, 1024, PF_X8B8G8R8); 652 mSceneMgr->setShadowTextureConfig(2, 1024, 1024, PF_X8B8G8R8); 653 mSceneMgr->setShadowTextureSelfShadow(false); 654 mSceneMgr->setShadowCasterRenderBackFaces(false); 655 mSceneMgr->setShadowTextureCasterMaterial(MaterialPtr()); 656 } 657 658 matProfile->setReceiveDynamicShadowsDepth(depthShadows); 659 matProfile->setReceiveDynamicShadowsPSSM(static_cast<PSSMShadowCameraSetup*>(mPSSMSetup.get())); 660 661 //addTextureShadowDebugOverlay(TL_RIGHT, 3); 662 } 663 else 664 { 665 mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE); 666 } 667 668 669 } 670 671 /*----------------------------------------------------------------------------- 672 | Extends setupView to change some initial camera settings for this sample. 673 -----------------------------------------------------------------------------*/ setupView()674 void setupView() 675 { 676 SdkSample::setupView(); 677 678 mCameraNode->setPosition(mTerrainPos + Vector3(1683, 50, 2116)); 679 mCameraNode->lookAt(Vector3(1963, 50, 1660), Node::TS_PARENT); 680 mCamera->setNearClipDistance(0.1); 681 mCamera->setFarClipDistance(50000); 682 683 if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE)) 684 { 685 mCamera->setFarClipDistance(0); // enable infinite far clip distance if we can 686 } 687 } 688 setupControls()689 void setupControls() 690 { 691 mTrayMgr->showCursor(); 692 693 // make room for the controls 694 mTrayMgr->showLogo(TL_TOPRIGHT); 695 mTrayMgr->showFrameStats(TL_TOPRIGHT); 696 mTrayMgr->toggleAdvancedFrameStats(); 697 698 mInfoLabel = mTrayMgr->createLabel(TL_TOP, "TInfo", "", 350); 699 700 mEditMenu = mTrayMgr->createLongSelectMenu(TL_BOTTOM, "EditMode", "Edit Mode", 370, 250, 3); 701 mEditMenu->addItem("None"); 702 mEditMenu->addItem("Elevation"); 703 mEditMenu->addItem("Blend"); 704 mEditMenu->selectItem(0); // no edit mode 705 706 mFlyBox = mTrayMgr->createCheckBox(TL_BOTTOM, "Fly", "Fly"); 707 mFlyBox->setChecked(false, false); 708 709 mShadowsMenu = mTrayMgr->createLongSelectMenu(TL_BOTTOM, "Shadows", "Shadows", 370, 250, 3); 710 mShadowsMenu->addItem("None"); 711 mShadowsMenu->addItem("Colour Shadows"); 712 mShadowsMenu->addItem("Depth Shadows"); 713 mShadowsMenu->selectItem(0); // no edit mode 714 715 // a friendly reminder 716 StringVector names; 717 names.push_back("Help"); 718 mTrayMgr->createParamsPanel(TL_TOPLEFT, "Help", 100, names)->setParamValue(0, "H/F1"); 719 } 720 setupContent()721 void setupContent() 722 { 723 bool blankTerrain = false; 724 //blankTerrain = true; 725 726 mTerrainGlobals = OGRE_NEW TerrainGlobalOptions(); 727 728 // Bugfix for D3D11 Render System because of pixel format incompatibility when using 729 // vertex compression 730 if (Ogre::Root::getSingleton().getRenderSystem()->getName() == "Direct3D11 Rendering Subsystem") 731 mTerrainGlobals->setUseVertexCompressionWhenAvailable(false); 732 733 mEditMarker = mSceneMgr->createEntity("editMarker", "sphere.mesh"); 734 mEditNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); 735 mEditNode->attachObject(mEditMarker); 736 mEditNode->setScale(0.05, 0.05, 0.05); 737 738 setupControls(); 739 740 mCameraMan->setTopSpeed(50); 741 742 setDragLook(true); 743 744 MaterialManager::getSingleton().setDefaultTextureFiltering(TFO_ANISOTROPIC); 745 MaterialManager::getSingleton().setDefaultAnisotropy(7); 746 747 mSceneMgr->setFog(FOG_LINEAR, ColourValue(0.7, 0.7, 0.8), 0, 10000, 25000); 748 749 LogManager::getSingleton().setLogDetail(LL_BOREME); 750 751 Vector3 lightdir(0.55, -0.3, 0.75); 752 lightdir.normalise(); 753 754 Light* l = mSceneMgr->createLight("tstLight"); 755 l->setType(Light::LT_DIRECTIONAL); 756 l->setDirection(lightdir); 757 l->setDiffuseColour(ColourValue::White); 758 l->setSpecularColour(ColourValue(0.4, 0.4, 0.4)); 759 760 mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2)); 761 762 mTerrainGroup = OGRE_NEW TerrainGroup(mSceneMgr, Terrain::ALIGN_X_Z, TERRAIN_SIZE, TERRAIN_WORLD_SIZE); 763 mTerrainGroup->setFilenameConvention(TERRAIN_FILE_PREFIX, TERRAIN_FILE_SUFFIX); 764 mTerrainGroup->setOrigin(mTerrainPos); 765 766 configureTerrainDefaults(l); 767 #ifdef PAGING 768 // Paging setup 769 mPageManager = OGRE_NEW PageManager(); 770 // Since we're not loading any pages from .page files, we need a way just 771 // to say we've loaded them without them actually being loaded 772 mPageManager->setPageProvider(&mDummyPageProvider); 773 mPageManager->addCamera(mCamera); 774 mTerrainPaging = OGRE_NEW TerrainPaging(mPageManager); 775 PagedWorld* world = mPageManager->createWorld(); 776 mTerrainPaging->createWorldSection(world, mTerrainGroup, 2000, 3000, 777 TERRAIN_PAGE_MIN_X, TERRAIN_PAGE_MIN_Y, 778 TERRAIN_PAGE_MAX_X, TERRAIN_PAGE_MAX_Y); 779 #else 780 for (long x = TERRAIN_PAGE_MIN_X; x <= TERRAIN_PAGE_MAX_X; ++x) 781 for (long y = TERRAIN_PAGE_MIN_Y; y <= TERRAIN_PAGE_MAX_Y; ++y) 782 defineTerrain(x, y, blankTerrain); 783 // sync load since we want everything in place when we start 784 mTerrainGroup->loadAllTerrains(true); 785 #endif 786 787 if (mTerrainsImported) 788 { 789 TerrainGroup::TerrainIterator ti = mTerrainGroup->getTerrainIterator(); 790 while(ti.hasMoreElements()) 791 { 792 Terrain* t = ti.getNext()->instance; 793 initBlendMaps(t); 794 } 795 } 796 797 mTerrainGroup->freeTemporaryResources(); 798 799 // create a few entities on the terrain 800 Entity* e = mSceneMgr->createEntity("tudorhouse.mesh"); 801 Vector3 entPos(mTerrainPos.x + 2043, 0, mTerrainPos.z + 1715); 802 Quaternion rot; 803 entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) + 65.5 + mTerrainPos.y; 804 rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)), Vector3::UNIT_Y); 805 SceneNode* sn = mSceneMgr->getRootSceneNode()->createChildSceneNode(entPos, rot); 806 sn->setScale(Vector3(0.12, 0.12, 0.12)); 807 sn->attachObject(e); 808 mHouseList.push_back(e); 809 810 e = mSceneMgr->createEntity("tudorhouse.mesh"); 811 entPos = Vector3(mTerrainPos.x + 1850, 0, mTerrainPos.z + 1478); 812 entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) + 65.5 + mTerrainPos.y; 813 rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)), Vector3::UNIT_Y); 814 sn = mSceneMgr->getRootSceneNode()->createChildSceneNode(entPos, rot); 815 sn->setScale(Vector3(0.12, 0.12, 0.12)); 816 sn->attachObject(e); 817 mHouseList.push_back(e); 818 819 e = mSceneMgr->createEntity("tudorhouse.mesh"); 820 entPos = Vector3(mTerrainPos.x + 1970, 0, mTerrainPos.z + 2180); 821 entPos.y = mTerrainGroup->getHeightAtWorldPosition(entPos) + 65.5 + mTerrainPos.y; 822 rot.FromAngleAxis(Degree(Math::RangeRandom(-180, 180)), Vector3::UNIT_Y); 823 sn = mSceneMgr->getRootSceneNode()->createChildSceneNode(entPos, rot); 824 sn->setScale(Vector3(0.12, 0.12, 0.12)); 825 sn->attachObject(e); 826 mHouseList.push_back(e); 827 828 mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox"); 829 830 831 } 832 _shutdown()833 void _shutdown() 834 { 835 if (mTerrainPaging) 836 { 837 OGRE_DELETE mTerrainPaging; 838 mTerrainPaging = 0; 839 OGRE_DELETE mPageManager; 840 mPageManager = 0; 841 } 842 else if(mTerrainGroup) 843 { 844 OGRE_DELETE mTerrainGroup; 845 mTerrainGroup = 0; 846 } 847 848 if (mTerrainGlobals) 849 { 850 OGRE_DELETE mTerrainGlobals; 851 mTerrainGlobals = 0; 852 } 853 854 mHouseList.clear(); 855 856 SdkSample::_shutdown(); 857 } 858 859 860 }; 861 862 #endif 863