高度图压缩后的边界处理
几年前我曾经写过一篇 blog 介绍我发明的一种高度图压缩算法 。最近几天,我将这个算法用于目前正在开发的 engine ,如之前所料,效果不错。由于数据被压缩,更改善了资源加载的速度。并在同等内存条件下,让用户得到更高的体验。(这是因为,现代操作系统,都会把暂时不用的物理内存全部用于磁盘缓存,更小的文件体积同时意味着在同等内存条件下能缓存更多的数据)
因为我们需要做动态地形数据的加载,所以地形高度数据也被切割成了一小块一小块。采用这个算法后带来的一个问题是:由于压缩有数据损失,两个相临块之间不能严丝合缝的衔接在一起。
为了解决这个问题,这两天想了好几个方法。
相临的数据块的接缝上,每个顶点被拆分成了两个。数据未压缩前,拆分出来的顶点值应该完全相等。最容易想到的方案是,每次加载完一个地形块,就去查看周围的块是否有加载入内存,如果有,就把邻接边的数据 copy 一份过来。
但这个方案增加了数据间的耦合度,同时导致在数据读取层的代码需要从更高的层次上获取数据。这会破坏 engine 的设计,故而放弃这个方案。
另一个方案是将边界上的一圈高度信息,以无损方式额外保存。但是我们每个地形块的数据本身不多,这将会极大的损失好不容易获得的压缩比。
今天白天,我一直在想如何有效的保存轮廓信息。想到了一些方法会轮廓上的顶点增加额外的精度(大约每个顶点多使用一个字节)。代码写了一堆,实现出来却不太满意,因为直觉告诉自己,我把问题弄复杂了。
晚上去健身房活动了一下,回来的路上突然灵机一动,想到一个最为简洁的方案。
其实,不应该从提高边界上顶点的精度(甚至是无损)这方面努力。我们需要的仅仅是让邻接的地块可以无缝连接,也就是说,邻接线上的顶点高度值应该一一相等。
其实,让我们降低结果浮点数的精度就够了。关于实际操作的方法,很早以前我在留言本上发过帖子。Blog 上也有一个帖子讨论过 EPSILON 取值的问题
这次我这样实现(把要降低精度的浮点指针传入即可):
static __inline void reduce_precision(float*fdata) { uint32_t *d=(uint32_t *)fdata; *d=(*d + 0x8000) & 0xffff0000; }
ps. Spore 是个好游戏。
9 月 6 日补充: 这个方法对于在 0 附近的数值为有问题,因为它不能处理正负号所以应该要注意。解决方法很简单:发现数值绝对值小于 1 即浮点指数是负数的时候,把值先加一再做上述处理,然后再减一。
另外对于跨越指数边界的时候可能会出现问题,比如一个值的底数是 1.11111111111 而另一个是 1.000000000 , 而指数差了一位。解决这个问题应该手工判断进位。
有人提到法线,其实法线是按常规方法从顶点高度中推算出来的。可以多保存一圈顶点。也可以在轮廓上用较少顶点来计算。法线的细微差别不会对视觉上有太大影响。(从我们的渲染结果上看是这样)
9 月 10 日再补充: 如果只是想去掉绝对数字上的浮点精度,比如去掉十进制小数点大约 4 位以后的偏差。可以如此:
a+=8192.0f; a-=8192.0f;
这样便可以将 a 降低精度。原理不详述。另外在写程序的时候应该想办法防止编译器优化掉上面的代码。
Comments
Posted by: varg | (20) July 16, 2011 12:44 AM
Posted by: Anson Ling | (19) October 13, 2008 02:05 PM
Posted by: Jet Wong | (18) September 23, 2008 02:41 AM
Posted by: Cloud | (17) September 20, 2008 09:14 PM
Posted by: chenyujie | (16) September 20, 2008 07:29 PM
Posted by: Cloud | (15) September 19, 2008 07:55 PM
Posted by: chenyujie | (14) September 19, 2008 04:28 PM
Posted by: david | (13) September 17, 2008 05:12 PM
Posted by: Cloud | (12) September 10, 2008 05:54 PM
Posted by: plainroc | (11) September 10, 2008 09:24 AM
Posted by: plainroc | (10) September 10, 2008 09:09 AM
Posted by: Cloud | (9) September 6, 2008 01:54 AM
Posted by: Zwinger | (8) September 5, 2008 12:44 PM
Posted by: liuzhi | (7) September 5, 2008 10:32 AM
Posted by: sjinny | (6) September 5, 2008 09:49 AM
Posted by: xiumu | (5) September 5, 2008 08:17 AM
Posted by: Zhe | (4) September 5, 2008 08:00 AM
Posted by: Anonymous | (3) September 5, 2008 07:50 AM
Posted by: rayment | (2) September 5, 2008 07:46 AM
Posted by: Anonymous | (1) September 5, 2008 07:42 AM