Unity中的UGUI屏幕适配
本文分享Unity中的UGUI屏幕适配屏幕适配一直是一个老生常谈的问题, 虽然只是项目一开始的时候会用到, 但是还是有很多东西需要学习和了解, 今天给大家分享下一些个人的学习和总结.各种坐标屏幕适配有很多重要的概念, 坐标总是一个难以绕过的话题.与适配相关的坐标有, 局部坐标, 世界坐标, 屏幕坐标. 下面我们一一道来.本地坐标(LocalPosition)父节点模型空间: 以父节点的轴心点为原点
本文分享Unity中的UGUI屏幕适配
屏幕适配一直是一个老生常谈的问题, 虽然只是项目一开始的时候会用到, 但是还是有很多东西需要学习和了解, 今天给大家分享下一些个人的学习和总结.
各种坐标
屏幕适配有很多重要的概念, 坐标总是一个难以绕过的话题.
与适配相关的坐标有, 局部坐标, 世界坐标, 屏幕坐标. 下面我们一一道来.
本地坐标(LocalPosition)
父节点模型空间: 以父节点的轴心点为原点, 横纵坐标分别位于长和宽上, 构建父节点的模型空间.
本地坐标也被称为局部坐标, 就是节点的轴心点在父节点的模型空间中的位置. 也可以说是在世界空间下, 节点的轴心点所在位置向量减去父节点轴心点所在位置向量后的结果向量.
本地坐标随着父节点和子节点的轴心点的变化而变化.
在UGUI中, 真正决定本地坐标的是子节点的锚点和父节点的轴心点. 我们将在其它文章详细说明.
如果没有父节点, 那么节点的父节点就是整个世界空间.
我们在属性面板中看到的Position指的就是LocalPosition, 在没有父节点时, 节点的Position属性与LocalPosition属性相同.
世界坐标(Position)
世界坐标代表轴心点在世界空间下的坐标.
不管是Transform组件还会RectTransform组件, 都有世界坐标的属性.
有所区别的是, RectTransform的轴心点可以手动修改, 而Transform的轴心点需要在其他如3DMax中修改(或者通过代码).
屏幕坐标
屏幕分辨率指的是设备的可见区域, 以原点(左下角)和宽高为xy轴组成的屏幕空间.
屏幕坐标就是屏幕空间中某个点的位置.
屏幕适配
上面了解了各种坐标后, 我们发现一个直接的问题, 就是如何将屏幕坐标与Unity中的世界坐标乃至局部坐标作适配, 这个过程就叫屏幕适配.
因为本文是分享UGUI的屏幕适配, 所以会着重讲解Canvas的适配, 3D物体的适配实质上是一样的, 大家可以作类比.
下面进入正题.
为什么需要屏幕适配
现在设备的分辨率五花八门, 我们不可能对每种不同的尺寸单独设计一套UI, 所以需要一套比较通用的适配方案来满足大部分设备的需求.
一些基本的术语
-
设计分辨率(引用分辨率): 我们会定义一个叫做设计分辨率的尺寸(Unity中叫引用分辨率), 美术会基于该分辨率来设计UI, 然后通过程序适配到游戏世界中, 适应各种不同的真实设备分辨率.
-
宽高比: 宽除以高得出的一个数值, 用于一些判断和缩放.
-
缩放因子: 按照某种适配方案得出的一个数值, 用于对物体的某个维度或者整体进行缩放.
-
映射: 将物体的各个维度分别与另一个物体一一对应.
-
Units: 代表Unity世界中一个单位的大小, 这个大小与屏幕像素的关系由摄像机或者其它因素决定.
适配方案
Canvas根据绘制在屏幕空间还是世界空间后, 确定好大小后, 使用CanvasScaler组件来确定最终的大小.
CanvasScaler介绍
当屏幕分辨率与设计分辨率不一致时, 可以通过CanvasScaler对画布进行调整, 以不同的方式来更好的将需要内容合理的展示给用户.
CanvasScaler的主要属性是UIScaleMode.
UIScaleMode
UIScaleMode是CanvasScaler的主要属性.
- Constant Pixel Size: 固定像素大小, 通过Scale Factor调节像素与Units之间的关系.
- Constant Physical Size: 固定物理像素大小(point).
- Scale With Screen Size: 根据屏幕大小缩放.
Scale With Screen Size
这个属性决定了Canvas不同的展示方式. 是屏幕适配的关键属性, 大部分屏幕适配是和这个属性打交道.
主要属性有
- Reference Resolution: 参考分辨率(设计分辨率)
- Screen Match Mode: 屏幕适配模式
-
Shrink: 收缩并剪切, 选择变换比较大的一方来计算缩放因子, 另一方多余的部分被剪切
-
主要为了保证在缩小的情况下(按照比例来说, 而不是大小来说), 尽可能少的损失内容
-
比如: 1280x720=>2160x1080, 宽和高的缩放因子分别是1.6875和1.5, 这时, 将采用1.6875作为缩放因子

-
新的Canvas宽度为2160/1.6875=1280, 高度为1080/1.6875=640, 高度720-640=80的单位被剪切了(黄框的部分)

-
-
Expand: 扩充, 选择变换较小的一方来计算缩放因子, 另一方不够的部分填充固定颜色
-
主要为了保证在放大的情况下(比例放大), 显示所有内容
-
比如: 1280x720=>2160x1080, 宽和高的缩放因子分别是1.6875和1.5, 这时, 将采用1.5作为缩放因子

-
新的Canvas宽度为2160/1.5=1440, 高度为1080/1.5=720, 高度1440-1280=160的单位被填充了, 表现为多余的黑边(黄框部分)


-
-
Match Width Or Height: 匹配宽或者高, 并由Match值来决定最终的缩放值
- 值为0时
-
按照宽度适配, 使用宽度的缩放因子

-
比如: 1280x720=>2160x1080, 将采用宽的1.6875作为缩放因子, 得到Canvas的宽2160/1.6875=1280, 高1080/1.6875=640
-
- 值为1时
-
按照高度适配, 使用高度的缩放因子

-
比如: 1280x720=>2160x1080, 将采用高的1.5作为缩放因子, 得到Canvas的宽2160/1.5=1440, 高1080/1.5=720
-
- 值为0.5时
- 取宽的缩放因子和高的缩放因子的对数空间平均值作为缩放因子, 对数空间的平均值大约按照正常的平均数理解即可.
- 比如: 1280x720=>2160x1080, 将采用宽的1.6875和高的1.5取对数空间中的平均值1.59099, 得到Canvas的宽2160/1.59099=1357.645, 高1080/1.59099=678.8226.

- 取其他值时, 最终的缩放因子取决于更接近0还是1.
- 值为0时
-
Canvas介绍
Canvas组件是UGU的核心, Canvas定义了所有UI对象的绘制区域, 所有UI对象都是Canvas的子节点.
我们可以通过设置Canvas的属性来定义UI的渲染行为.
下面简单介绍Canvas的主要属性.
RenderMode: 渲染模式
渲染模式决定Canvas的绘制方式, 可以在屏幕空间中绘制, 也可以在世界空间中绘制.
绘制在屏幕空间中时, Canvas的大小不能手动指定, 需要由屏幕大小来决定.
在世界空间中绘制
在世界空间中绘制比较简单, 此时Canvas相当于一个3D物体, 只不过没有Z值为0.
在屏幕空间中绘制
绘制在屏幕空间中时, Canvas的大小不能手动指定, 需要由屏幕大小来决定.
又可以根据是否使用摄像机, 可以分为覆盖模式和摄像机模式.
ScreenSpace-Overlay: 覆盖模式
在这种模式下, Canvas总是在绘制完其它物体后, 最后进行绘制, 所以Canvas会覆盖在所有物体之上.
Canvas的大小和位置无法通过手动设置, 大小只能和屏幕大小一致, 位置总是处于屏幕正中间.
此时Canvas的一个像素等于一个Units.
根据CanvasScaler组件的设置, 最终确定Canvas的大小. 下面是例子.
-
如屏幕大小(800, 480)

-
不使用CanvasScaler, Canvas的Unit大小和像素大小与屏幕像素相同=(800, 400)

-
使用CanvasScaler, 设置如下

- Canvas的Unit大小=(800, 400), 像素大小=(1200, 720), Scale=480/720=0.6666667
- 一个Canvas像素等于0.6666667个Unit

ScreenSpace-Camera: 屏幕空间-摄像机
在这种模式下, Canvas相当于摄像机空间下的一个平面.
摄像机视口范围内的所有物体, 包括3D, Canvas, 粒子等, 都可以通过Z坐标或者SortingLayer来调整渲染和视觉顺序.
我们也可以混合多个摄像机的结果, 根据摄像机的Depth属性来决定渲染顺序, 值小的先渲染.

上面的摄像机负责照射UI, 下面的摄像机负责照射3D物体, 注意ClearFlags需要设置为DepthOnly或者Don’t Clear, 否则后渲染的摄像机渲染内容会被覆盖.

相机的视景体大小
相机主要分为正交相机和透视相机.
- 正交相机
- 正交相机的视景体大小由属性Size确定, Size代表视景体高度的一半, 宽度由高度x屏幕宽高比得出
- Size = 5, 屏幕为(800, 480), 则视景体高度为5x2=10个Units, 宽度= 800/480x10=16.666667个Units, 视景体大小为(10, 16.666667)(Units)
- 由此可得, 10个Units的高度可以将屏幕的竖直方向填满, 16.666667个Units的高度可以将屏幕的水平方向填满, 缩放因子为: 10/480=0.02083333
- 屏幕的像素x缩放因子=Units, Units/缩放因子=屏幕的像素
- 透视相机
- 透视相机的视景体大小由Field of View(视野)和近平面和远平面决定
- 在UI中我们一般使用正交相机, 透视相机具体计算在另外的文章给出
相机模式下的绘制
Canvas会被绘制在摄像机Z轴上的一定距离上, 这个距离由Canvas的Plane Distance指定.
Canvas的位置和旋转随摄像机位置和旋转的变化而变化, 不能通过RectTransform改变.
- 旋转摄像机, Canvas的位置也会跟着变化.
- 移动摄像机, Canvas的位置也会跟着变换
Canvas的大小由屏幕大小和CanvasScaler组件决定, 不能通过RectTransform改变.
Canvas的大小
Canvas的Units大小固定, 由摄像机的视景体决定.
- 正交相机下与摄像机的视景体大小一致
- 透视相机下与由视野, 近平面, 远平面, Canvas的Plane Distance值共同决定.
Canvas的像素大小不固定, 由几个因素决定.
- 默认情况下与屏幕像素大小一致
- 使用CanvasScaler之后, 根据适配方式调整大小
-
调整之后整体按照摄像机Sizex2/Canvas.Height作为Scale缩放
-
即Canvas的一个像素等于Scale个Units
-
如屏幕大小(800, 480), 摄像机为正交, Size=5


-
不使用CanvasScaler
- Canvas的Unit大小=(10, 16.66667), 像素大小为(800x480), Scale=5x2/480=0.208333333
- Canvas的一个像素等于0.208333333个Units

-
使用CanvasScaler, 设置如下

- Canvas的Unit大小=(10, 16.66667), 像素大小为(1200, 720), Scale=5x2/720=0.01388889
- Canvas的一个像素等于0.01388889个Units

-
总结
虽然屏幕适配只是在项目一开始的时候会使用, 但是其中涉及到的知识点还是很多的.
而且理解屏幕适配是后续理解UI坐标, 大小, 即RectTransform相关信息的前提条件.
我们会在另外的文章对RectTransform进行探索.
本文对一些关键的术语概念做了简单的介绍, 并对一些常用的设置和方案做了测试和验证.
希望对大家有所启发.
更多推荐


所有评论(0)