1.UGUI源码导读
2.unity 动态图集
3.UGUI源码阅读之Mask
4.UGUI源码介绍
5.UI(一) - NGUI和UGUI比较
6.Unity源码学习遮罩:Mask与Mask2D
UGUI源码导读
对于想了解UGUI C#源码阅读顺序的源码同学,我有些建议。文字首先,源码要知道UI组件的文字渲染需要顶点、材质和Layout数据,源码这与模型相似但多了Layout。文字数轮源码组件脚本继承自MonoBehaviour,源码当数据改变或组件启用时,文字会自动加入CanvasUpdateRegistry的源码更新列表。
源码大致可以分为几个部分:基础组件如Image、文字Text,源码它们包含自身数据;CanvasUpdateRegistry负责组件更新,文字当Canvas更新时会调用组件的源码方法;辅助工具如LayoutRebuilder、FontData和动画工具CoroutineTween;数据结构工具,文字如ListPool、源码ObjectPool等,虽非业务核心,但价值不容忽视;Mask与Mask2D的实现;以及EventSystem的事件处理机制,这部分我已经详细阐述过。
从基础组件开始,Graphic脚本是起点。OnEnable时会调用SetAllDirty,这里包含了组件的三个更新数据:Layout、顶点和材质。SetLayoutDirty等方法负责实际的更新,其中LayoutRebuilder是一个关键的辅助类。当Canvas更新时,会遍历并执行需要更新的LayoutGroup的Rebuild方法。
Image的Filled模式生成Mesh的过程是另一个看点。至于RectMask2D,其工作流程涉及挂载、众发源码子物体处理和Canvas重建后的Clip方法。Mask则通过Stencil材质实现子物体的遮罩效果。
最后,推荐关注几个实用的工具脚本,如ObjectPool用于对象管理和CoroutineTween用于动画效果。整体来看,阅读源码时,理解这些结构和流程会让你事半功倍,但需做好心理准备,因为源码可能并不包含详细的DC(详细内容)或Text的文字网格计算等具体实现。
unity 动态图集
动态图集,是为了解决图集在制作过程和运行时合并批次问题而产生的解决方案。在NGUI和UGUI中,图集通常在制作期间就生成,运行时则是一张大图。这种方法的优势在于可以在一定程度上合并批次,但同时也存在一些局限性。例如,图集在制作过程中会分为commonatlas和系统atlas两类。一个界面prefab至少会使用两张图集,这会导致ABA的图集穿插打断合批的情况。此外,随着游戏内容的增加,各种也会增多,如图标、commonatlas这类图集,一张x可能已经装不下,此时,两张x图集又会出现ABA的情况,同时,神箭手 爬虫 源码内存消耗也随之上升。
为解决这些问题,动态图集应运而生。动态图集在打包阶段是零散的,但在运行时自动生成一张空白大,并将界面上使用的零散绘制到这张大图上。仅将这个大图传入GPU中,以实现合批效果。对于手机界面的制作,通常采用的标准分辨率低于,因此一张的动态图集足以解决一个界面的绘制工作。然而,动态图集也有其缺点,主要是图集生成过程被延迟到游戏运行时,增加了图集生成的成本。此外,目前尚未出现公开支持压缩的动态图集解决方案,动态图集通常只能以RGBA格式呈现。静态图集在生成过程中是确定的,可以优化分配算法,提高图集利用率。动态图集由于在运行过程中动态生成和变化,图集会存在碎片问题,利用率难以达到很高。
动态图集的威力,通过下面的demo可以一窥究竟。这个demo仅为动态图集主要思路的简单演示,分配算法将大划分为x的分区,并使用引用计数来控制是否在使用。这套算法适用于UI系统的azkaban 源码下载维护,对于图标等固定尺寸的元素来说,特别合适。下面提供源码进行参考。
UGUI源码阅读之Mask
Mask主要基于模版测试来进行裁剪,因此先来了解一下unity中的模版测试。
Unity Shader中的模版测试配置代码大致如上
模版测试的伪代码大概如上
传统的渲染管线中,模版测试和深度测试一般发生在片元着色器(Fragment Shader)之后,但是现在又出现了Early Fragment Test,可以在片元着色器之前进行。
Mask直接继承了UIBehaviour类,同时继承了ICanvasRaycastFilter和IMaterialModifier接口。
Mask主要通过GetModifiedMaterial修改graphic的Material。大致流程:
1.获取当前Mask的层stencilDepth
2.StencilMaterial.Add修改baseMaterial的模板测试相关配置,并将其缓存
3.StencilMaterial.Add设置一个unmaskMaterial,用于最后将模板值还原
MaskableGraphic通过MaskUtilities.GetStencilDepth计算父节点的Mask层数,然后StencilMaterial.Add修改模板测试的配置。
通过Frame Debugger看看具体每个batch都做了什么。先看第一个,是Mask1的m_MaskMaterial,关注Stencil相关的数值,白色圆内的stencil buffer的值设置为1
这个是Mask2的m_MaskMaterial,根据stencil的计算公式,Ref & ReadMask=1,Comp=Equal,只有stencil buffer & ReadMask=1的像素可以通过模板测试,即第一个白色圆内的像素,然后Pass=Replace,会将通过的像素写入模板值(Ref & WriteMask=3),即两圆相交部分模板值为3
这个是RawImage的Material,只有模板值等于3的profinet协议源码像素可以通过模板测试,所以只有两个圆相交的部分可以写入buffer,其他部分舍弃,通过或者失败都不改变模板值
这是Mask2的unmaskMaterial,将两个圆相交部分的模板值设置为1,也就是还原Mask2之前的stencil buffer
这是Mask1的unmaskMaterial,将第一个圆内的模板值设置为0,还有成最初的stencil buffer
可以看到Mask会产生比较严重的overdraw。
2.drawcall和合批
每添加一个mask,一般会增加2个drawcall(加上mask会阻断mask外和mask内的合批造成的额外drawcall),一个用于设置遮罩用的stencil buffer,一个用于还原stencil buffer。
如图,同一个Mask下放置两个使用相同的RawImage,通过Profiler可以看到两个RawImage可以进行合批
如图,两个RawImage使用相同的,它们处于不同的Mask之下,但是只要m_StencilValue相等,两个RawImage还是可以进行合批。同时可以看到Mask1和Mask1 (1),Mask2和Mask2 (1)也进行了合批,说明stencilDepth相等的Mask符合合批规则也可以进行合批。
StencilMaterial.Add会将修改后的材质球缓存在m_List中,因此调用StencilMaterial.Add在相同参数情况下将获得同一个材质球。
UGUI源码介绍
本文提供对Unity UI系统(UGUI)源码的概览,内容主要来自官方文档。
UGUI主要由EventSystem和UI两部分构成。
EventSystem部分包含输入模块和射线投射器。输入模块用于配置事件系统的主要逻辑,提供不同平台的开箱即用选项,支持各类输入系统如触控、控制器、键盘和鼠标,并将事件分发至对应组件。射线投射器则用于检测事件位置,决定事件传递至的UI元素。
UI部分结构相对复杂,包含多个类和接口,如IMaterialModifier和IndexedSet等。IMaterialModifier接口允许修改用于渲染的Material,IndexedSet是一种结合List和Dictionary实现的自定义容器,提供快速移除和插入元素的功能,但牺牲了顺序和序列化的友好性。
总之,UGUI源码通过模块化设计和接口定义,为开发者提供了丰富的UI构建和事件处理能力。
UI(一) - NGUI和UGUI比较
在选择UI系统作为游戏项目主框架时,NGUI和UGUI是两个主要选项。本文将从多个方面对两者进行比较,以帮助开发者做出决策。
首先,考虑图集处理功能。NGUI需要手动使用工具拼接,而UGUI在开发期间可以将直接作为元素使用,打包时自动拼接成图集,且自带alpha拆分功能,操作更为便捷。
组件支持方面,NGUI提供了丰富的组件选择,如Localization System、ScrollView、UIButton、UIToggle等,涵盖多语言、滚动、按钮、切换选择、进度条、下拉列表、输入框、快捷键绑定、导航绑定、排列、表格、动画、锚点、摄像头、拖拽等功能。相比之下,UGUI组件数量较少,主要涵盖文字、贴图、按钮、切换与选择、滑动条、下拉框、输入框、画布、面板、滑动视图、遮挡块等。
可定制程度方面,NGUI通过源代码支持,允许开发者随时根据需求进行修改。而UGUI采用开源C#代码,开发者可以进行修改,但需要重新打包成DLL文件后替换原文件,操作稍显复杂。
输入事件处理方式不同。NGUI通过摄像头发出射线碰撞,识别输入事件并按碰撞顺序处理层级。UGUI根据输入点位置RaycastTarget,判断事件应交由哪个UI元素处理。
层级显示控制方面,NGUI依靠Panel depth和RenderQueue控制。UGUI则通过距离摄像机的前后位置或排序顺序设置层级。
字体制作方面,NGUI不支持动态字体,而UGUI支持动态字体,可以直接使用字体文件。
社区完善程度上,NGUI由商业运营,氛围较好。UGUI官方自运营,后端强大,拥有更多资源支持。
性能方面,NGUI和UGUI均表现良好,不同测试网站的统计结果均显示其性能可靠。
在综合比较后,NGUI和UGUI各有特色,没有绝对的好与差。项目选择应根据个人和项目需求而定。对于Unity3D 4.x项目,NGUI可能是更合适的选择,而新项目通常会选用最新版本的Unity3D,因此UGUI应用更为广泛。
建议开发者选择自己熟悉的UI系统,并尝试不熟悉的系统以扩展技能。对于希望更深入自定义和修改源码以服务于特定游戏逻辑或性能定制需求的开发者,NGUI可能是一个更理想的选择。然而,UGUI也提供了开源源码,允许在现有基础上扩展和重载。
最终,决策应基于项目需求、团队技能、资源可用性以及个人喜好。在不断学习和适应新趋势的同时,选择适合自己项目需求的UI系统,将是推动项目成功的关键。
Unity源码学习遮罩:Mask与Mask2D
Unity源码学习遮罩详解:Mask与Mask2D UGUI裁切功能主要有两种方式:Mask和Mask2D。它们各自有独特的原理和适用场景。1. Mask原理与实现
Mask利用IMaskable和IMaterialModifier功能,通过指定一张裁切图,如圆形,限定子元素的显示区域。GPU通过StencilBuffer(一个用于保存像素标记的缓存)来控制渲染,当子元素像素位于Mask指定区域时,才会被渲染。 StencilBuffer像一个画板,每个像素有一个1字节的内存区域,记录是否被遮盖。当多个UI元素叠加时,通过stencil buffer传递信息,实现精确裁切。2. Mask2D原理
RectMask2D则基于IClippable接口,其裁剪基于RectTransform的大小。在C#层,它找出所有RectMask2D的交集并设置剪裁区域,然后Shader层依据这些区域判断像素是否在内,不满足则透明度设为0。 RectMask2D的性能优化在于无需依赖Image组件,直接使用RectTransform的大小作为裁剪区域。3. 性能区别
Mask需要Image组件,裁剪区域受限于Image,而RectMask2D独立于Image,裁剪灵活。因此,Mask2D在不需要复杂裁剪时更高效。 总结:虽然Mask和Mask2D各有优势,选择哪种遮罩取决于具体需求,合理使用能提高性能和用户体验。