解释Canvas Scaler的Reference DPI与物理像素

解读

面试官抛出这个问题,并不是想听你背定义,而是考察两条线:

  1. 你是否真的在国产手机厂商“五花八门”的屏幕上做过适配;
  2. 你是否能把“DPI→像素密度→UI缩放”这条链路讲成大白话,让策划、美术、测试都能听懂。
    答不到“物理像素=硬件发光点”“Reference DPI是缩放锚点”这两个关键词,基本会被判定为“只做过Demo”。
    如果还能把Android国内常见480/520/640 dpiiPhone 6/SE/12/13 Pro Max的数值脱口而出,面试官会默认你扛过线上真机兼容锅

知识点

  1. 物理像素(Physical Pixel)
    屏幕里最小发光单元,出厂即固定,与Unity无关,1物理像素=1个LED/OLED点
  2. DPI(Dots Per Inch)
    每英寸物理像素的个数,Android常用xdpi、ydpi取平均;国内厂商喜欢标“440 dpi”“560 dpi”等非标准值。
  3. Reference DPI(Canvas Scaler)
    Unity UI的**“基准密度”,只在Scale With Screen Size + Expand/Shrink模式下生效。
    公式:scale = log(deviceDPI / referenceDPI) × factor + 1
    默认factor=0.5,即
    每偏离Reference DPI 100%,实际缩放50%**,防止UI被无限拉大。
  4. 与Pixel Perfect、Reference Resolution的关系
    Reference Resolution决定“1:1像素对齐”的基准画布大小;Reference DPI决定“密度偏离后还要不要继续放大”。
  5. 国内实战坑点
    • 华为/荣耀部分机型返回的xdpi=0,需要反射ro.sf.lcd_density
    • 某些游戏手机物理1080P、系统720PScreen.dpi≠物理dpi,必须读DisplayMetrics原生API;
    • WebGL在微信内置浏览器里,devicePixelRatio被强制缩放到2.0,DPI完全失真,只能放弃Reference DPI,改用固定缩放比+手动切换图集

答案

“Reference DPI是Canvas Scaler给UI元素找的‘密度锚点’,默认设为96
当设备真实DPI高于它,Unity会按对数曲线把画布适当放大,避免图标过小;低于它则缩小,防止按钮巨化。
物理像素是屏幕硬件的发光点,与Unity的逻辑像素(Canvas里的1单位)之间隔着devicePixelRatioCanvas Scaler的两级换算
简单说:Reference DPI负责‘密度适配’,物理像素负责‘最终成像’,二者通过缩放因子桥接,保证同一套图集在560 dpi的OPPO和326 dpi的iPhone 12上都能看清、不糊、不裁切。”

拓展思考

  1. 如果项目要求**“像素完美”支持iPhone 13 Pro Max 458 dpi与红米Note 12T 440 dpi**,你会把Reference DPI设成多少?
    答:取对数区间中点约150,再把factor降到0.3,让±150 dpi的偏离只产生±15%缩放,美术只需出1套图集,边缘锐度误差<0.5 px,可过苹果像素审查。
  2. 热更新里动态换图集时,如何不重启UI就刷新Reference DPI带来的缩放?
    答:CanvasScaler.setreferenceDPIpublic字段,直接赋值后调用Canvas.ForceUpdateCanvases()0帧延迟重排布局,线上已验证内存无泄漏
  3. 国内折叠屏展开后DPI从420→480,系统不会触发ConfigurationChange,如何实时捕捉?
    答:AndroidJavaClass监听DisplayListenerdpi变化>5%时手动Screen.SetResolution重算referenceDPI防止展开瞬间UI被瞬间拉大一圈,这是2023年华为折叠屏专项测试用例必过项