简介
开始尝试做开放世界游戏,记录用的插件和要考虑的东西
地形切割
- 提供对于Unity Terrain组件进行切割,并生成多级Low网格
- 在设定区域内使用Terrain,区域外则使用Mesh渲染处理后的Low网格
- 地形会切割成多个场景,提供场景流式加载
- 场景的异步加载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49IEnumerator LoadAsync()
{
// yield return new WaitForSeconds(0.5f);
//Debug.Log("scenesToLoad " + scenesToLoad.Count);
int[] sceneLoadIndexes = new int[scenesToLoad.Count];
for (int i = 0; i < scenesToLoad.Count; i++)
{
int sceneID = SceneManager.sceneCount;
SceneSplit split = scenesToLoad[i];
AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(split.sceneName, LoadSceneMode.Additive);
asyncOperation.completed += (operation) =>
{
SceneLoadComplete(sceneID, split);
OnOperationDone(operation);
};
asyncOperations.Add(asyncOperation);
yield return null;
}
scenesToLoad.Clear();
//Debug.Log("Load finished " + asyncOperations.Count);
operationStarted = false;
}
IEnumerator UnloadAsync()
{
yield return null;
//Debug.Log(asyncOperations.Count);
for (int i = 0; i < scenesToUnload.Count; i++)
{
AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(scenesToUnload[i]);
asyncOperation.completed += OnOperationDone;
asyncOperations.Add(asyncOperation);
yield return null;
}
scenesToUnload.Clear();
//Debug.Log("Unload finished " + asyncOperations.Count);
operationStarted = false;
}
- 场景的异步加载
- 浮点数错误修复系统,根据设置,在移动指定数量格子后,将整体位置移动到原点,不会产生,浮点数过大导致的浮点数精度问题
地形贴图混合
地形和Mesh混合
图形引擎实战:移动端URP地形贴图融合与HBAO实现 - 搜狐畅游引擎部的文章 - 知乎
地形LOD的poping问题
为了避免两个LOD级别之间的突变,可以使用简单的线性插值,通过线性插值因子从0-1的变换,实现LOD的变换
- CDLOD
- CDLOD过渡算法
-
基于使用在顶点着色器中置换的固定网格网格来直接从高度图数据源渲染地形
Continuous Distance-Dependent Level of Detail for Rendering Heightmaps (CDLOD) - 生鱼片的文章 - 知乎
ShaderToy
1 |
|
PCA压缩
地表贴图压缩:7通道2采样→4通道1采样 - profhua的文章 - 知乎
使用PCA,对贴图进行压缩
网易GDC2023中提到将 PBR 所需要的 diffuse(rgb)、normal(xyz)、ao、roughness、metallic,总共九个通道,通过 PCA 压缩成 一张具有4通道的贴图
【GDC2023干货分享】90帧高质量写实手游的程序实现与美术设计 - 网易游学的文章 - 知乎
大片草地
草地编辑器
插件存在的问题
- 剔除操作是对所有存储在显存中的草数据,对做一遍视锥体裁剪,开销比较大
- 优化方式 1:UnityURP-MobileDrawMeshInstancedIndirectExample 里用到的裁剪方式,将草根据位置划分为一个个AABB,CPU计算AABB的裁剪结果,然后传递给GPU,ComputeShader只需要计算通过视锥裁剪的草数据,而不是全部数据
- 优化方法 2:作者后续更新,通过四叉树对空间进行划分成AABB,然后进行剔除,和方式1一样
- 交互方式上,只是根据传递的角色位置,顶点进行相应偏移,不适用于多个移动物体
- 优化方式:UnityURP-MobileDrawMeshInstancedIndirectExample 中,将角色运动轨迹用LineRenderer保存,将这个结果存为一张RT图,保存法线信息,采样这张RT图可以得到相应路线结果,可以设置相关参数控制草地从被压扁到恢复的时间
- 没有写入深度,会导致渲染时结果被覆盖
草地和地形贴图混合
大气渲染
altos
可以提供动态日夜切换,指定太阳、月亮贴图,提供体积云,并有次表面散射效果
细节记录
问题:云的结果把草的结果覆盖了
原因:草地编辑器没有写入深度法线信息,需要添加对应的Pass
解决后效果
1 | Pass |
全局光照
使用天空盒或固定颜色实现的环境光不能有效的适应周边环境和动态光源,可以通过预辐射度全局光照实现
Unity自带的实时全局光照,目前仅支持Buildin,SRP计划在Unity2024后支持
阴影
用的Unity自带的级联阴影,四级感觉够了,八级感觉没必要,根本看不到
动物生态
计划用行为树简单的实现,主要包括以下行为
- 行为模拟,食物搜索、躲避捕食者
- 领地模拟,动物在领地之间会产生相互竞争和冲突
- 群体行为,模拟动物群体间的领导、集体防御行为
- 环境交互,对环境的交互性,包括地形、季节、气候的处理,饮水、觅食
Boids算法,可以实现集群行为.将个体行为分为规避、结盟、凝聚共同作用。
Vector3 direction = separation+ alignment + (cohesion - boid.position).normalized;