欢迎光临散文网 会员登陆 & 注册

BlockOS开发日志(二)着手设计方块世界

2023-02-27 15:52 作者:Zerous  | 我要投稿

刚发完第一篇总结性质的文章,那么就趁热打铁,先把方块世界的设计方案在这写明白。

如何渲染

首先如何在电脑上渲染出这些方块就是一大问题。在mc的1.18版本前,方块的数量就非常多。java版mc的渲染距离应该是256*256*256,如果让这个距离里填满方块,那么这片区域的方块数量将是16777216个。回顾下图形学基础知识,每个立方体有六个面,每个面有两片三角形,每个三角形有三个顶点,假设顶点数据只有位置和uv,也就是3+2=6个浮点数,单精度浮点数的字节数为4,那么直接用立方体渲染这些方块需要16777216*6*2*3*6*4=14495514624字节,也就是13.5GB。显然没那么多显存给我们耗,而且从内存到显存的带宽(以GTX1050Ti为例,112GB/s)也不足以支撑60fps的刷新率,CPU除了做数据传输,也是要跑逻辑的啊(这就先当单核看)。因此合批渲染(Batch Rendering)是必需的。有人可能说,我用Instanced Rendering一样可以啊,确实好像可以,数据确实少了,但是还有个DrawCall的问题没解决...这里参考(偷)mc里的设计,按照一个渲染单元(mc里叫Section)为16*16*16个方块进行渲染。这样做的好处是可以将数据整合成一大块传输给显卡,提高传输效率,减少DrawCall,也可以手动写出来简单高效的面剔除算法。坏处就是没办法定位到渲染单元中特定的一个方块了,因为做了面剔除之后,暴露多的方块比暴露少的方块传输的数据多,各方块占用的顶点数据参差不齐,这就造成了每次放置和破坏方块的时候都需要重新计算渲染单元的网格的问题。

经过以上的思考以及摸着mc过河,我决定使用合批渲染的办法来渲染这个方块世界。下面简单描述一下合批的算法思路:在每个渲染单元生成时,首先对其内部的方块按照x,y,z轴的顺序依次遍历。对每个方块,首先查询其上下左右前后方向上的方块是否为透明方块,如果全都不是,那么就跳过该方块。如果某一方向是透明方块,那么就将这个方向的模型数据并入渲染单元。

问题解决了吗?并没有完全解决。因为除此之外,还有不完整方块、半透明方块和带动画的方块存在。

不完整方块
半透明方块

先解决最容易的不完整方块的剔除问题。所以进一步的思路是将上面算法的扫描结果作为一系列标志位写入一个Flags枚举变量,然后将其作为参数输入到以面为最小单位构建方块模型对象中。这个方块模型对象的每个面都拥有一个掩码,在实际的建模过程中方块模型会向这些面对象分发这个枚举,如果该面的掩码和该枚举的按位与运算结果不为0,就将该面所持有的模型数据并入到渲染单元中。

对于半透明的方块和动画方块,我目前还只是停留在一个初步轮廓的阶段。比如对于玻璃这样的部分全透明部分不透明的方块,可以直接写着色器丢弃透明的片段而不做颜色混合,而如果是冰或者彩色玻璃一类的方块,可能就要用到各种OIT技术。我对这方面的认知还是不完全,还得去做做实验补补课。而动画方块呢,我认为可以学习戴森球计划开发组的策略,将这些可动的方块都用Instancing渲染然后用Uniform的方式把当前帧传给顶点着色器的方式来做动画。但是需要为每种动画方块编写着色器,工作量可能有点大。

如何用数据表示

因为之前看过mc的Nbt存档并且写过MagicaVoxel的模型读取器,所以世界的数据表示我也是相当思维定式地采用了“调色板”的方法(感觉和图形API中使用index buffer来减少顶点输入的思路也是类似的)。好处当然是可以有效缩减空间占用,坏处是增大了复杂程度从而提高开发难度和维护成本。

这里也直接用一下mc里的术语,把一组方块称之为区块。那么就接着理一下区块的数据结构。最基础的区块,由两个表组成,一个是索引表,一个是方块元数据表。索引表表示在哪里有哪些方块,方块元数据表表示区块内总共有哪几种方块。为什么不直接用一个方块ID的三维数组?因为随着元数据的不同,方块的外观和性质都可能不一样。比如草方块和覆雪草方块,点亮和熄灭的红石火把等。这个设计足以实现mc早期的各种方块,但是还有一类会自我更新的方块无法实现。如熔炉等。所以mc加入了“方块实体”的概念,玄学点说方块实体可以理解成是背后操纵方块的傀儡师,随着放置方块而来,拆除方块而走,也可以顺着线(坐标)找到它来查询方块更细节的数据。所以还存在一个跟随游戏更新而更新的方块实体列表。

这个我也不知道是思维定式还是殊途同归,总之想来想去发现做体素世界的数据结构都大体相同,就先这么做着吧。如果有更好的想法也欢迎到评论区讨论。

下一篇就是这个方块世界的实现篇了,我大概会在里面写一写踩坑经历和技术难点。

参考

https://fabricmc.net/wiki/tutorial:blocks

https://minecraft.fandom.com/zh/wiki/%E5%8C%BA%E5%9D%97%E6%A0%BC%E5%BC%8F

https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/03%20Blending/

https://indienova.com/indie-game-development/dyson-sphere-devlog-4/

BlockOS开发日志(二)着手设计方块世界的评论 (共 条)

分享到微博请遵守国家法律