美文网首页
Unity UGUI系列一 Canvas 和 Canvas Gr

Unity UGUI系列一 Canvas 和 Canvas Gr

作者: 合肥黑 | 来源:发表于2021-11-20 20:58 被阅读0次

    Canvas(画布)是承载所有UI元素的区域。所有的UI元素都必须是Canvas的子对象。如果场景中没有画布,那么我们创建任何一个UI元素,都会自动创建画布,并且将新元素置于其下。

    Canvas下挂了3个组件。Canvas,CanvasScaler,GraphicRaycaster

    image.png
    一、Canvas

    参考
    Unity Canvas组件的三种渲染模式
    UGUI:Canvas
    UGUI(一)- Canvas
    渲染顺序

    1.RenderMode: Screen Space-Overlay
    image.png

    此模式下 UGUI 总会处于渲染队列的最高层级,可以想像成 UGUI 是紧贴相机屏幕的,因此 UI 与屏幕之间无法插入任何 3D 物体。

    • Pixel Perfect 使UI元素像素对应,效果就是边缘清晰, 不过渲染过程中的计算量也会相应增加
    • Sort Order 控制多个 Canvas 的渲染前后顺序,越大越靠近屏幕。
    • Target Display 指定最终渲染到的Display。Display主要的作用是分屏,一个主机上连接两个屏幕或者多个屏幕,可以在两个屏幕上显示不同的内容。比如:有两个屏幕,一个大的显示屏挂在高高的墙上作为展示屏,另一个小屏幕可以作为输入屏幕拿在手中进行控制。
    2.Screen Space-Camera
    image.png
    注意上图这个提示:A Canvas with no specified camera acts like a overlay canvas,表示需要指定一个Camera,如果不指定则其跟Overlay相同。
    image.png
    现在我们指定了一个UICamera,设置如下:
    image.png
    • UI 相机的 Culling Mask 建议只选 UI 层。
    • UI 相机的 Clear Flags 建议选为 Depth Only。
    • UI 相机可以是透视相机,Canvas 会根据相机视锥体来自动调节宽高以达到铺满屏幕的视觉效果, 建议选择正交相机,方便在 Canvas 间插入 3D 物体时保证 3D 物体渲染不受透视影响。

    现在,比Screen Space-Overlay模式的画布多了下面几个参数:

    • Plane Distance:该Canvas到 UI 相机的距离(一般是Z轴距离),可用于调节多个 Canvas 的渲染前后层级。
    • Sorting Layer: Sorting Layer是UGUI专用的设置,用来指示画布的深度。可以通过点击该栏的选项,在下拉菜单中点击“Add Sorting Layer”按钮进入标签和层的设置界面,或者点击导航菜单->edit->Project Settings->Tags and Layers进入该页面。可以点击“+”添加Layer,或者点击“-”删除Layer。画布所使用的Sorting Layer越排在下面,显示的优先级也就越高。
    • Order in Layer:在相同的Sort Layer下的画布显示先后顺序。数字越高,显示的优先级也就越高。
    • 此模式下 Canvas 渲染优先级 Sorting Layer > Order in Layer > Plane Distance。
    • Default 的层级低于任何自定义的 Sorting Layer 层级 此模式下 Canvas 与相机之间可以插入 3D 物体,比如 特效 和 皮肤展示模型 等。
    image.png

    3D对象想要显示在UI前面的话只需要调节Z轴的值,让Z轴坐标在相机和Canvas之间就可以了。而Canvas与相机的距离则可以通过调节 PlaneDistance参数的值,但是注意不要超过相机的最远可视距离,也不要小于最近可视距离。

    3.为什么要单独用一个相机去渲染UI

    例如Screen Space - Overlay会将Canvas下的元素全部渲染到最前面,都是使用一个Sort Order进行管理,很不方便。但使用UICamera之后,Canvas下的元素都可以使用Sorting Layer进行分组管理。(只需要在需要管理的元素上添加新的Canvas组件)。

    再例如,在3D游戏中Screen Space - Overlay最好只用于HUD。其他的UI如果使用Screen Space - Overlay,在需要有粒子效果的情况下,则粒子效果会被UI遮挡。如果使用UICamera则可以对粒子效果进行管理。

    这种模式可以用来实现在UI上显示3D模型的需求,比如很多MMO游戏中的查看人物装备的界面,可能屏幕的左侧有一个运动的3D人物,左侧是一些UI元素。通过设置Screen Space-Camera模式就可以实现上述的需求,效果如下图所示:


    image.png
    4.World Space模式
    image.png
    • Event Camera 指定接受 UI 事件的摄像机。

    此模式下 UGUI 与其它 3D 物体无区别。在这种模式下,UI 存在于场景中,并渲染到其他对象的前面或后面(例如,3D 世界中角色上方的名称标签)。此模式下 UI 不会随相机旋转而旋转,其它两个模式下 UI 总是与 UI相机 保持相对静止。此模式可以用于制作 HUD ,比如 人物血条、 攻击或掉血飘字 等。

    image.png
    二、Canvas Scaler

    参考
    CanvasScaler的三种适配模式——恒定像素模式(constant Pixel Size)
    CanvasScaler的三种适配模式——缩放模式(Scale with Screen Size)
    UGUI之Canvas Scaler适配模式

    Canvas Scaler 这个组件用来做整体 UI 屏幕适配的。为什么是整体适配?因为适配时还会用到 RectTransform 中的 Anchor 属性。Canvas Scaler 同样挂在 Canvas Gameobject 下。

    缩放模式与 Canvas 的渲染模式相关:当 Canvans 渲染模式为 Screen Space - Overlay 和 Screen Space - Camera 时,缩放模式有 三种;当 Canvans 渲染模式为 World Space 时,缩放模式只有 一种。

    Scale Mode只有一个,未作深入研究
    Scale Mode有三个
    image.png

    UI Scale Mode有三种,主要使用的是第二种。下面先介绍第一种和第三种:

    1.constant Pixel Size

    无论屏幕大小如何,UI始终保持相同像素大小。

    缺点:当处于恒定像素模式时,改变屏幕的大小,其中的图片是固定大小不变的。它不会让UI控件进行分辨率大小自适应,会让UI控件始终保持设置的尺寸大小显示。一般极少使用这种模式,除非通过代码计算来设置缩放系数。

    image.png
    • ScaleFactor :缩放系数,按此系数缩放UI中的所有元素
    • Reference Pixels Per Unit:单位参考像素,多少像素对应unity中的一个单位(默认一个单位为100像素),图片设置中的Pixels Per Unit设置,会和该参数一起参与计算。

    恒定像素模式计算公式:UI原始尺寸=图片大小(像素)/(Pixels Per Unit /Reference Pixel Per Unit)


    image.png
    image.png
    2.Contant Physical Size 不变物理尺寸
    image.png
    和Constant Pixel Size类似,但是只能通过RectTransform来改变大小。
    image.png
    这个应用场景较少,具体是这样的,比如你电脑分辨率是 1000*2000而你的手机分辨率也是1000*2000。虽然电脑屏幕比手机屏幕大的多,但是他们最后显示出来图片的物理大小是一样的。
    3.Scale with Screen Size 大部分游戏使用此模式
    image.png

    第一个参数一般是美术人员根据游戏主要面向的手机市场,比如安卓市场,用市场上最常用的分辨率作为制作UI图片的标准。这里填的数就是美术人员确认的尺寸,之后的屏幕自适应就通过这个参数进行计算。Windows系统一般是1920*1080。注意:一般是通过宽高比来进行计算的。Game视图中的比值就是宽高比。使用宽高比就可以模拟不同设备的显示情况。

    第二个参数是屏幕匹配模式,主要有三种:


    image.png

    第三个参数 Match值, 决定 Canvas 按宽高缩放的权重值,当 Match = 0 时,按宽度进行 Canvas 等比缩放;当 Match 值 = 1 时,按高度度进行 Canvas 等比缩放。一般情况下这个值非 0 即 1,不用纠结中间值。(横屏游戏Match=1,竖屏游戏Match=0)

    Expand有黑边,Shrink有裁剪,一般都是使用Match Width Or Height

    4.Expand

    Expand 在屏幕大小上“内接” 画布。以 Canvas 小于 屏幕 为例,放大画布直至宽或高有一边与屏幕重合停止。此模式下为 Canvas 全部显示在屏幕中 的前提下 Canvas 的最大缩放值

    image.png
    5.Shrink

    Shrink 在屏幕大小上 “外切” 画布。以 Canvas 小于 屏幕 为例,放大画布直至宽或高最后一边与屏幕重合停止。此模式下为 Canvas 被裁切,不能完全显示在屏幕中。


    image.png
    6.再次强调,任何缩放模式都不会改变 Canvas 固有设计宽高比。
    三、Graphic Raycaster

    参考
    UGUI(三)- Graphic Raycaster
    Unity Raycasters 剖析

    image.png

    Raycasters 用来检测当前事件发送给哪个对象,检测原理就是 Raycast。当给定一个屏幕坐标系中的位置,Raycasters 就会利用射线检测寻找潜在的对象,并返回一个离当前屏幕最近的对象。

    在 Unity Raycasters 中有三种类型的 Raycasters:

    • Graphic Raycaster - 存在于 Canvas 下,用于检测 Canvas 中所有的物体
    • Physics 2D Raycaster - 用于检测 2D 物体
    • Physics Raycaster - 用于检测 3D 物体
    1.做一个示例
    image.png
    image.png
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class TestGraphicRaycaster : MonoBehaviour
    {
        [SerializeField] private Text m_Text;
        [SerializeField] private Button m_AddBtn;
        [SerializeField] private Button m_RestBtn;
    
        /// <summary>
        /// 记录点击次数
        /// </summary>
        private int mClickCount;
    
        private void Start()
        {
            m_AddBtn.onClick.AddListener(OnAddButtonClick);
            m_RestBtn.onClick.AddListener(OnButtonResetClick);
        }
    
        private void OnButtonResetClick()
        {
            mClickCount = 0;
            SetText();
        }
    
        private void OnAddButtonClick()
        {
            mClickCount++;
            SetText();
        }
    
        private void SetText()
        {
            m_Text.text = string.Format("已点击{0}次", mClickCount);
        }
    }
    
    image.png

    点击Add按钮,文本显示点击次数加1;点击Reset按钮,点击次数清0.

    2.Ignore Reversed Graphics

    是否忽略反转的 UI 元素的射线检测(文中暂时可理解为按钮点击事件的触发),如果勾选此项,射线将会穿过被翻转(正反面)的 UI 元素

    我们把实例中 ResetBtn 沿X或Y轴翻转180°(沿Z轴旋转不会翻转 UI),比如rotation y = 180。运行实例,这时点击 AddBtn 次数会增加,但点击 ResetBtn 次数不会清零;

    如果我们把 Graphic 下的 Ignore Reversed Graphics 取消勾选后再点击 ResetBtn,会发现 ResetBtn 会触发清零。

    3.Blocked Objects 和 Blocking Mask

    这两个属性一块使用,用来阻止 UI 射线的延伸(这么描述比较容易理解,下文会有解释)

    Blocked Objects 阻挡物体的类型(2D或3D或者二者都判断),官方字面是这么解释,其实是根据阻挡物上挂的 Collider (必须要有Collider) 类型来判断 阻挡物是 2D 还是 3D

    Blocking Mask 阻挡物的 Layer

    • 先会从相机发条射线去检测阻挡物,如果有同时满足 Blocked Objects 设定 和 Blocking Mask 设定的阻挡物,记录相机与该阻挡物距离 Dis(其实是个矢量)
    • 相机发射 UI 射线,把在射线范围内的 UI 元素先加入集合 m_RaycastResults,再遍例集合剔除不满足 Dis 的元素,剩下的进行 EventSystem 处理
    • 所以整个流程是分两步,并不存在阻挡物阻止 UI 射线的说法

    现在来改造一下上面的例子:

    image.png
    增加一个Sprite 2D,而不是UI中的Image,关于这两者的区别,可后续系列Unity UGUI系列二 图片 SpriteRenderer和Image
    image.png
    这里图片源随便选一张图片,如果太小了,改一下Scale。然后将Layer改为Water,然后将Main Camera不要再看Water层,UI Camera看Water层,这样确保运行时是通过UI Camera看到的这张图片:
    image.png
    image.png
    然后参照Canvas的位置,把BlockSprite的位置调整过去。其中XY基本是一致的,Z可以调大或调小,能观察到图片和按钮的互相遮挡情况。这里注意,虽然BlockSprite属于Water Layer,是必定遮挡Default Layer的Canvas的。但是它还有一个单独的Additional Settings-->Sorting Layer
    image.png
    image.png

    现在把代码运行起来,调节Blocking Objects的参数,就能看到Reset按钮是否生效了。当我们选阻挡物体是2D时,由于 Sprite 上挂的是 Box Collider 2D,此时Reset按钮会失效。


    image.png

    需要注意的是,Blocked Objects 和 Blocking Mask 属性仅在 Canvas 的 RenderMode 为 Screen Space - Camera 或者 World Space 时生效,在 Screen Space - Overlay 模式下无效。

    四、Canvas Group

    参考
    Unity中CanvasGroup组件

    Canvas Group可以影响该组UI元素的部分性质,而不需要费力的对该组UI下的每个元素进行逐一得得调整。Canvas Group是同时作用于该组件UI下的全部元素。

    image.png
    1.参数
    • Alpha : 该组UI元素的透明度。注:每个UI最终的透明度是由此值和自身的alpha数值相乘得到。
    • Interactable : 是否需要交互(勾选的则是可交互),同时作用于该组全部UI元素。
    • Blcok Raycasts : 是否可以接收图形射线的检测(勾选则接受检测)。注:不适用于Physics.Raycast.。比如:开启的时候,Button会阻挡射线检测。这样你点击Button,它才会响应点击。
    • Ignore Parent Group : 是否需要忽略父级对象中的CanvasGroup的设置。(勾选则忽略)
    2.应用场景
    • 在窗口的GameObject上添加一个CanvasGroup,通过控制它的Alpha值来淡入淡出整个窗口;
    • 通过给父级GameObject上添加一个CanvasGroup并设置它的Interactable值为false来设置一套没有交互(灰色)的控制;
    • 通过将元素或元素的一个父级添加Canvas Group并设置BlockRaycasts值为false来制作一个或多个不阻止鼠标事件的UI元素;
    3.CanvasGroup的Alpha与SetActive()方法比较
    • CanvasGroup的Alpha与SetActive()两者之间的性能区别不大。
    • CanvasGroup的Alpha由0设为1的时候,并不会让自己活着的子节点中脚本执行Awake()方法,而SetActive(true)则会执行Awake()方法。
    • CanvasGroup的Alpha设为0和SetActive(false)的时候,同样不会调用drawcall;
    4.示例(一闪一暗)
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
     
    public class Test : MonoBehaviour {
     
        private float alpha0 = 0.0f;
     
        private float alphaSpeed = 2.0f;
        bool isShow;
     
        private CanvasGroup cg;
     
        void Start () {
            cg = this.transform.GetComponent<CanvasGroup>();
        }
        
        void Update ()
        {
            if (!isShow)
            {
                cg.alpha = Mathf.Lerp(cg.alpha, alpha0, alphaSpeed * Time.deltaTime);
                if (Mathf.Abs(alpha0 - cg.alpha) <= 0.01)
                {
                    isShow = true;
                    cg.alpha = alpha0;
                    alpha0 = 1;
                }
            }
            else
            {
                //*0.5是因为从隐藏当显示感觉很快
                cg.alpha = Mathf.Lerp(cg.alpha, alpha0, alphaSpeed * Time.deltaTime * 0.5f);
                if (Mathf.Abs(alpha0 - cg.alpha) <= 0.01)
                {
                    isShow = false;
                    cg.alpha = alpha0;
                    alpha0 = 0;
                }
            }
        }
     
    }
    

    相关文章

      网友评论

          本文标题:Unity UGUI系列一 Canvas 和 Canvas Gr

          本文链接:https://www.haomeiwen.com/subject/avbezltx.html