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]; } }