屏幕适配一直是一个老生常谈的问题, 虽然只是项目一开始的时候会用到, 但是还是有很多东西需要学习和了解, 今天给大家分享下一些个人的学习和总结.
屏幕适配有很多重要的概念, 坐标总是一个难以绕过的话题.
与适配相关的坐标有, 局部坐标, 世界坐标, 屏幕坐标. 下面我们一一道来.
父节点模型空间: 以父节点的轴心点为原点, 横纵坐标分别位于长和宽上, 构建父节点的模型空间.
本地坐标也被称为局部坐标, 就是节点的轴心点在父节点的模型空间中的位置. 也可以说是在世界空间下, 节点的轴心点所在位置向量减去父节点轴心点所在位置向量后的结果向量.
本地坐标随着父节点和子节点的轴心点的变化而变化.
在UGUI中, 真正决定本地坐标的是子节点的锚点和父节点的轴心点. 我们将在其它文章详细说明.
如果没有父节点, 那么节点的父节点就是整个世界空间.
我们在属性面板中看到的Position指的就是LocalPosition, 在没有父节点时, 节点的Position属性与LocalPosition属性相同.
世界坐标代表轴心点在世界空间下的坐标.
不管是Transform组件还会RectTransform组件, 都有世界坐标的属性.
有所区别的是, RectTransform的轴心点可以手动修改, 而Transform的轴心点需要在其他如3DMax中修改(或者通过代码).
屏幕分辨率指的是设备的可见区域, 以原点(左下角)和宽高为xy轴组成的屏幕空间.
屏幕坐标就是屏幕空间中某个点的位置.
上面了解了各种坐标后, 我们发现一个直接的问题, 就是如何将屏幕坐标与Unity中的世界坐标乃至局部坐标作适配, 这个过程就叫屏幕适配.
因为本文是分享UGUI的屏幕适配, 所以会着重讲解Canvas的适配, 3D物体的适配实质上是一样的, 大家可以作类比.
下面进入正题.
现在设备的分辨率五花八门, 我们不可能对每种不同的尺寸单独设计一套UI, 所以需要一套比较通用的适配方案来满足大部分设备的需求.
设计分辨率(引用分辨率): 我们会定义一个叫做设计分辨率的尺寸(Unity中叫引用分辨率), 美术会基于该分辨率来设计UI, 然后通过程序适配到游戏世界中, 适应各种不同的真实设备分辨率.
宽高比: 宽除以高得出的一个数值, 用于一些判断和缩放.
缩放因子: 按照某种适配方案得出的一个数值, 用于对物体的某个维度或者整体进行缩放.
映射: 将物体的各个维度分别与另一个物体一一对应.
Units: 代表Unity世界中一个单位的大小, 这个大小与屏幕像素的关系由摄像机或者其它因素决定.
Canvas根据绘制在屏幕空间还是世界空间后, 确定好大小后, 使用CanvasScaler组件来确定最终的大小.
当屏幕分辨率与设计分辨率不一致时, 可以通过CanvasScaler对画布进行调整, 以不同的方式来更好的将需要内容合理的展示给用户.
CanvasScaler的主要属性是UIScaleMode.
UIScaleMode是CanvasScaler的主要属性.
这个属性决定了Canvas不同的展示方式. 是屏幕适配的关键属性, 大部分屏幕适配是和这个属性打交道.
主要属性有
Shrink: 收缩并剪切, 选择变换比较大的一方来计算缩放因子, 另一方多余的部分被剪切
Expand: 扩充, 选择变换较小的一方来计算缩放因子, 另一方不够的部分填充固定颜色
Match Width Or Height: 匹配宽或者高, 并由Match值来决定最终的缩放值
Canvas组件是UGU的核心, Canvas定义了所有UI对象的绘制区域, 所有UI对象都是Canvas的子节点.
我们可以通过设置Canvas的属性来定义UI的渲染行为.
下面简单介绍Canvas的主要属性.
渲染模式决定Canvas的绘制方式, 可以在屏幕空间中绘制, 也可以在世界空间中绘制.
绘制在屏幕空间中时, Canvas的大小不能手动指定, 需要由屏幕大小来决定.
在世界空间中绘制比较简单, 此时Canvas相当于一个3D物体, 只不过没有Z值为0.
绘制在屏幕空间中时, Canvas的大小不能手动指定, 需要由屏幕大小来决定.
又可以根据是否使用摄像机, 可以分为覆盖模式和摄像机模式.
在这种模式下, Canvas总是在绘制完其它物体后, 最后进行绘制, 所以Canvas会覆盖在所有物体之上.
Canvas的大小和位置无法通过手动设置, 大小只能和屏幕大小一致, 位置总是处于屏幕正中间.
此时Canvas的一个像素等于一个Units.
根据CanvasScaler组件的设置, 最终确定Canvas的大小. 下面是例子.
在这种模式下, Canvas相当于摄像机空间下的一个平面.
摄像机视口范围内的所有物体, 包括3D, Canvas, 粒子等, 都可以通过Z坐标或者SortingLayer来调整渲染和视觉顺序.
我们也可以混合多个摄像机的结果, 根据摄像机的Depth属性来决定渲染顺序, 值小的先渲染.
上面的摄像机负责照射UI, 下面的摄像机负责照射3D物体, 注意ClearFlags需要设置为DepthOnly或者Don’t Clear, 否则后渲染的摄像机渲染内容会被覆盖.
相机主要分为正交相机和透视相机.
Canvas会被绘制在摄像机Z轴上的一定距离上, 这个距离由Canvas的Plane Distance指定.
Canvas的位置和旋转随摄像机位置和旋转的变化而变化, 不能通过RectTransform改变.
Canvas的大小由屏幕大小和CanvasScaler组件决定, 不能通过RectTransform改变.
Canvas的Units大小固定, 由摄像机的视景体决定.
Canvas的像素大小不固定, 由几个因素决定.
调整之后整体按照摄像机Sizex2/Canvas.Height作为Scale缩放
即Canvas的一个像素等于Scale个Units
不使用CanvasScaler
虽然屏幕适配只是在项目一开始的时候会使用, 但是其中涉及到的知识点还是很多的.
而且理解屏幕适配是后续理解UI坐标, 大小, 即RectTransform相关信息的前提条件.
我们会在另外的文章对RectTransform进行探索.
本文对一些关键的术语概念做了简单的介绍, 并对一些常用的设置和方案做了测试和验证.
希望对大家有所启发.