OGRESE没有采用四叉树管理LOD。而是计算每个地形Tile每等级lod 改变最小距离的平方 存储在了std::vector<Ogre::Real> m_LODChangeMinDistSqr;
然后根据摄像机的位置实时计算出来地形Tile的当前LOD的值。
OGRESE中对于这两个函数的注释比较少 以下是注释
//-----------------------------------------------------根据相机计算当前LOD的值
void TerrainTile::_notifyCurrentCamera(Ogre::Camera* cam)
{
MovableObject::_notifyCurrentCamera(cam);
if (!mVisible)//如果不可见 则返回
return;
//
Ogre::Vector3 cpos = cam->getDerivedPosition();//得到摄像机的位置
//
const Ogre::AxisAlignedBox& aabb = getWorldBoundingBox(true);
Ogre::Vector3 diff(0, 0, 0);
Ogre::Vector3 temp1=cpos-aabb.getMaximum();
Ogre::Vector3 temp2=cpos-aabb.getMinimum();
diff.makeFloor(cpos - aabb.getMinimum());
diff.makeCeil(cpos - aabb.getMaximum());
float L = diff.squaredLength();
//
// 找出当前lod
m_nLOD = m_pOwner->GetMaxLod();
unsigned short nMaxLod = m_nLOD+1;
for (unsigned short i = 1; i < nMaxLod; ++i)
{
if (m_LODChangeMinDistSqr[i] > L)//每等级lod 改变最小距离的平方 大于 L
{
m_nLOD = i - 1;//那么就得到了当前的LOD m_nLod 对于平整的地形 那么就会这个选择最大的LOD
break;
}
}
if (m_pOwner->GetLODMorphEnabled())
{
// 找出下一级lod
unsigned short nextLevel = m_nLOD + 1;//下一集的LOD m_nLOD+1
for (unsigned short i = nextLevel; i < nMaxLod; ++i)
{
if (m_LODChangeMinDistSqr[i] > m_LODChangeMinDistSqr[m_nLOD])
{
nextLevel = i;
break;
}
}
// 计算两个lod等级间的变形因子
if (nextLevel == nMaxLod)
{
m_fLODMorphFactor = 0;
}
else
{
float range = m_LODChangeMinDistSqr[nextLevel] - m_LODChangeMinDistSqr[m_nLOD];
float percent = (L - m_LODChangeMinDistSqr[m_nLOD]) / range;
float rescale = 1.0f / (1.0f - m_pOwner->GetLodMorphStart());
m_fLODMorphFactor = __max((percent - m_pOwner->GetLodMorphStart()) * rescale, 0.0f);
}
//最近一次计算的下一级 lod m_nLastNextLOD
if (m_nLastNextLOD != nextLevel)
{
if (nextLevel != nMaxLod)
{
m_pVertexData->vertexBufferBinding->setBinding(DELTA_BINDING, m_DeltaBuffers[nextLevel-1]);
}
else
{
// bind dummy
m_pVertexData->vertexBufferBinding->setBinding(DELTA_BINDING, m_DeltaBuffers[0]);
}
}
m_nLastNextLOD = nextLevel;
}
}
//***************************************************************************************
// 功能: 计算每两级间的最小距离,用来作为选择当前LOD的标准
void TerrainTile::_CalculateMinLevelDist2()
{
using namespace Ogre;
Real CSquare = m_pOwner->m_fFactorC * m_pOwner->m_fFactorC;//基准系数
// LOD 0 has no distance LOD0 没有距离
m_LODChangeMinDistSqr[0] = 0.0f;//每等级lod 改变最小距离的平方
//从LOD1到LODMAX
for (unsigned short level = 1; level <= m_pOwner->GetMaxPossibleLod(); ++level)
{
m_LODChangeMinDistSqr[level] = 0.0f;//每等级lod 改变最小距离的平方
unsigned short step = 1 << level;//左移level位 下一级的step
unsigned short higherstep = step >> 1;//step右移一位 当前这一级的step
float* pDeltas = 0;
// for LOD morphing, lock the according delta buffer now
if (m_pOwner->GetLODMorphEnabled())
{
// indexed at LOD-1, because there are only maxLOD transitions between LODs...
_EmptyBuffer(m_DeltaBuffers[level-1]);//硬件缓存
pDeltas = static_cast<float*>(m_DeltaBuffers[level-1]->lock(HardwareBuffer::HBL_NORMAL));
}
// for every vertex that is not used in the current LOD we calculate its interpolated
// height and compare against its actual height. the largest difference of a vertex
// is then used to determine the minimal distance for this LOD.
for (unsigned short j = 0; j <= m_nSize - step; j += step)//该块的大小, 2^n m_nSIze
{
for (unsigned short i = 0; i <= m_nSize - step; i += step)
{
Vector3 v1 = m_pOwner->m_pData->PixelToWorld(m_nStartX + i, m_nStartZ + j);// // 功能: 得到结点 xz 点的world坐标
Vector3 v2 = m_pOwner->m_pData->PixelToWorld(m_nStartX + i + step,m_nStartZ + j);
Vector3 v3 = m_pOwner->m_pData->PixelToWorld(m_nStartX + i, m_nStartZ + j+ step);
Vector3 v4 = m_pOwner->m_pData->PixelToWorld(m_nStartX + i + step,m_nStartZ + j+ step);//对应于地形tile的某个栅格的四个坐标(v1,v2,v4,v3)
Plane t1 (v1, v3, v2);//上三角
Plane t2 (v2, v3, v4); //下三角
unsigned short zubound = (j == (m_nSize + 1 - step) ? step : step - 1);//z轴的界限 指的是z轴在某个step中的栅格栅格的界限[0,step-1],最后一个比较特殊
for (unsigned short z = 0; z <= zubound; ++z)
{
unsigned short xubound = (i == (m_nSize + 1 - step) ? step : step - 1);//x轴的界限
for (unsigned short x = 0; x < xubound; ++x)
{
unsigned short fulldetailx = i + x; //真实的栅格号码
unsigned short fulldetailz = j + z; //真实的栅格号码
if (fulldetailx % step == 0 && fulldetailz % step == 0)//这是由于要内插 所以不能选择边界点
{
continue;
}
Real zpct = Real(z) / Real(step);//内插的点在四边形中的z比例
Real xpct = Real(x) / Real(step);//内插的点在四边形中的x比例
//真实的点
Vector3 actualPos = m_pOwner->m_pData->PixelToWorld(fulldetailx + m_nStartX, fulldetailz + m_nStartZ);
Real interp_h;//内插高度
if (xpct + zpct <= 1.0f)//在上三角
{
float temp1=t1.normal.x;
temp1=actualPos.x;
temp1=t1.normal.z;
temp1=actualPos.z;
temp1=t1.d;
temp1=t1.normal.y;
interp_h = (
-(t1.normal.x * actualPos.x)
- t1.normal.z * actualPos.z
- t1.d) / t1.normal.y;
}
else
{
interp_h = (
-(t2.normal.x * actualPos.x)
- t2.normal.z * actualPos.z
- t2.d) / t2.normal.y;
}
Real actual_h = actualPos.y;
Real delta = fabs(interp_h - actual_h);
Real D2 = delta * delta * CSquare;
if (m_LODChangeMinDistSqr[level] < D2)
m_LODChangeMinDistSqr[level] = D2;
// for LOD morphing(LOD变形), store the difference in the delta buffer
if (m_pOwner->GetLODMorphEnabled() &&
fulldetailx != 0 && fulldetailx != m_nSize &&
fulldetailz != 0 && fulldetailz != m_nSize)
{
pDeltas[fulldetailx + fulldetailz * (m_nSize + 1)] = interp_h - actual_h;
}
}
}
}
}
// unlock delta buffers
if (m_pOwner->GetLODMorphEnabled())
m_DeltaBuffers[level-1]->unlock();
}
// post validate
for (unsigned short i = 1; i <= m_pOwner->GetMaxPossibleLod(); ++i)
{
// ensure level distances are increasing
if (m_LODChangeMinDistSqr[i] < m_LODChangeMinDistSqr[i-1])
m_LODChangeMinDistSqr[i] = m_LODChangeMinDistSqr[i-1];
}
}