通过抄一遍代码来学习UGUI 的工作原理
Unity没有开源Canvas/CanvasRender的源码
可以被剪裁的对象:IClippable IClippable 的cull 接口是对 clip 的一个优化? 如果没有在rect里面,直接cull掉 可以被mask 的对象: IMaskable 这两个总是一起的?
RectMask2D 用来mask 那些 IClippable mask 的时候会去遍历自己的所有父节点RectMask2D 来做交集, ref RectMask2D:PerformClipping() 单个RectMask2D 的大小是根据Canvas 的大小决定的
RectMask2D VS Mask RectMask2D 是用 rectClip + cull 来实现 Mask 是用 stencil, todo
MaskableGraphic 实现了这两种机制,前者在Notify2DMaskStageChanged() 函数中触发,后者在NotifyStencilStateChanged() 函数中触发 前者在 RectMask2D 的OnEnable/OnDisable 中触发,后者在 Mask and(or) MaskableGraphic 的 OnEanble/OnDisable 中触发
RectMask2D:OnEnable/OnDisable --> Notify2DMaskStageChanged() 导致所有孩子节点RecalculateClipping(),然后孩子节点将自己添加到父节点的clippable 列表里面去,AddClippable()
MaskableGraphic OnEnable/OnDisable/OnTransformParentChanged/.. -> 导致 UpdateClipParent() --> AddClippable(), 最后 ClipperRegistry:Cull() -->PerformClipping()
ICanvasElement 表示一个界面,CanvasUpdate 有5种枚举值, PreLayout/Layout/PostLayout/PreRender/LateRender, 按照先后顺序执行
CanvasUpdateRegistry:PerfromUpdate() 所有UI Update 总入口,有两个列表, layourRebuildQueue (mesh的重建) + PerformingGraphicUpdateQueue, layout rebuild 之后就会执行 cull操作(ClipperRegistry:Cull()) Graphic 和 LayoutRebuilder 都实现了 ICanvasElement 接口,前者处理CanvasUpdate.PreRender,后者处理 CanvasUpdate.Layout 渲染的时候使用材质 materialForRendering, 这个是经过所有的 IMaterialModifier 处理过之后的材质;
IMaterialModifier 有哪些?TODO
所有显示对象的基类是 Graphic有layoutDirty/verticesDirty/materialDirty 三个层次的dirty verticesDirty 会导致mesh 的重构
TODO 啥时候被加入layout 列表? OnRecttransformDimensionsChange/OnTransformParentChanged/ Graphic:OnEnable/OnDisable,OnDidApplyAnimationProperties 1,Graphic:SetLayoutDirty() LayoutRebuilder 负责具体执行
啥时候被加入graphic 列表? verticesDirty/materialDirty的时候 todo
Canvas的排序是怎么做的?
EventSystem是如何将一个点击事件派送到一个按钮上的? GraphicRaycaster 作为EventSystem 的一个module 来处理点击事件; 处理逻辑:找到当前Canvas 所对应的所有Graphic 对象并检测raycaster 位置是否正确,(每个Graphic对象在OnEnable的时候都会去注册自己跟父Canvas的关系) 然后排除掉所有朝向与摄像机朝向角度大于90度的,以及所有位于摄像机后面的,最后按照 DESCENT order by depth/sortOrderPriority/sortingLayer/sortingOrder/depth/distance 排序 ref GraphicRaycaster:Raycast()
ICanvasRaycasterFilter 接口表示一个可以被Raycaster 的对象, Image 对象实现该接口
EventSystem:Update -> inputModule:Process() -> StandaloneInputModule:Process() -> ProcessTouchEvents() ->GetTouchPointerEventData() -> EventSystem:RaycastAll() -> raycastModule:Raycast()
StandaloneInputModule:ProcessTouchEvent() 处理touch事件
EventInterfaces.cs 中定义了相应的接口,例如 IPointerClickHandler / IBeginDragHandler/ IDragHandler/ IPointerDownHandler 等等 Selectable 实现了 MoveHandler+PointerDownHandler + PointerDownHandler + PointerEnterHandler + PointerExitHandler + SelectHandler + DeselectHandler Button 继承了 Selectable, 并且自己实现了 IPointerClickHandler ScrollRect 实现了 IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler 等
ExecuteEvents 类负责调用相应的事件 handler 进行处理, 主要有两个接口,ExecuteHierarchy / Execute, 前者从当前节点向上传递,直到遇到一个正常的handler来处理,后者直接在指定对象上面调用handler 还有一接口GetEventHandler 是从当前节点开始向上找handler click 跟drop 事件是互斥的
以IPointerDown 为例: 在 StandalineInputModule:ProcessTouchPress() 中,在当前pointerEvent 的raycast对象上执行 (ExecuteHierarchy) PointerDownHandler