Example #1
0
// ---------------------------------------------------------------------
// 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
}
Example #2
0
// ---------------------------------------------------------------------
// 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;
}
Example #3
0
/**
 * 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;
	}
}