public bool CalculateCurrentLod(Camera cam, float cFactor)
{
mSelfOrChildRendered = false;
//check children first.
int childrenRenderedOut = 0;
if (!IsLeaf)
{
for (int i = 0; i < 4; ++i)
{
if (mChildren[i].CalculateCurrentLod(cam, cFactor))
++childrenRenderedOut;
}
}
if (childrenRenderedOut == 0)
{
// no children were within their LOD ranges, so we should consider our own
Vector3 localPos = cam.DerivedPosition - mLocalCentre - mTerrain.Position;
float dist;
if (TerrainGlobalOptions.IsUseRayBoxDistanceCalculation)
{
// Get distance to this terrain node (to closest point of the box)
// head towards centre of the box (note, box may not cover mLocalCentre because of height)
Vector3 dir = mAABB.Center - localPos;
dir.Normalize();
Ray ray = new Ray(localPos, dir);
IntersectResult intersectRes = ray.Intersects(mAABB);
// ray will always intersect, we just want the distance
dist = intersectRes.Distance;
}
else
{
// distance to tile centre
dist = localPos.Length;
// deduct half the radius of the box, assume that on average the
// worst case is best approximated by this
dist -= (mBoundingRadius * 0.5f);
}
// Do material LOD
Material material = this.Material;
Axiom.Core.LodStrategy str = material.LodStrategy;
float lodValue = str.GetValue(mRend, cam);
mMaterialLodIndex = (ushort)material.GetLodIndex(lodValue);
// For each LOD, the distance at which the LOD will transition *downwards*
// is given by
// distTransition = maxDelta * cFactor;
int lodLvl = 0;
mCurrentLod = -1;
foreach (LodLevel l in mLodLevels)
{
// If we have no parent, and this is the lowest LOD, we always render
// this is the 'last resort' so to speak, we always enoucnter this last
if (lodLvl + 1 == mLodLevels.Count && mParent == null)
{
CurentLod = lodLvl;
mSelfOrChildRendered = true;
mLodTransition = 0;
}
else
{
//check the distance
LodLevel ll = l;
// Calculate or reuse transition distance
float distTransition;
if ( Utility.RealEqual( cFactor, ll.LastTranistionDist ) )
distTransition = ll.LastTranistionDist;
else
{
distTransition = ll.MaxHeightDelta * cFactor;
ll.LastCFactor = cFactor;
ll.LastTranistionDist = distTransition;
}
if (dist < distTransition)
{
// we're within range of this LOD
CurentLod = lodLvl;
mSelfOrChildRendered = true;
if (mTerrain.IsMorphRequired)
{
// calculate the transition percentage
// we need a percentage of the total distance for just this LOD,
// which means taking off the distance for the next higher LOD
// which is either the previous entry in the LOD list,
// or the largest of any children. In both cases these will
// have been calculated before this point, since we process
// children first. Distances at lower LODs are guaranteed
// to be larger than those at higher LODs
float distTotal = distTransition;
if (IsLeaf)
{
// Any higher LODs?
#warning: check if this if is correct!
if (lodLvl < mLodLevels.Count)
{
int prec = lodLvl - 1;
distTotal -= mLodLevels[lodLvl].LastTranistionDist;
}
}
else
{
// Take the distance of the lowest LOD of child
LodLevel childLod = mChildWithMaxHeightDelta.GetLodLevel(
(ushort)(mChildWithMaxHeightDelta.LodCount - 1));
distTotal -= childLod.LastTranistionDist;
}
// fade from 0 to 1 in the last 25% of the distance
float distMorphRegion = distTotal * 0.25f;
float distRemain = distTransition - dist;
mLodTransition = 1.0f - (distRemain / distMorphRegion);
mLodTransition = System.Math.Min(1.0f, mLodTransition);
mLodTransition = System.Math.Max(0.0f, mLodTransition);
// Pass both the transition % and target LOD (GLOBAL current + 1)
// this selectively applies the morph just to the
// vertices which would drop out at this LOD, even
// while using the single shared vertex data
mRend.SetCustomParameter(Terrain.LOD_MORPH_CUSTOM_PARAM,
new Vector4(mLodTransition, mCurrentLod + mBaseLod + 1, 0, 0));
}//end if
// since LODs are ordered from highest to lowest detail,
// we can stop looking now
break;
}//end if
}//end else
++lodLvl;
}//end for each
}//end if
else
{
// we should not render ourself
mCurrentLod = -1;
mSelfOrChildRendered = true;
if (childrenRenderedOut < 4)
{
// only *some* children decided to render on their own, but either
// none or all need to render, so set the others manually to their lowest
for (int i = 0; i < 4; ++i)
{
TerrainQuadTreeNode child = mChildren[i];
if (!child.IsSelfOrChildrenRenderedAtCurrentLod)
{
child.CurentLod = child.LodCount - 1;
child.LodTransition = 1.0f;
}
}
}//(childRenderedCount < 4)
}// (childRenderedCount == 0)
return mSelfOrChildRendered;
}
/// <summary>