# 渲染系统

# 渲染系统

渲染系统负责整个渲染管线的驱动、全局配置管理等等,可以认为就是其将所有渲染需要的资源串联起来,转换成一系列的渲染指令到渲染硬件接口(RHI),再交给不同的图形 API 去执行真正的绘制。

在小游戏框架的角度,渲染系统主要包括game.renderSystemengine.renderEnv两个单例,以及后续章节的渲染图(Render Graph)。

# renderSystem

renderSystem是游戏game下的一个单例,其作为整个渲染系统驱动的入口。由于是入口,所以其功能也比较简单,主要是管理一些配置信息,大部分的工作都是由它管理的模块负责的。

开发者需要关心的renderSystem相关的功能如下:

  1. screen:主屏,可以设置给相机。
  2. setting:全局渲染配置。
  3. renderGraph:当前使用的渲染管线,后面会说道。

当然还有一些方法:

// 通过某个特定的剔除结果列表中的`id`,获取对应的`MeshRenderer`
renderSystem.getMeshById(id);

// 启用某个渲染管线
renderSystem.useRenderGraph(rg);

# renderEnv

在 game 级别的renderSystem之外,还有一个 engine 级别的单例renderEnv供开发者调整和获取一些全局信息,其中的部分接口甚至能够允许开发者脱离框架完全定制属于自己的渲染管线,详见深入渲染管线,不过在这里我们只需要了解其中的部分功能即可:

首先是一些信息的获取:

  1. version:获取渲染 Backend 的版本,比如1.2、1.3。
  2. backendType:获取渲染 Backend 的类型,比如WebGL。
  3. canvasWidth:画布的宽。
  4. canvasHeight:画布的高。
  5. supportCompressTextures:支持的压缩纹理类型。
  6. features:当前支持的渲染特性列表,比如dynamicBatch3D

除了这些信息,开发者还可以理由一些方法来定制一些全局配置。

首先是效果Effect,在实际渲染过程中,我们会使用某种 lightMode 去渲染一个批次,但在这批渲染中很可能有些 Material 拥有的 Effect 并不具有拥有这种 lightMode 的Pass,这就需要一个针对于这种 lightMode 的默认材质:

// 为某种`lightMode`注册一个默认的降级材质
renderEnv.registerFallbackEffect(lightMode, effect);

// 取消注册降级材质
renderEnv.unregisterFallbackEffect(lightMode);

除此之外,在之前效果与材质我们也提到过关于宏和 UniformBlock 均有全局的部分,而这个全局的部分其实也是在这里设置的。

# 全库宏

首先是全局的宏。全局的宏和 Material 的宏一样,也是控制 Effect 内定义好的宏的开关的,只不过其影响的维度是全局所有的Effect。

全局宏有两种形式,一种是直接宏:

// 设置一批全局宏,以{key: value}的形式
renderEnv.changeMacros(macros);

// 获取一个全局宏
renderEnv.getMarco(key);

直接宏理解起来很简单,开销也低一些,但其有一个问题——不能和 Material 的宏冲突

为了解决这个问题,小游戏框架还提供了另一种方法,来稍微增加开销但是更灵活,即全局虚拟宏

// 设置一批全局虚拟宏,以{key: value}的形式
renderEnv.changeVirtualMacros(macros);

// 获取一个全局虚拟宏
renderEnv.getVirtualMacro(key);

虚拟宏和普通的宏不同,其相当于某个宏的总开关,其牺牲一小部分 CPU 的开销,来保证最大的相容性。

如果没有特殊的必要,建议总是使用虚拟宏。

# 全局Uniform

全局 Uniform 最终是在 renderEnv 中设置的,但为了方便管理,小游戏框架为了单独做了一套体系,用于让开发者方便地构建和管理自己的全局Uniform。

为了创建属于自己的全局Uniform,开发者首先需要在project.config.jsonglobalSetting字段中添加:

{
  "globalSetting": {
    "shaderGlobalProperties": [
			{
				"key": "_GlobalMainLightDir",
				"type": "Vector4",
				"default": [
					0,
					0,
					0,
					0
				]
			},
			{
				"key": "_GlobalMainLightColor",
				"type": "Vector4",
				"default": [
					0,
					0,
					0,
					0
				]
			}
		]
  }
}

之后便可以使用下列方法修改和获取全局Uniform:

engine.setGlobalFloat(key, value);
engine.getGlobalFloat(key);
engine.setGlobalVector(key, vector);
engine.getGlobalVector(key);

注意,目前只支持 Float 和Vector类型的Uniform。

在运行时设置完了以后,还需要在着色器中定义中使用,如果对应不上则会不生效。