本文目标
- 分析三国:谋定天下的场景渲染技术,提高技术力。主体思路用三谋的,具体实现可能不会完全用和三谋一样的方案
- 集赞,如果点赞收藏超过512,我给大家伙手搓一个三谋场景实现
分析方法
- 三谋官方技术分享
- RenderDoc截帧
- 我寻思大法
使用RenderDoc截帧分析地形实现方法
结论
- RenderDoc可以连上mumu模拟器,连不上雷电模拟器
- 地形一块一块绘制,没有合批
- 三谋截帧中没有看到compute shader的代码
- 三谋使用渲染着色器完成地形表面贴图烘焙、编码,Culling在CPU中完成
- 三谋的场景渲染技术在小程序下也可以使用
RenderDoc调试compute shader
- https://renderdoc.org/docs/how/how_debug_shader.html#debugging-a-compute-thread
渲染着色器中structuredbuffer是否存在?
不存在,根据RenderDoc截帧shader代码,看到使用的uniform data,所以支持opengles3.0
glsl知识
UBO
- Uniform Buffer Object
- UBO通过GL_UNIFORM_BUFFER缓冲类型绑定,常用于只读类型的数据
- 需要ES 3.0,大部分设备都支持
- 可以认为ES 3.0 约等于 WebGL2,所以微信小程序也能跑
Uniform Buffer Objects
- 小容量的结构体数组,一般16k以内
- 需 ES 3.1+
SSBO
- Shader Storage Buffer Object,大容量的结构体数组
- Mali平台使用SSBO会导致early-Z失效
- 需 ES 3.1+
三谋的一些技术数据
- 7级LOD,0到6,每加一层,尺寸翻2倍,面积翻4倍
- LOD6常驻,最小的一块地3.2x3.2平米,LOD6面积204.8x204.8
- 全图1200x1200,1500x1500个格子
- 每一级 LOD 都会加载距离视野中间点最近的 5×5 个地块进内存,一共是 25×7,175 个地块
- 整个场景拆分成 36 个分组,每个分组下面包含了 16 个 Unity 节点,每个节点覆盖了 51.2 米的范围
- 全量导出地形2分钟,增量导出地形几秒
- Splat图
- Splat 贴图包含了 17×17 个 block,每个 block 包含 32×32 个控制点,并且覆盖 3.1×3.1 米的区域,Splat 的贴图尺寸是 544×544
- 所有的 Splat 贴图加起来是 53.3 兆
- 一块地形是51.2米方形,导出544×544的Splat图
- 渲染 LOD0 到 LOD4 chunk 时,只需要采样一张 Splat 贴图
- 渲染LOD5往上的地形时,用LODn-1的Splat图合并缩放成544x544尺寸作为LODn的Splat图
- block 现在是 32×32 的,所以它存储在 ASTC8×8 中是不会有插值问题的,但是如果 block 是 36×36,那就只能是使用 ASTC6×6 或者 4×4 这种格式了,要让它整除 36
- IDMap图
- IDMap 只有一张全局的,贴图宽度是 24×17 408 个像素,每个 IDMap 的像素需要两个字节存储 4 个 ID
- 一块地形一个ID图,17x17个block,每个block需要4个id,所以id图应该是17x17,怎么就24x17了呢?
- IDMap 只有一张全局的,贴图宽度是 24×17 408 个像素,每个 IDMap 的像素需要两个字节存储 4 个 ID
三谋场景渲染优化点
低视角下内存优化
分析
- 从LOD6到LOD0之间的所有资源都会加载,但只显示最低一层的LOD,并且是LOD6到LOD0加载,最终视野内显示的都是LOD0的资源
- 一共36个LOD6的分块,同一时间最多同时显示4块LOD6,所以三谋的内存压力蛮大
优化
- 不加载子LOD的全部分块资源,只加载视野内的地块资源
- LODn的当前视野内child chunk加载完毕后就算加载完成
实现三谋地形方案
思路
- 结构:分块,LOD分父子级
- 资源:Mesh LOD + RVT + RVT自定义编码
- 显示逻辑:LOD0常驻内存,多个LOD同时显示,但只会和差一级的LOD相邻,LOD之间互相不覆盖
编辑器下处理地形
主流程
- 美术制作地形
- 生成模型
- 生成模型LOD:减面后切割地形
制作地形
unity的terrain或者外部软件
生成模型
地形转模型:T4M(terrain for model)
生成LOD chunk资源
- 减面后切割地形,要求地形尺寸是51.2米方形,如果不是则需要输出LOD chunk资源配置文件,事情会变得复杂点,不过可以用来改造老项目
- LOD模型 = 减面(生成的地形模型, LOD)
- LOD的分块模型 = 切割(每一层LOD模型)
- LODn贴图 = 降分辨率(合并分块(LODn-1))
- splat图
- 对不是地形的物件减面,降分辨率
减面工具
Simplygon:微软出品
https://github.com/huailiang/lod
unity官方
https://github.com/Whinarn/UnityMeshSimplifier
生成LOD资源
https://github.com/Unity-Technologies/AutoLOD
切割模型工具
自己写代码:https://www.bilibili.com/opus/693401957195317251
插件:eazy-slicer
切割地形
根据制作方案切,以unity terrain为例
自己写切割脚本
https://blog.csdn.net/yang973125061/article/details/135480007
Unity Terrain Tools自带的切割工具
TerrainSlicer:可能有缝,需要额外处理接缝,对齐相邻地形即可
https://assetstore.unity.com/packages/tools/terrain/terrain-slicer-180920?srsltid=AfmBOopOV1fHjgjR6BN3eTZ-UCgFOvWjQtQBuKWugWKBQxgKV28xbioQ
Terrain Split and Merge Utility:无缝
https://assetstore.unity.com/packages/tools/utilities/terrain-split-and-merge-utility-209845?locale=zh-CN&srsltid=AfmBOoo3svPC8fi9yF29XKuh7CcBw2sa7ceZp_eaecjt7VGzuyWzUvic
资源构成
地形LOD chunk Mesh,材质,贴图,shader,RVT
物件LOD Mesh,材质
绘制
地形
烘焙
理论上可以使用共265个图层,目前支持16个图层,但单像素只支持4层混合
使用渲染着色器烘焙Albedo + Normal
Albedo = 渲染Albedo(IDMap, Splat, 图层贴图数组)
Normal = 渲染Normal(IDMap, Splat, 图层贴图数组)
RVT = 管理(Albedo, Normal)
地形着色器
Albedo + Normal + Roughness
RG:Noraml,B:Roughness
简化: Albedo + Normal
处理接缝
三谋的接缝是因为加载规则,LODn和LODn+2相邻,贴图精度不一致导致问题,只要让lodn+2采样高精度贴图即可
其它物件
绘制:路、山体、贴花等
采样地形RT把颜色叠加到物体上使用AlphaBlend做融合过渡:根据世界坐标计算归属LOD、chunk,查询Albedo
参考资料
- 三谋分享:https://developer.unity.cn/projects/671f499dedbc2a001e2ddc77
- RenderDoc连mumu模拟器:https://zhuanlan.zhihu.com/p/664975271
- https://renderdoc.org/docs/how/how_debug_shader.html#debugging-a-compute-thread
- 减面:https://zhuanlan.zhihu.com/p/360524404