// --------------------------------------------------------------------- // Create an approximate mesh. // bool Patch::Tessellate(const float3& campos, int groundDetail) { // Set/Update LOD params (FIXME: wrong height?) const float myx = (coors.x + PATCH_SIZE / 2) * SQUARE_SIZE; const float myz = (coors.y + PATCH_SIZE / 2) * SQUARE_SIZE; const float myy = (readMap->GetCurrMinHeight() + readMap->GetCurrMaxHeight()) * 0.5f; const float3 myPos(myx, myy, myz); camDistLODFactor = myPos.distance(campos); camDistLODFactor *= 300.0f / groundDetail; // MAGIC NUMBER 1: increase the dividend to reduce LOD in camera distance camDistLODFactor = std::max(1.0f, camDistLODFactor); camDistLODFactor = 1.0f / camDistLODFactor; // MAGIC NUMBER 2: // variances are clamped by it, so it regulates how strong areas are tessellated. // Note, the maximum tessellation is untouched by it. Instead it reduces the maximum // LOD in distance, while the param above defines the overall FallOff rate. varianceMaxLimit = groundDetail * 0.35f; { // Split each of the base triangles currentVariance = &varianceLeft[0]; const int2 left = {coors.x, coors.y + PATCH_SIZE}; const int2 rght = {coors.x + PATCH_SIZE, coors.y }; const int2 apex = {coors.x, coors.y }; RecursTessellate(&baseLeft, left, rght, apex, 1); } { currentVariance = &varianceRight[0]; const int2 left = {coors.x + PATCH_SIZE, coors.y }; const int2 rght = {coors.x, coors.y + PATCH_SIZE}; const int2 apex = {coors.x + PATCH_SIZE, coors.y + PATCH_SIZE}; RecursTessellate(&baseRight, left, rght, apex, 1); } return (!CTriNodePool::GetPool()->OutOfNodes()); }
// --------------------------------------------------------------------- // Tessellate a Patch. // Will continue to split until the variance metric is met. // void Patch::RecursTessellate(TriTreeNode* tri, const int2 left, const int2 right, const int2 apex, const int node) { // bail if we can not tessellate further in at least one dimension if ((abs(left.x - right.x) <= 1) && (abs(left.y - right.y) <= 1)) return; // default > 1; when variance isn't saved this issues further tessellation float TriVariance = 10.0f; if (node < (1 << VARIANCE_DEPTH)) { // make max tessellation viewRadius dependent // w/o this huge cliffs cause huge variances and will always tessellate // fully independent of camdist (-> huge/distfromcam ~= huge) const float myVariance = std::min(currentVariance[node], varianceMaxLimit); const int sizeX = std::max(left.x - right.x, right.x - left.x); const int sizeY = std::max(left.y - right.y, right.y - left.y); const int size = std::max(sizeX, sizeY); // take distance, variance and patch size into consideration TriVariance = (myVariance * PATCH_SIZE * size) * camDistLODFactor; } // stop tesselation if (TriVariance <= 1.0f) return; Split(tri); if (tri->IsBranch()) { // triangle was split, also try to split its children const int2 center = {(left.x + right.x) >> 1, (left.y + right.y) >> 1}; RecursTessellate(tri->LeftChild, apex, left, center, (node << 1) ); RecursTessellate(tri->RightChild, right, apex, center, (node << 1) + 1); } }
// --------------------------------------------------------------------- // Tessellate a Patch. // Will continue to split until the variance metric is met. // void Patch::RecursTessellate(TriTreeNode* const& tri, const int2& left, const int2& right, const int2& apex, const int& node) { const bool canFurtherTes = ((abs(left.x - right.x) > 1) || (abs(left.y - right.y) > 1)); if (!canFurtherTes) return; float TriVariance; const bool varianceSaved = (node < (1 << VARIANCE_DEPTH)); if (varianceSaved) { // make max tessellation viewRadius dependent // w/o this huge cliffs cause huge variances and so will always tessellate fully independent of camdist (-> huge/distfromcam ~= huge) const float myVariance = std::min(m_CurrentVariance[node], varianceMaxLimit); const int sizeX = std::max(left.x - right.x, right.x - left.x); const int sizeY = std::max(left.y - right.y, right.y - left.y); const int size = std::max(sizeX, sizeY); // Take both distance and variance and patch size into consideration TriVariance = (myVariance * PATCH_SIZE * size) * camDistLODFactor; } else { TriVariance = 10.0f; // >1 -> When variance isn't saved issue further tessellation } if (TriVariance > 1.0f) { Split(tri); // Split this triangle. if (tri->IsBranch()) { // If this triangle was split, try to split it's children as well. const int2 center( (left.x + right.x) >> 1, // Compute X coordinate of center of Hypotenuse (left.y + right.y) >> 1 // Compute Y coord... ); RecursTessellate(tri->LeftChild, apex, left, center, (node << 1) ); RecursTessellate(tri->RightChild, right, apex, center, (node << 1) + 1); } } else {