lod详解

TerrainQuadTreeNode::updateVertexBuffer(HardwareVertexBufferSharedPtr& posbuf

void Terrain::getPointAlign(long x, long y, float height, Alignment align, Vector3* outpos)//计算出每个顶点的坐标

 Terrain::updateBaseScale() 

TerrainQuadTreeNode生成子块.


LOD结构

         有三个参数对Ogre地形的网格结架比较重要:terrainSize、minBatch及maxBatch。

terrainSize决定地形每条边的顶点总数目,minBatch决定四叉树非叶节点所包含的顶点数目,maxBatch决定四叉树叶节点所包含的顶点数目。

LOD的数目也并非等同于四叉树的层数,在非叶节点,一层四叉树对应一个LOD,顶点数目为minBatch;但是在叶节点,则包含了从minBatch到maxBatch的一套LOD列表。

         按照理论,Ogre地形LOD层数及四叉树深度计算公式如下:

LODlevels = log2(size - 1) - log2(minBatch - 1) + 1

TreeDepth = log2((size - 1) / (maxBatch - 1)) + 1

值得一提的是,由于OgreTerrain的顶点采用16位索引,所以所能索引到最大顶点数目为TERRAIN_MAX_BATCH_SIZE,这样一来,不仅仅顶点索引会根据四叉树分层,顶点数据本身也会根据四叉树分块,理论上顶点数据被分为terrainSize / TERRAIN_MAX_BATCH_SIZE块,但由于上层LOD不能跨块进行索引,Ogre会再开辟一些新的块,所以总共用到的顶点数据会多于实际数据,另外层与层之间视情况还可能共享顶点,比较复杂。根据官方的解释,这种多建顶点的办法更易实现且数目不大,所以是可接受的;更重要的是在制作超大场景的时候,大量底层顶点缓存可以在低LOD时被释放,这在降低内存占用上很重要。TERRAIN_MAX_BATCH_SIZE这一特殊设定的存在,限定了地形的maxBatch不能大于TERRAIN_MAX_BATCH_SIZE,地形本身的size不能小于TERRAIN_MAX_BATCH_SIZE(terrainSize小于TERRAIN_MAX_BATCH_SIZE会导致只有Top节点有顶点数据)。TERRAIN_MAX_BATCH_SIZE = 129,在使用时需要谨记




  在第五步中,Terrain有三个属性(TerrainGroup里的DefaultImportSettings设置)来决定如何分区分块,分别Size,MaxBatchSize,MinBatchSize.意思分别是这个Terrain的大小,Terrain里的单个块里的最大值与最小值,注意这三个值是同一量程,并且他们的长度都满足 2^n+1,我们都可以看做是地形的虚拟单位,他的实际大小是worldSize,比如worldSize是10240,而Size是257,那么Size,MaxBatchSize,MinBatchSize里的一个单位1可以看做是实际长度40.而MaxBatchSize与Size影响Terrain的如何分块,而MaxBatchSize与MinBatchSize影响Terrain精度最高的块的再细分.综合MinBatchSize与size就是地形的LOD层数.如下公式

       LODlevels = log2(size - 1) - log2(minBatch - 1) + 1

       TreeDepth = log2(size - 1) - log2(maxBatch - 1) + 1 

  Terrain在创建时,会生成一个TerrainQuadTreeNode节点,TerrainQuadTreeNode根据地形的Size,MaxBatchSize,MinBatchSize生成四叉树,这里我们先假设Size等于257,MaxBatchSize等33,而MinBatchSize等于17,根据公式LODlevels=5,TreeDepth=4这个TerrainQuadTreeNode的Size就是Terrain的Size,然后生成四个子节点,想象一下把一个正方形中间横竖各一条线分隔成四个正方形.TerrainQuadTreeNode生成的子节点也是这个过程,那么子节点的边长为父节点边长的1/2,也就是(257-1)/2+1=129.这个过程会递归下去,一直到MaxBatchSize的长度,也就是257,129,65,33一共是四层(这四层的顶点密度都是MinBatchSize),也就是上面TreeDepth的结果,而到1/8*257=33(下图中的8*17,LOD1)后,TerrainQuadTreeNode不会生成子节点了,而是生成log2(maxBatch - 1)-log2(minBatch - 1)+1=2个LodLevel(LOD0,LOD1),请看下图.(节点生成的顺序是LOD4-LOD0,不要搞反了.)

  其中Lod越高,Terr depth越低,地度的精度越低.我们可以看到深度对应着地形的分块大小,代码同TerrainQuadTreeNode生成子节点的过程,一共四层.而在LOD1后,没有生成子节点,而是再生成一个LodLevel,其中BatchSize为33(对应面积每边取点),之前每个TerrainQuadTreeNode对应的BatchSize都为17.而MaxBatchSize与MinBatchSize是针对图上的每1/256的Terrain的细分.TreeDepth加上最后细分的LodLevel就等于LODlevels.总结如下:根据Size与MaxBatchSize得到最小块 (256/32)^2 =8*8,8对应四层,分别是8*8,4*4,2*2,1*1.而4*4,2*2,1*1这三块的精度都为MinBatchSize就17,而8*8精度从MaxBatchSize到MinBatchSize. 

地形顶点计算.

  那么我们如何根据上面的LOD来给出对应的顶点与索引数据.这个在Terrain的方法DistributeVertexData里的注释详细讲解了如何根据Terrain的Size,MaxBatchSize,MinBatchSize来创建顶点元素,在这里设Size为2049,MaxBatchSize为65,MinBatchSize为33. 

  因为要支持16位的索引,故最大为2^8*2^8也就是256*256的值,考虑这个值太大,TERRAIN_MAX_BATCH_SIZE为128+1.就是说支持最大的正方形每边的顶点为129个,总索引为129*129.根据前面一节我们来分成如下段:

            LODlevels = log2(2049 - 1) - log2(33 - 1) + 1 = 11 - 5 + 1 = 7
            TreeDepth = log2((2049 - 1) / (65 - 1)) + 1 = 6
            Number of vertex data splits at most detailed level:
            (size - 1) / (TERRAIN_MAX_BATCH_SIZE - 1) = 2048 / 128 = 16    

  四叉对节点深度:每边顶点数/(每边块数*每边顶点)地形总块数/LOD/顶点索引/数据内存划分:[每边顶点*每边块数](总块数=每边块平方)

  • tree depth 0: 33   vertices, 1  x 33(总1块) vertex tiles (LOD 6) vdata 18    [33](总一块) 
  • tree depth 1: 65   vertices, 2  x 33(总4块) vertex tiles (LOD 5) vdata 16-17 [2x129](总4块)
  • tree depth 2: 129  vertices, 4  x 33(总16块) vertex tiles (LOD 4) vdata 16-17 [2x129](总4块)
  • tree depth 3: 257  vertices, 8  x 33(总64块) vertex tiles (LOD 3) vdata 16-17 [2x129](总4块)
  • tree depth 4: 513  vertices, 16 x 33(总256块) vertex tiles (LOD 2) vdata 0-15  [16x129](总256块)
  • tree depth 5: 1025 vertices, 32 x 33(总1024块) vertex tiles (LOD 1) vdata 0-15  [16x129](总256块)
  • tree depth 5: 2049 vertices, 32 x 65(总1024块) vertex tiles (LOD 0) vdata 0-15  [16x129](总256块)

  这个和前面差不多,唯一就是最后多出来的129*16,129*2,33这三段,前面的LODLevels可以说是数据索引分区,而这129*16,129*2,33是数据分区.直接来看,32*65,32*33,16*33如何分进129*16这个块,而为什么8*33以及如下又不能分进这块.我们看到的32*65,12*33,129*16都是正方形一边的点数,而129是每小块最大点数(TERRAIN_MAX_BATCH_SIZE),那么边为2049点的正方形在每块最大占129点的情况下,可以分为16*16个129点的小正方形块.在LOD 0 32*(65点)的情况下,就是一个16*16*(129点)的块分成四个32*(65点)的块.而LOD1和LOD0一样也是一个16*16*129的块分成了四个,但是每块的点数只有33点,就是四个32*(33点)的块.而LOD2的一块也是16*16*(33点),也就是说,LOD2的一块大小和16*16*(129点)大小一样,只是原始的每块每边有129个基点,现在LOD2的每块只有33个顶点,但是他们的大小是一样.那么在LOD3开始,他是分成8*8*(33点),这一块有16*16*(129点)四个大,这样LOD3里的索引匹配不到16*16*(129点)里的数据,所以重新开始分割,然后LOD3,4,5和前面的分块一样,都能匹配到2*2*(129)点块上.最后一块是直接分成33*33,这里对应注释告诉我们有二个选择,为了减少渲染次数而分成33*33.而不是分成四块17*17. 

  大家可能要说,为什么不为每LOD直接生成对应每层数据.这样完全没必要,因为就和上面分析一样,LOD0,1,2完全可以共用顶点,只需要选择好相应索引就能正确的渲染,而每层生成顶点数据,直接造成内存紧张.这样分三层的第一层是2049*2049=4198401,第二层是513*513=263169,第三层是33*33=1089.第二层和第三层只占第一层的3%左右,在合适的情况下,可以只要第二层的数据,大大缩减内存使用. 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值