// --------------------------------------------------------------------- // Create an approximate mesh of the landscape. // void CRoamMeshDrawer::Tessellate(const float3& campos, int viewradius) { // Perform Tessellation #ifdef _OPENMP // hint: just helps a little with huge cpu usage in retessellation, still better than nothing // _____ // |0|_|_|.. // |_|_|_|.. // |_|_|8|.. // ..... // split the patches in 3x3 sized blocks. The tessellation itself can // extend into the neighbor patches (check Patch::Split). So we could // not multi-thread the whole loop w/o mutexes (in ::Split). // But instead we take a safety distance between the thread's working // area (which is 2 patches), so they don't conflict with each other. for (int idx = 0; idx < 9; ++idx) { #pragma omp parallel for for (int i = m_Patches.size() - 1; i >= 0; --i) { Patch* it = &m_Patches[i]; const int X = it->m_WorldX; const int Z = it->m_WorldY; const int subindex = (X % 3) + (Z % 3) * 3; if ((subindex == idx) && it->IsVisible()) { it->Tessellate(campos, viewradius); } } } #else for (std::vector<Patch>::iterator it = m_Patches.begin(); it != m_Patches.end(); ++it) { if (it->IsVisible()) it->Tessellate(campos, viewradius); } #endif }
// --------------------------------------------------------------------- // Create an approximate mesh of the landscape. // bool CRoamMeshDrawer::Tessellate(const float3& campos, int viewradius) { // Perform Tessellation // hint: threading just helps a little with huge cpu usage in retessellation, still better than nothing // _____ // |0|_|_|.. // |_|_|_|.. // |_|_|8|.. // ..... // split the patches in 3x3 sized blocks. The tessellation itself can // extend into the neighbor patches (check Patch::Split). So we could // not multi-thread the whole loop w/o mutexes (in ::Split). // But instead we take a safety distance between the thread's working // area (which is 2 patches), so they don't conflict with each other. bool forceTess = false; for (int idx = 0; idx < 9; ++idx) { for_mt(0, roamPatches.size(), [&](const int i){ Patch* it = &roamPatches[i]; const int X = it->m_WorldX; const int Z = it->m_WorldY; const int subindex = (X % 3) + (Z % 3) * 3; if ((subindex == idx) && it->IsVisible()) { if (!it->Tessellate(campos, viewradius)) forceTess = true; } }); if (forceTess) return true; } return false; }
/** * Retessellates the current terrain */ void CRoamMeshDrawer::Update() { //FIXME this retessellates with the current camera frustum, shadow pass and others don't have to see the same patches! //const CCamera* cam = (inShadowPass)? camera: cam2; CCamera* cam = cam2; // Update Patch visibility Patch::UpdateVisibility(cam, m_Patches, numPatchesX); // Check if a retessellation is needed #define RETESSELLATE_MODE 1 bool retessellate = false; { //SCOPED_TIMER("ROAM::ComputeVariance"); for (int i = 0; i < (numPatchesX * numPatchesY); ++i) { Patch& p = m_Patches[i]; #if (RETESSELLATE_MODE == 2) if (p.IsVisible()) { if (!visibilitygrid[i]) { visibilitygrid[i] = true; retessellate = true; } if (p.IsDirty()) { //FIXME don't retessellate on small heightmap changes? p.ComputeVariance(); retessellate = true; } } else { visibilitygrid[i] = false; } #else if (p.IsVisible() != visibilitygrid[i]) { visibilitygrid[i] = p.IsVisible(); retessellate = true; } if (p.IsVisible() && p.IsDirty()) { //FIXME don't retessellate on small heightmap changes? p.ComputeVariance(); retessellate = true; } #endif } } // Further conditions that can cause a retessellation #if (RETESSELLATE_MODE == 2) static const float maxCamDeltaDistSq = 500.0f * 500.0f; retessellate |= ((cam->pos - lastCamPos).SqLength() > maxCamDeltaDistSq); #endif retessellate |= forceRetessellate; retessellate |= (lastGroundDetail != smfGroundDrawer->GetGroundDetail()); // Retessellate if (retessellate) { { //SCOPED_TIMER("ROAM::Tessellate"); //FIXME this tessellates with current camera + viewRadius // so it doesn't retessellate patches that are e.g. only vis. in the shadow frustum Reset(); Tessellate(cam->pos, smfGroundDrawer->GetGroundDetail()); } { //SCOPED_TIMER("ROAM::GenerateIndexArray"); #pragma omp parallel for for (int i = m_Patches.size() - 1; i >= 0; --i) { Patch* it = &m_Patches[i]; if (it->IsVisible()) { it->GenerateIndices(); } } } { //SCOPED_TIMER("ROAM::Upload"); for (std::vector<Patch>::iterator it = m_Patches.begin(); it != m_Patches.end(); ++it) { if (it->IsVisible()) { it->Upload(); } } } /*{ int tricount = 0; for (std::vector<Patch>::iterator it = m_Patches.begin(); it != m_Patches.end(); it++) { if (it->IsVisible()) { tricount += it->GetTriCount(); } } LOG_L(L_DEBUG, "ROAM dbg: Framechange, fram=%i tris=%i, viewrad=%i, cd=%f, camera=(%5.0f, %5.0f, %5.0f) camera2= (%5.0f, %5.0f, %5.0f)", globalRendering->drawFrame, tricount, smfGroundDrawer->viewRadius, (cam->pos - lastCamPos).SqLength();, camera->pos.x, camera->pos.y, camera->pos.z, cam2->pos.x, cam2->pos.y, cam2->pos.z ); }*/ lastGroundDetail = smfGroundDrawer->GetGroundDetail(); lastCamPos = cam->pos; forceRetessellate = false; } }