引擎设计跟踪 地形LOD的改进
虽然地形已经有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的改进的更多相关文章
- 引擎设计跟踪(九.14.2a) 导出插件问题修复和 Tangent Space 裂缝修复
由于工作很忙, 近半年的业余时间没空搞了, 不过工作马上忙完了, 趁十一有时间修了一些小问题. 这次更新跟骨骼动画无关, 修复了一个之前的, 关于tangent space裂缝的问题: 引擎设计跟踪( ...
- 引擎设计跟踪(九.10) Max插件更新,地形问题备忘
最近没有大的更新. 最近本来要做max的骨骼/动画导出, 看导出插件代码的时候, 突然想起之前tagent space导出的疑问, 于是确认了一下. http://www.cnblogs.com/cr ...
- 引擎设计跟踪(九.14.3.4) mile stone 2 - model和fbx导入的补漏
之前milestone2已经做完的工作, 现在趁有时间记下笔记. 1.设计 这里是指兼容3ds max导出/fbx格式转换等等一系列工作的设计. 最开始, Blade的3dsmax导出插件, 全部代码 ...
- 引擎设计跟踪(九.14.2i) Android GLES 3.0 完善
最近把渲染设备对应的GLES的API填上了. 主要有IRenderDevice/IShader/ITexture/IGraphicsResourceManager/IIndexBuffer/IVert ...
- 引擎设计跟踪(九.14.2f) 最近更新: OpenGL ES & tools
之前骨骼动画的IK暂时放一放, 最近在搞GLES的实现. 之前除了GLES没有实现, Android的代码移植已经完毕: [原]跨平台编程注意事项(三): window 到 android 的 移植 ...
- 引擎设计跟踪 ShadowMap 细节和分析
之前在工作总汇总了shadowmap的各种问题 [工作积累] shadow map问题汇总 最近有点时间再仔细研究了shadowmap的一些算法.主要修复了LiSPSM(上面链接里后面有更新),实现了 ...
- 引擎设计跟踪(九.14.2 final) Inverse Kinematics: CCD 在Blade中的实现
因为工作忙, 好久没有记笔记了, 但是有时候发现还得翻以前的笔记去看, 所以还是尽量记下来备忘. 关于IK, 读了一些paper, 觉得之前翻译的那篇, welman的paper (http://gr ...
- 引擎设计跟踪(九.14.2d) [翻译] shader的跨平台方案之2014
Origin: http://aras-p.info/blog/2014/03/28/cross-platform-shaders-in-2014/ 简译 translation: 作者在2012年写 ...
- 引擎设计跟踪(九.9) 文件包系统(Game Package System)
很早之前,闪现过写文件包系统的想法, 但是觉得还没有到时候. 由于目前工作上在做android ndk开发, 所以业余时间趁热做了android的移植, 因为android ndk提供的mountab ...
随机推荐
- nopcommerce 4.1 core 学习 增加商城配置属性
需求: 原本是想用nop 来做国际版的商城,可以像亚马逊那样 国内外通用, 专门增加一个跨进元素属性. 学习里面的一些架构思想. 国内的行情还是 像himall 会比较实用. 这是在商城的综合 ...
- spark中map与mapPartitions区别
在spark中,map与mapPartitions两个函数都是比较常用,这里使用代码来解释一下两者区别 import org.apache.spark.{SparkConf, SparkContext ...
- LeetCode 547 朋友圈
题目: 班上有 N 名学生.其中有些人是朋友,有些则不是.他们的友谊具有是传递性.如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友.所谓的朋友圈,是指所有朋友的 ...
- python的标识符
1.在pyhon中,标识符由字母.数字.下划线组成 2.在python中,所有标识符可以有字幕,下划线开头,但不能以数字开头 3.python的标识符是区分大小写的 4.以下划线开头的标识符是有特殊意 ...
- day02 while循环 运算符 格式化输出 编码
今日主要内容 while循环:判断条件是否成立. 如果成立执行循环体.然后再次判断条件,.....直到条件不成立的时候跳出循环 语法: while 条件: 循环体 else: 当条件不成立的时候执行 ...
- 万维网(WWW)
简介:万维网(WWW)是 Internet上最为普及的一种应用服务,它是由成千上万万维网站点(简称网站)组成的一个联机信息存储系统. 万维网的工作模式采用客户机/服务器方式,在用户计算机上运行浏览器作 ...
- 2017年5月12日15:10:46 rabbitmq不支持非阻塞调用服务器
就像昨天碰到的问题描述一样,问题不是出在消费者上而是在生产者发送消息出现没有得到返回值时消息通道被挂起,rabbitmq发送的消息是阻塞调用即当发生阻塞时,继续发送的消息都堆在后面.在网上看到有两个方 ...
- 虚机配置vip命令行配置
测试脚本:import osimport re import urllib from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler ...
- python之路之简单介绍:
python介绍: a. python 基础 - 基础 - 基本的数据类型 - 函数 - 面向对象 python 安装 python 安装在os上 执行操作: 写一个文件,文件中按照python规则写 ...
- Linux 驱动——Button驱动7(Timer)消抖
button_drv.c驱动文件: #include <linux/module.h>#include <linux/kernel.h>#include <linux/f ...