虽然地形已经有LOD和形变(geomorphing, 这里简称morphing)来进行LOD的渐变,从而避免bump, 但是如果LOD级别过多,远处的高山就会严重丢失细节,比如变成尖尖的凸起,非常丑陋,这是morphing无法解决的。

解决一种方式是使用强制的固定LOD (fixed LOD),如果一个block的高度(maxH)或者高度比率(dH/dX)超过一定阈值,就使用固定的高细节的LOD。

例如LOD 0为最高细节,aab为block的包围盒,那么:

  if(aab.getSize().y / aab.getSize().x >= THRESOLD)
block.fixedLOD = ; //use the 2nd largest detail level. the most largest 0 is better.

之前我也考虑过类似的问题, 比如一个block如果是平的,那么就使用固定的最低细节的LOD。 这个想法我也是开的脑洞,看起来非常简单,但是实现起来有很多坑:

1.LOD链接问题

通常的LOD索引方法,只处理了相邻两级LOD的缝合链接: LODn--- LODn+1  (1:1),中间不会有2级以上的跳变。但是如果一个block是固定的级别f,那么对于所有的LOD级别,要处理LODf--LODn的缝合问题。

如果固定LOD级别f有n个,数量就是n:n(n对n),index buffer会呈指数级增长,非常浪费。如果固定LOD级别f比较少,比如只有两种: f=0 和 f=max(LOD),实际上index buffer的数量不会太多,

只需要生成2:n (2对n)的缝合。实际上1种或者两种就足够了,f=max(LOD)是针对平的地形block的优化,可有可无,一般地形里面纯平的地面比较少,除了像城市这种场景,里面可能会多点。

另外一种避免浪费的思路是,把中间和四个边的index buffer 拆开,因为中间是大部分index buffer的内容,边上的skirt缝合数据非常少,不管是1:1还是n:n,基本都可以忽略不计。这样每个block要分2个draw call,数量会double,但在开启批次合并时并没有损失。

2.LOD morhping的问题

如果一个block使用了固定LOD,顶点不会有任何改变,那么这个block的morphing已经没有意义了。原来的morhping数据反而会对固定LOD产生影响,导致一些不必要的高低起伏,表现为一些奇怪的凸起。

比如vertex buffer存储了morphing 高度, 就需要清除掉,使用原始高度,关闭morhping。同时,相邻的那些block, 如果不是固定LOD级别,也要清除掉一排边缘衔接顶点的morphing数据,否则一边没有morhping,另一边有,这样也有问题,会有裂缝。

3.LOD 索引生成的方式

假如有一个固定LOD级别f,那么对于f,要生成1对n的缝合。缝合的方式和正常的LODn--- LODn+1缝合方式类似,生成各个边的skirt。

主要问题是生成skirt的方式,可能会影响顶点插值效果。要尽量避免狭长的三角形,因为使用了fixed LOD的block,通常高度或者高度差很大,如果有狭长的三角形,那么他的两个顶点的高度可能差距很大,导致这个三角形的边非常突兀,具体表现为一个非常硬的边和旁边一个凹陷的坑(在加了shadow和AO之后更加明显)。

比如下面的这种就是不好的 (bad tesselation pattern of LOD skirt):

下面这种更好

最后发效果截图.。512x512地形, 6级LOD 从远处看:

下图是加载范围为1536x1536 (512x3)的地形,6级LOD。可以看到远处山的细节还在,近处纯平面的地形的三角形数量很低 (图中有bug已经修复)

另外,目前世界和地形的最大范围为16km(千米),因为原点在(0,0,0),范围为0~16km,损失了符号位的精度。如果将原点设置在-16km,范围为-16km~16km,世界最大范围就能达到32km。

关于最大范围的预估,可以根据IEEE754的浮点数来简单确认,float32的尾数位为23, 而游戏的最小精度大概要1毫米,即10-3,约等于1/1024 = 2-10, 要占用10位,剩下13位,就是8km,加上符号位是16km, 如果精度降低到2毫米,2-9,最大范围可以支持到32km。

如果要支持更大的范围,那么就需要用local坐标系或者类似的方法,或者再加上渲染前直接用物体和相机的相对位置,等等。工作太忙,暂时放后面有时间再做。


总的来说,ChunkLOD虽然比较老,没有充分利用现代GPU的优势,但是也比较适合大型世界,玩法也不算少,而且目前来说更适合mobile。如果是geometry clipmap的话,还没想过如何实现上面类似的效果。

---更新:clipmap也很简单,远处的高山也用高密度网格,采样mip用更高级的miplevel,比如0或者1,效果应该也是类似,但是也要处理缝合。

---更新2:因为clipmap周边低lod网格是空心的“回”型结构,所以高密度网格不管是直接做到这些低密度网格里,还是用缝合衔接,都比较复杂,并不简单。想到的可能方法,至少要对固定LOD的高密度网格分chunk,因为这些网格的形状(高LOD的范围)不固定。

引擎设计跟踪 地形LOD的改进的更多相关文章

  1. 引擎设计跟踪(九.14.2a) 导出插件问题修复和 Tangent Space 裂缝修复

    由于工作很忙, 近半年的业余时间没空搞了, 不过工作马上忙完了, 趁十一有时间修了一些小问题. 这次更新跟骨骼动画无关, 修复了一个之前的, 关于tangent space裂缝的问题: 引擎设计跟踪( ...

  2. 引擎设计跟踪(九.10) Max插件更新,地形问题备忘

    最近没有大的更新. 最近本来要做max的骨骼/动画导出, 看导出插件代码的时候, 突然想起之前tagent space导出的疑问, 于是确认了一下. http://www.cnblogs.com/cr ...

  3. 引擎设计跟踪(九.14.3.4) mile stone 2 - model和fbx导入的补漏

    之前milestone2已经做完的工作, 现在趁有时间记下笔记. 1.设计 这里是指兼容3ds max导出/fbx格式转换等等一系列工作的设计. 最开始, Blade的3dsmax导出插件, 全部代码 ...

  4. 引擎设计跟踪(九.14.2i) Android GLES 3.0 完善

    最近把渲染设备对应的GLES的API填上了. 主要有IRenderDevice/IShader/ITexture/IGraphicsResourceManager/IIndexBuffer/IVert ...

  5. 引擎设计跟踪(九.14.2f) 最近更新: OpenGL ES & tools

    之前骨骼动画的IK暂时放一放, 最近在搞GLES的实现. 之前除了GLES没有实现, Android的代码移植已经完毕: [原]跨平台编程注意事项(三): window 到 android 的 移植 ...

  6. 引擎设计跟踪 ShadowMap 细节和分析

    之前在工作总汇总了shadowmap的各种问题 [工作积累] shadow map问题汇总 最近有点时间再仔细研究了shadowmap的一些算法.主要修复了LiSPSM(上面链接里后面有更新),实现了 ...

  7. 引擎设计跟踪(九.14.2 final) Inverse Kinematics: CCD 在Blade中的实现

    因为工作忙, 好久没有记笔记了, 但是有时候发现还得翻以前的笔记去看, 所以还是尽量记下来备忘. 关于IK, 读了一些paper, 觉得之前翻译的那篇, welman的paper (http://gr ...

  8. 引擎设计跟踪(九.14.2d) [翻译] shader的跨平台方案之2014

    Origin: http://aras-p.info/blog/2014/03/28/cross-platform-shaders-in-2014/ 简译 translation: 作者在2012年写 ...

  9. 引擎设计跟踪(九.9) 文件包系统(Game Package System)

    很早之前,闪现过写文件包系统的想法, 但是觉得还没有到时候. 由于目前工作上在做android ndk开发, 所以业余时间趁热做了android的移植, 因为android ndk提供的mountab ...

随机推荐

  1. 在servlet中跳转问题

    跳转有重定向和转发 1重定向 2转发

  2. 实训任务04 MapReduce编程入门

    实训任务04 MapReduce编程入门 1.实训1:画图mapReduce处理过程 使用有短句“A friend in need is a friend in deed”,画出使用MapReduce ...

  3. phpstrom mac 快捷键

    对应键 ⌘——Command ⌃ ——Control ⌥——Option/Alt ⇧——Shift ⇪——Caps Lock fn——功能键就是fn 编辑 Command+alt+T 用 (if..e ...

  4. 零基础IDEA整合SpringBoot + Mybatis项目,及常见问题详细解答

    开发环境介绍:IDEA + maven + springboot2.1.4 1.用IDEA搭建SpringBoot项目:File - New - Project - Spring Initializr ...

  5. 一个C++右值引用的问题

    暂时先不更新前一篇文章了,感觉那个文章要写好久.累死. 今天说一说C++右值引用的一个问题. 这个问题的发现也是很偶然的. 来一段毫无意义但是能证明问题的代码: std::string &&a ...

  6. 安装vue脚手架和vue安装element-ui

    首先下载安装node.js,因为vue依赖node.js,然后用npm安装vue,步骤如下: 安装成功后安装element-UI,步骤如下: 完成后用npm run dev 运行项目.

  7. 二、Memcached缓存穿透、缓存雪崩

    二.Memcached缓存穿透.缓存雪崩 1. 缓存雪崩 可能是数据魏加载到缓存中,或者缓存同一时间大面积失效,导致大量请求去数据库查询的过程,数据库过载,崩溃. 解决方法: 1 采用加锁计数,使用合 ...

  8. web语言发展史

    引用自CSDN,地址:https://blog.csdn.net/moshenglv/article/details/51590830 提到Web,不得不提一个词就是“互联网”.Web是World W ...

  9. 最近在学习Flask框架,那么就说下jinja2吧~~~

    jinja是组成Flask的模板引擎,先写一个demo吧 {% block body %} <ul> {% for user in users %} <li><a hre ...

  10. 阻止事件冒泡传播stopPropagation() 阻止自身默认行为preventdefault()

    stopPropagation       简单理解:子元素的点击事件  不会去触发父元素的点击事件 preventdefault       简单理解:当点击提交按钮时(submit)   阻止对表 ...