背景
作为一名游戏开发者,我在过去10年中积累了很多项目的经验,同时我也想把自己在大公司的经历分享给大家。为此,我在2021年出版了一本书《Unity3D高级编程:主程序员笔记》。书中记录了我过去做过的所有项目的各个模块的技术点3D角色,包括框架、算法、原理、优化方案(博客:)。同时,通过这些经历,我深刻认识到引擎作为游戏开发的基础构建和底层逻辑的重要性。这些年来,我对引擎也有了自己的理解,近几年通过对引擎的解剖和分析,对其模块结构、流程、技术原理、实现方法等都有了深刻的理解。
最近突然有个想法,想系统地剖析一下游戏引擎,于是开始了这一行动。想通过这次分析过程,更加深入地了解引擎,并将它们分享出来,于是决定写一系列的文章,来分析引擎的各个模块,包括结构、流程、技术原理和实现方法。为了能与自己的工作结合起来游戏引擎技术,发挥出最大的效益,我在分析引擎的同时,也把这些技术运用到了自己的项目中。
由于过去几年一直在性能优化方面努力,包括性能工具开发、性能分析、性能优化、框架结构改造升级等,也深刻了解到了解引擎的架构、各个引擎模块的运行原理对于优化工作的重要性。其实“引擎技术”并不单单指引擎,为了描述方便,我这里就称之为“引擎技术”。同时,为了大家能更好的理解引擎,我会在本系列文章中用图来描述其中的原理、流程、结构,加速我和读者对知识的理解。
我将这个系列命名为《图形化游戏引擎》,希望用“图”来形象地诠释抽象的技术。写作的过程也是我的学习过程,通过学习和复习可以对引擎技术有更深入的理解。本系列文章将系统地分析游戏引擎技术,涵盖引擎的历史、架构、功能框架、模块结构、执行流程、策略机制、公式算法、硬件结构等。此外,如果时间允许,我也会用一些自制的引擎案例来完成引擎技术的实战。
目录
1.UGUI结构概述
2. UGUI图集及组件
2.1 Atlas算法
2.2 组件原理
3.UGUI输入机制
4. UGUI内核
4.1 UGUI核心结构
4.2 批处理算法及流程
4.2.1 元素排序
4.2.2 元素批次计算
4.2.3 批量网格生成
5. UGUI渲染与材质
5.1 渲染过程
5.2 渲染材质
摘要:UGUI的渲染方式有两种,一种是将渲染提交给场景统一管理,一种是UGUI独立渲染。这两种方式都需要将批量对象转化为通用渲染对象。UGUI内置了三种效果:Outline、Position As UV1、Shadow。Outline会对UI元素的轮廓做外部描边,Position As UV会将网格顶点的uv修改为坐标,Shadow会添加阴影效果。在材质Shader方面,UGUI分为Default、ETC、Overdraw,以及3DUI细节叠加、反射光等,都是由基础Shader扩展而来。
关键词:Unity引擎、UI底层框架、UGUI分析、UI Shader、材质效果
内容
5. UGUI渲染与材质
本文主要讲渲染流程和材质
5.1 渲染过程
元素批量计算、批量网格生成算法及流程如上所示。
批量网格生成完成后就进入渲染提交步骤了,UGUI的渲染有两种,一种是自己管理渲染提交,一种是让场景统一管理渲染提交,如下图:
(批量对象提交绘制流程-图)
Mesh 经过 batch 处理后,所有 batch 数据都会进入渲染逻辑。渲染逻辑有两种,一种是直接提交给场景渲染统一渲染处理,但在提交给场景渲染之前,需要将 batch 对象转换为通用渲染对象,即 Render 对象,因此每个 batch 都会创建一个新的 Render 实例,用于承载 batch 渲染内容。另一种是 UGUI 的独立渲染,与场景完全不同,一定会覆盖场景渲染,也就是直接控制渲染顺序,让 OverLayer 的 UI 渲染覆盖其他所有渲染。上面说的两种渲染方式,都可以在 Canvas 中设置,当 Canvas 设置了 WorldCamera 时,使用 SceneRender 场景渲染流程,当 Canvas 设置了 Overlays 时,使用独立叠加渲染。
这两种方法的一些细节:
1)UI 采用场景渲染的方式,使用场景渲染时,Batched 的待渲染对象会在 EmitWorldScreenspaceCameraGeometry 中转化为引擎通用的 Render 对象,并放入场景渲染容器中。然后渲染时,渲染管线会先更新渲染对象的信息,再将渲染对象集合交给裁剪器进行裁剪,最后提交渲染。
2)UI 采用叠加模式渲染。使用 Overlays 进行渲染时,会在 RenderOverlays 中解析 batched Shader 的 Pass,并对 batched Shader 中的每个 Pass 进行一次绘制。绘制时会将每个 batched 对象中的绘制数据传递到渲染缓冲区,最终提交渲染。
5.2 渲染材质
UGUI 内置了 3 个效果,Outline、Position As UV1、Shadow,都可以通过在 UI/Effects 下添加脚本来应用。
下面就对这三种效果的实现原理进行分析,具体代码可以参阅UGUI的C#部分开源代码。
Outline 会对 UI 元素的轮廓做外部描边,其原理和步骤如下:
1)取出UI元素的网格。
2)复制网格,并修改坐标偏移,以与原始网格进行区分。
3)偏移为上、下、左、右四个方向,进行四次偏移。
4)将新生成的4组网格添加到原有的顶点缓冲区中,成为UI元素网格
ApplyShadowZeroAlloc,4次
Position As UV,即坐标决定UV,其原理和步骤为:
1)删除UI元素的网格
2)网格顶点的uv将被修改为坐标
3)最后将修改后的网格确定为UI元素网格
这个效果可以理解为一个拼图碎片,其中显示的坐标表示纹理的一部分。
Shadow 使UI元素拥有类似阴影的效果游戏素材,其原理和步骤如下:
1)删除UI元素的网格
2)复制网格,并修改坐标偏移,以与原始网格进行区分。
3)将偏移网格添加到原网格中,形成新网格
以上就是三种效果的原理和步骤,最常用的函数是网格偏移函数ApplyShadowZeroAlloc,该函数对网格的每个顶点进行偏移,并按照逻辑设置颜色和透明度,是网格效果类中的常用函数。
下面对UGUI中使用的Shader进行分析,UGUI中常用的Shader是UI-Default.shader,可以看到这个Shader应用在UGUI的元素上的默认材质球中。
UGUI Shader的专属函数都放在UnityUI.cginc中,里面包含了获取模板测试数据的函数以及UI漫反射颜色计算函数。同时,大部分的UGUI Shader都需要用到Unity的通用Shader函数库,也就是UnityCG.cginc,所以在大部分的UGUI Shader中都会看到这两个cginc文件。
UI-默认.shader
UGUI 中最常用的 Shader 是 UI-Default.shader,关闭后台剔除、光照、深度写入,开启深度测试进行遮挡测试、透明混合进行半透明渲染、颜色遮罩进行颜色剔除。其顶点函数和片段函数为:
v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
v.vertex; =
UnityObjectToClipPos(OUT.worldPosition); =
TRANSFORM_TEX(v.texcoord, _MainTex); =
v.color * _Color; =
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
#ifdef UNITY_UI_CLIP_RECT
*= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
(列表 - UI-Default.shader 代码)
vertex函数转换顶点坐标,并叠加自定义颜色。然后经过光栅化后进入fragment函数,fragment函数采样图集,并叠加自定义颜色。然后如果有模板测试,就把模板计算结果传给alpha,这个跟Mask组件和其他一些编辑器的功能效果有关。最后经过alpha校正后输出颜色。
UI-DefaultETC1.shader 和 UI-Default.shader 基本一样,不同之处在于 UI-DefaultETC1.shader 有自己的 alpha map,用来决定坐标上的 alpha 值。当 UGUI 识别到 UI 图是 ETC1 格式时,会自动做这样的分割。
UI-DefaultFont.shader是用于字体的,它其实就是UI-Default.shader的拷贝,所以代码量很少,基本和UI-Default.shader一致。
其他UI-Sahder包括带光照和不带光照的,主要用于3D中的UI,需要接受光照等颜色变化,具体有以下几种:
UI-Lit-Bumped.shader,在屏幕上平铺 UI 元素的顶点
UI-Lit-Detail.shader游戏引擎技术,可以将细节图像叠加在原始 UI 图集上
UI-Lit-Refraction.shader,计算UI图像的反射光的光照模型
UI-Lit-RefractionDetail.shader,类似辐射光照模型+细节图的叠加
UI-Lit-Transparent.shader,用于 UI 图像中的半透明混合
UI-Unlit-XXX.shader中非光照部分均以Unlit开头,具体内容和光照UI Shader类似,只是少了接收光照的计算部分。
参考:
UGUI C#开源地址:
Unity内置资源官网地址:
内置资源GitHub地址: