当前位置: 网站首页 >> 热点 > >> 正文

BlockOS开发日志(四)面标志位、密度场和广度优先遍历

时间:2023-04-13 00:53:20   来源:哔哩哔哩

把开发日志按大章节从设计到实现来写感觉很有节奏感,很Nice。以后都这样做吧。

在前面的设计中提到,面对海量的方块,把这些方块看作为单独的个体设计带来的性能开销是现在所有电脑都不能接受的,因此需要将这些结构简单的方块合成一个结构稍微复杂的大模型处理,这样可以有效减少性能开销。

面标志位和面掩码

为了表示方块六个面的有无,我联想到了计算机科学中常用的设计:标志位和掩码。使用一个比特的6个位,从低到高,依次表示从正x,y,z方向到负x,y,z方向的有无。比如000001,表示x轴的正方向;000111表示x,y,z的正方向。这么排列有一个小小的好处:只要循环位移3位,就可以取到反方向的标志位。


(相关资料图)

确定了方向的表示方式后,我设计了一种专用于这种方块世界的模型格式。在这个格式中,模型由材质绑定点和数个子网格构成。它的独特之处在于,除了传统的顶点数据之外。模型中还额外包含了不透明面标志位(Opacity Flags),子网格中包含了暴露面标志位(Exposure Flags)。在以后的生成具体区块网格的过程中,会根据由区块方块的不透明面标志位组成的不透明密度场生成暴露密度场,然后依据这个暴露密度场来具体计算每个方块需要提供的网格。

下面是一个用我定义的模型格式表示的普通方块。这个格式是用我自己用C#实现的Lisp解释器来进行解析的。和Lisp比较像。

以上这个标志位和场的设计灵感来自《GPU Gems3》中的第一篇论文:Generating Complex Procedural Terrains Using the GPU。

密度场

在区块生成时,首先会为根据区块存储的方块的不透明面标志位生成不透明密度场,和按照全部不暴露初始化的暴露密度场。

接着遍历这个不透明密度场,如果在区块中某个方块的不透明面标志位表示某方向的位为0,那么就给这个方块在这个相邻方向取反的暴露面标志位置1。

用语言描述这段代码实在是有点绕...直接上一段代码吧。

看代码还是绕,硬要理解的话可以这么想象:把每一个遍历的格子想象成里面有一个盲人。首先盲人在格子里面,如果格子某个面不透明,那么这个盲人就出不去。如果这个面透明,那么盲人就能走出格子,去摸上下左右前后的方块,如果摸到了(该面不透明),那么就会报告给统计员该位置方块是暴露的。

然后由这个像是积分的过程得出最终的暴露密度场。最后遍历这个暴露密度场,让这一格的暴露面标志位和模型子网格的暴露面标志位做按位与,如果结果等于模型子网格的暴露面标志位,那么就代表这个子网格需要被添加到区块模型中。

广度优先遍历

在开发过程中突然回想起不知道多少年前看过的一篇Mojang写的博客,介绍MCPE的剔除算法的。印象里那篇博客还按曼哈顿距离画了一张菱形像素图,而且以一定的透明度叠加上了Minecraft的区块示意图。

这让我意识到,是不是可以不用遍历所有方块,而是使用广度优先搜索?

思考了一下,确实可行,从玩家眼睛所在的方格出发,按照一定的曼哈顿距离使用广度优先遍历的方式,模拟一群盲人人行走。可以减少不少的被埋在深处的方块的遍历。

最终遍历的方式也从暴力遍历改成了广度优先遍历的形式。

还有吗?

我其实已经可以想到用并发的方式来批量计算它们了,这是完全可行的。这个步骤做一下类比,像极了用计算着色器去做图像模糊算卷积核的过程。只不过维度从二维升到了三维而已。

不过因为时间问题只好留待以后优化了。

最后贴一张渲染出来的成品区块

关键词:
x 广告
x 广告

Copyright ©  2015-2022 华东游戏网版权所有  备案号:京ICP备2022016840号-41   联系邮箱:2 913 236 @qq.com