先了解一个公式

原始尺寸 = 图片尺寸/(Pixels Per Unit / Refenrence Pixels Unit)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//官方源码
public float pixelsPerUnit
{
get
{
float spritePixelsPerUnit = 100;
if (sprite)
spritePixelsPerUnit = sprite.pixelsPerUnit;

float referencePixelsPerUnit = 100;
if (canvas)
referencePixelsPerUnit = canvas.referencePixelsPerUnit;

return spritePixelsPerUnit / referencePixelsPerUnit;
}
}
ge.csC#
public override void SetNativeSize()
{
if (overrideSprite != null)
{
float w = overrideSprite.rect.width / pixelsPerUnit;
float h = overrideSprite.rect.height / pixelsPerUnit;
rectTransform.anchorMax = rectTransform.anchorMin;
rectTransform.sizeDelta = new Vector2(w, h);
SetAllDirty();
}
}

Constant Pixel Size固定像素模式

图1

用的较少,因为无法自适应屏幕,但可以通过代码改变(手动获取屏幕分辨率,代码调整缩放系数)。

Scale With Screen Size缩放模式

图2

Reference Resolution:参考分辨率,缩放模式下的所有匹配模式都会基于参考分辨率进行自适应计算,总体来说,当前屏幕分辨率大于参考分辨率,Ui变大,反之Ui变小。

再了解一个公式:屏幕分辨率 = 画布尺寸 * 缩放系数,

屏幕分辨率不变,画布尺寸和缩放系数反比.

该模式下的三种匹配算法的目的都是为了得到一个缩放系数,从而改变画布尺寸,进而适配屏幕。


Screen Match Mode:屏幕匹配模式,当前屏幕分辨率不适应参考分辨率时,用于分辨率自适应的匹配模式,就是不同算法。

  • Expand :水平或垂直扩展画布区域,使画布不会小于参考分辨率,可能产生黑边。

    计算公式:

    缩放系数=Mathf.Min(屏幕宽度/参考分辨率宽度,屏幕高度/参考分辨率高度)

    1
    2
    3
    4
    5
    case ScreenMatchMode.Expand:
    {
    scaleFactor = Mathf.Min(screenSize.x / m_ReferenceResolution.x, screenSize.y / m_ReferenceResolution.y);
    break;
    }

    画布变大,简单说就是最大程度的展现整个Ui。

  • Shrink :水平或垂直裁剪画布区域,使画布不会大于参考分辨率,可能发生裁剪。

    计算公式:

    缩放系数=Mathf.Max(屏幕宽度/参考分辨率宽度,屏幕高度/参考分辨率高度)

    case ScreenMatchMode.Shrink:
    {
        scaleFactor = Mathf.Max(screenSize.x / m_ReferenceResolution.x, screenSize.y / m_ReferenceResolution.y);
        break;
    }
    

    画布变小,简单说就是最大程度的将UI填满屏幕。

  • Match Width or Height :以宽度、高度或二者的某种平均值作为参考来缩放画布区域.

    计算公式见下面官方源码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    kLogBase=2;
    case ScreenMatchMode.MatchWidthOrHeight:
    {
    // We take the log of the relative width and height before taking the average.
    // Then we transform it back in the original space.
    // the reason to transform in and out of logarithmic space is to have better behavior.
    // If one axis has twice resolution and the other has half, it should even out if widthOrHeight value is at 0.5.
    // In normal space the average would be (0.5 + 2) / 2 = 1.25
    // In logarithmic space the average is (-1 + 1) / 2 = 0
    float logWidth = Mathf.Log(screenSize.x / m_ReferenceResolution.x, kLogBase);
    float logHeight = Mathf.Log(screenSize.y / m_ReferenceResolution.y, kLogBase);
    float logWeightedAverage = Mathf.Lerp(logWidth, logHeight, m_MatchWidthOrHeight);
    scaleFactor = Mathf.Pow(kLogBase, logWeightedAverage);
    break;
    }

    为什么要用对数平均?因为采用对数得到的缩放系数更准确。

    举个例子:

    我们取Match为0.5,即长宽权重相同。

    屏幕分辨率:200,200.

    参考分辨率 : 100,400

    宽比为2,高比为0.5 按理来说应该扯平了的,缩放系数应该为1.

    但普通平均算出缩放系数为2*0.5+0.5**0.5=1.25,

    对数平均算出 logWeightedAverage= 1+(-1-1)*0.5=0, scaleFactor=1,显然更加准确。

Constant Physical Size固定物理模式

图3

俺没用过。

Physical Unit:Unit物理单位

Fallback Screen DPI: 备用DPI,当找不到设备Dpi时,使用此值。

Default Sprite DPI: 默认图片DPI。

还要知道的概念:

DPI:每英寸像素点数,像素密度

分辨率:如果1920x1080 则长有1920个像素点,高有1080个像素点。

电脑显示屏和手机显示屏分辨率能够相同,是由于手机屏幕DPI更高。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
float currentDpi = Screen.dpi;
float dpi = (currentDpi == 0 ? m_FallbackScreenDPI : currentDpi);
float targetDPI = 1;
switch (m_PhysicalUnit)
{
case Unit.Centimeters: targetDPI = 2.54f; break;
case Unit.Millimeters: targetDPI = 25.4f; break;
case Unit.Inches: targetDPI = 1; break;
case Unit.Points: targetDPI = 72; break;
case Unit.Picas: targetDPI = 6; break;
}

SetScaleFactor(dpi / targetDPI);
SetReferencePixelsPerUnit(m_ReferencePixelsPerUnit * targetDPI / m_DefaultSpriteDPI);

没用过也不好说效果是什么,官方这样说道

使用 Constant Physical Size 模式时,可按物理单位(如毫米、点或派卡)指定 UI 元素的位置和大小。此模式要求设备正确报告其屏幕 DPI。对于不报告 DPI 的设备,可以指定回退 DPI。

World3D模式(Canvas渲染模式为World Space的默认缩放模式)

Dynamic Pixels Per Unit:用于 UI 中动态创建的位图(如文本)的每单位像素量。越大图片越清晰,过大图片会变小。