//---------------------------------------------------------------------------- AVector Terrain::GetNormal (float x, float y) const { float xp = x + mSpacing; float xm = x - mSpacing; float yp = y + mSpacing; float ym = y - mSpacing; TerrainPage* page = GetCurrentPage(xp, y); float xtmp = xp - page->LocalTransform.GetTranslate().X(); float ytmp = y - page->LocalTransform.GetTranslate().Y(); float hpz = page->GetHeight(xtmp,ytmp); page = GetCurrentPage(xm, y); xtmp = xm - page->LocalTransform.GetTranslate().X(); ytmp = y - page->LocalTransform.GetTranslate().Y(); float hmz = page->GetHeight(xtmp,ytmp); page = GetCurrentPage(x, yp); xtmp = x - page->LocalTransform.GetTranslate().X(); ytmp = yp - page->LocalTransform.GetTranslate().Y(); float hzp = page->GetHeight(xtmp,ytmp); page = GetCurrentPage(x, ym); xtmp = x - page->LocalTransform.GetTranslate().X(); ytmp = ym - page->LocalTransform.GetTranslate().Y(); float hzm = page->GetHeight(xtmp,ytmp); AVector normal(hmz - hpz, hzm - hzp, 1.0f); normal.Normalize(); return normal; }
//------------------------------------------------------------------------- TerrainRenderable * TerrainSceneManager::getTerrainTile( const Vector3 & pt ) { TerrainPage* tp = getTerrainPage(pt); if (!tp) return NULL; else return tp->getTerrainTile(pt); }
//---------------------------------------------------------------------------- float Terrain::GetHeight (float x, float y) const { TerrainPage* page = GetCurrentPage(x,y); x -= page->LocalTransform.GetTranslate().X(); y -= page->LocalTransform.GetTranslate().Y(); return page->GetHeight(x, y); }
//---------------------------------------------------------------------------- float Terrain::GetHeight (float x, float y) const { TerrainPage* page = GetCurrentPage(x,y); // Subtract off the translation due to wrap-around. x -= page->LocalTransform.GetTranslate().X(); y -= page->LocalTransform.GetTranslate().Y(); return page->GetHeight(x, y); }
//---------------------------------------------------------------------------- void Terrain::SetJunglerStrength (float strength) { mJunglerStrength = strength; for (int i=0; i<mNumRows; i++) { for (int j=0; j<mNumCols; j++) { TerrainPage *page = GetPage(i, j); page->SetJunglerStrength(strength); } } }
//---------------------------------------------------------------------------- void Terrain::SetJunglerFrequency (float fre) { mJunglerFrequency = fre; for (int i=0; i<mNumRows; i++) { for (int j=0; j<mNumCols; j++) { TerrainPage *page = GetPage(i, j); page->SetJunglerFrequency(fre); } } }
//---------------------------------------------------------------------------- void Terrain::RemoveJunglers (Texture2D *tex, APoint center, float radius, int num) { for (int i=0; i<mNumRows; i++) { for (int j=0; j<mNumCols; j++) { TerrainPage *page = GetPage(i, j); page->RemoveJunglers(tex, center, radius, num); } } }
//---------------------------------------------------------------------------- void Terrain::AddJunglers (Texture2D *tex, APoint center, float radius, int num, float width, float height, float lower) { if (!tex) return; for (int i=0; i<mNumRows; i++) { for (int j=0; j<mNumCols; j++) { GetPage(i, j)->mAddingJObjs.clear(); } } for (int i=0; i<num; i++) { float unitRadius = Mathf::UnitRandom(); float fX0 = Mathf::SymmetricRandom(); float fY0 = Mathf::SymmetricRandom(); AVector normal0(fX0, fY0, 0.0f); normal0.Normalize(); float fX1 = Mathf::SymmetricRandom(); float fY1 = Mathf::SymmetricRandom(); AVector normal1(fX1, fY1, 0.0f); normal1.Normalize(); APoint pos = center + normal0*unitRadius*radius; pos.Z() = GetHeight(pos.X(), pos.Y()) - lower; JObj obj; obj.Pos = pos; obj.Normal = normal1; obj.Width = width; obj.Height = height; TerrainPage *page = GetCurrentPage(obj.Pos.X(), obj.Pos.Y()); page->mAddingJObjs.push_back(obj); } for (int i=0; i<mNumRows; i++) { for (int j=0; j<mNumCols; j++) { TerrainPage *page = GetPage(i, j); page->AddJunglers(tex, page->mAddingJObjs); } } }
//------------------------------------------------------------------------- void TerrainSceneManager::setWorldGeometryRenderQueue(uint8 qid) { OctreeSceneManager::setWorldGeometryRenderQueue(qid); for (TerrainPage2D::iterator pi = mTerrainPages.begin(); pi != mTerrainPages.end(); ++pi) { TerrainPageRow& row = *pi; for (TerrainPageRow::iterator ri = row.begin(); ri != row.end(); ++ri) { TerrainPage* page = *ri; if (page) { page->setRenderQueue(qid); } } } }
void TerrainMaterialCompilationTask::executeTaskInMainThread() { TimedLog timedLog("TerrainMaterialCompilationTask::executeTaskInMainThread"); for (CompilationInstanceStore::const_iterator J = mMaterialRecompilations.begin(); J != mMaterialRecompilations.end(); ++J) { TerrainPageSurfaceCompilationInstance* compilationInstance = J->first; TerrainPage* page = J->second; compilationInstance->compile(page->getMaterial()); S_LOG_VERBOSE("Compiling terrain page composite map material"); compilationInstance->compileCompositeMap(page->getCompositeMapMaterial()); S_LOG_VERBOSE("Recompiled material for terrain page " << "[" << page->getWFIndex().first << "|" << page->getWFIndex().second << "]"); page->getSurface()->getShadow()->setShadowTextureName(compilationInstance->getShadowTextureName(page->getMaterial())); mSignal(page); // Notify the terrain system of the material change delete compilationInstance; std::stringstream ss; ss << "Compiled for page [" << page->getWFIndex().first << "|" << page->getWFIndex().second << "]"; timedLog.report(ss.str()); } updateSceneManagersAfterMaterialsChange(); }
TerrainPageGeometry::TerrainPageGeometry(TerrainPage& page, SegmentManager& segmentManager, float defaultHeight) : mPage(page), mDefaultHeight(defaultHeight) { SegmentManager::IndexMap indices; int segmentsPerAxis = mPage.getNumberOfSegmentsPerAxis(); int segmentOffset = segmentsPerAxis; for (int y = 0; y < mPage.getNumberOfSegmentsPerAxis(); ++y) { for (int x = 0; x < mPage.getNumberOfSegmentsPerAxis(); ++x) { int segX = (int)((mPage.getWFPosition().x() * segmentsPerAxis) + x); int segY = (int)((mPage.getWFPosition().y() * segmentsPerAxis) + y) - segmentOffset; indices[x][y] = std::make_pair(segX, segY); } } size_t count = segmentManager.getSegmentReferences(indices, mLocalSegments); if (count == 0) { std::stringstream ss; ss << "Created TerrainPageGeometry for which there are no valid segments. Pos: " << page.getWFPosition(); S_LOG_WARNING(ss.str()); } }
//------------------------------------------------------------------------- TerrainPage* TerrainPageSource::buildPage(Real* heightData, const MaterialPtr& pMaterial) { String name; // Create a Terrain Page TerrainPage* page = new TerrainPage((mPageSize-1) / (mTileSize-1)); // Create a node for all tiles to be attached to // Note we sequentially name since page can be attached at different points // so page x/z is not appropriate StringUtil::StrStreamType page_str; size_t pageIndex = mSceneManager->_getPageCount(); page_str << pageIndex; name = "page["; name += page_str.str() + "]"; if (mSceneManager->hasSceneNode(name)) { page->pageSceneNode = mSceneManager->getSceneNode(name); } else { page->pageSceneNode = mSceneManager->createSceneNode(name); } size_t q = 0; for ( size_t j = 0; j < mPageSize - 1; j += ( mTileSize - 1 ) ) { size_t p = 0; for ( size_t i = 0; i < mPageSize - 1; i += ( mTileSize - 1 ) ) { StringUtil::StrStreamType new_name_str; // Create scene node for the tile and the TerrainRenderable new_name_str << "tile[" << pageIndex << "][" << (int)p << "," << (int)q << "]"; name = new_name_str.str(); SceneNode *c; if (mSceneManager->hasSceneNode(name)) { c = mSceneManager->getSceneNode( name ); if (c->getParentSceneNode() != page->pageSceneNode) page->pageSceneNode->addChild(c); } else { c = page->pageSceneNode->createChildSceneNode( name ); } TerrainRenderable *tile = new TerrainRenderable(name, mSceneManager); // set queue tile->setRenderQueueGroup(mSceneManager->getWorldGeometryRenderQueue()); // Initialise the tile tile->setMaterial(pMaterial); tile->initialise(i, j, heightData); // Attach it to the page page->tiles[ p ][ q ] = tile; // Attach it to the node c ->attachObject( tile ); p++; } q++; } pageIndex++; // calculate neighbours for page page->linkNeighbours(); if(mSceneManager->getOptions().lit) { q = 0; for ( size_t j = 0; j < mPageSize - 1; j += ( mTileSize - 1 ) ) { size_t p = 0; for ( size_t i = 0; i < mPageSize - 1; i += ( mTileSize - 1 ) ) { page->tiles[ p ][ q ]->_calculateNormals(); p++; } q++; } } return page; }
//---------------------------------------------------------------------------- void Terrains::CreateScene () { // Create the root of the scene. mScene = new0 Node(); // Load and initialize the sky dome. It follows the camera. std::string skyMeshName = Environment::GetPathR("SkyDomePNT2.wmvf"); Visual::PrimitiveType type; VertexFormat* vformat; VertexBuffer* vbuffer; IndexBuffer* ibuffer; Visual::LoadWMVF(skyMeshName, type, vformat, vbuffer, ibuffer); mSkyDome = new0 TriMesh(vformat, vbuffer, ibuffer); mScene->AttachChild(mSkyDome); APoint skyPosition = mCamera->GetPosition(); skyPosition[2] = 0.0f; mSkyDome->LocalTransform.SetTranslate(skyPosition); mSkyDome->LocalTransform.SetUniformScale(mCamera->GetDMax()); Texture2DEffect* skyEffect = new0 Texture2DEffect( Shader::SF_LINEAR_LINEAR, Shader::SC_REPEAT, Shader::SC_REPEAT); std::string skyTextureName = Environment::GetPathR("SkyDome.wmtf"); Texture2D* skyTexture = Texture2D::LoadWMTF(skyTextureName); skyTexture->GenerateMipmaps(); mSkyDome->SetEffectInstance(skyEffect->CreateInstance(skyTexture)); // Load the height field and create the terrain. vformat = VertexFormat::Create(3, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0, VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 1); // For lower-resolution terrain, change the paths to Height64/Color64 or // Height32/Color32. std::string heightName = ThePath + "Data/Height128/height"; std::string colorName = ThePath + "Data/Color128/color"; mTerrain = new0 Terrain(heightName, vformat, mCamera); mScene->AttachChild(mTerrain); // The effect that is shared across all pages. std::string effectFile = Environment::GetPathR("BaseMulDetailFogExpSqr.wmfx"); TerrainEffect* terrainEffect = new0 TerrainEffect(effectFile); std::string detailName = Environment::GetPathR("Detail.wmtf"); Texture2D* detailTexture = Texture2D::LoadWMTF(detailName); detailTexture->GenerateMipmaps(); ShaderFloat* fogColorDensity = new0 ShaderFloat(1); (*fogColorDensity)[0] = 0.5686f; (*fogColorDensity)[1] = 0.7255f; (*fogColorDensity)[2] = 0.8353f; (*fogColorDensity)[3] = 0.0015f; // Attach an effect to each page. Preload all resources to video memory. // This will avoid frame rate stalls when new terrain pages are // encountered as the camera moves. const int numRows = mTerrain->GetRowQuantity(); const int numCols = mTerrain->GetColQuantity(); for (int r = 0; r < numRows; ++r) { for (int c = 0; c < numCols; ++c) { TerrainPage* page = mTerrain->GetPage(r, c); char suffix[32]; sprintf(suffix, ".%d.%d.wmtf", r, c); std::string colorTextureName = colorName + std::string(suffix); Texture2D* colorTexture = Texture2D::LoadWMTF(colorTextureName); colorTexture->GenerateMipmaps(); VisualEffectInstance* instance = terrainEffect->CreateInstance( colorTexture, detailTexture, fogColorDensity); page->SetEffectInstance(instance); mRenderer->Bind(page->GetVertexBuffer()); mRenderer->Bind(page->GetVertexFormat()); mRenderer->Bind(page->GetIndexBuffer()); mRenderer->Bind(colorTexture); } } }
//---------------------------------------------------------------------------- void Terrain::OnCameraMotion () { assertion(mCamera != 0, "Camera must exist\n"); if (!mCamera) { return; } // Get camera location/direction in model space of terrain. APoint worldEye = mCamera->GetPosition(); AVector worldDir = mCamera->GetDVector(); APoint modelEye = WorldTransform.Inverse()*worldEye; AVector modelDir = WorldTransform.Inverse()*worldDir; // Update the model-space origins of the terrain pages. Start the // process by locating the page that contains the camera. float length = mSpacing*(float)(mSize - 1); float invLength = 1.0f/length; int newCameraCol = (int)Mathf::Floor(modelEye.X()*invLength); int newCameraRow = (int)Mathf::Floor(modelEye.Y()*invLength); if (newCameraCol != mCameraCol || newCameraRow != mCameraRow) { mCameraCol = newCameraCol; mCameraRow = newCameraRow; // Translate page origins for toroidal wraparound. int cminO = mCameraCol - mNumCols/2; int cminP = cminO % mNumCols; if (cminP < 0) { cminP += mNumCols; } int rminO = mCameraRow - mNumRows/2; int rminP = rminO % mNumRows; if (rminP < 0) { rminP += mNumRows; } int rO = rminO, rP = rminP; for (int row = 0; row < mNumRows; ++row) { int cO = cminO, cP = cminP; for (int col = 0; col < mNumCols; ++col) { TerrainPage* page = mPages[rP][cP]; Float2 oldOrigin = page->GetOrigin(); Float2 newOrigin(cO*length, rO*length); APoint pageTrn( newOrigin[0] - oldOrigin[0], newOrigin[1] - oldOrigin[1], page->LocalTransform.GetTranslate().Z()); page->LocalTransform.SetTranslate(pageTrn); ++cO; if (++cP == mNumCols) { cP = 0; } } ++rO; if (++rP == mNumRows) { rP = 0; } } Update(); } }