文档章节

NGUI 屏幕适配(2D UI)

ylme
 ylme
发布于 2017/05/05 20:22
字数 1801
阅读 84
收藏 0
点赞 0
评论 0

博客内容基于 NGUI.3.11.2,讲述 NGUI 2D UI 。

设备无关坐标

以 OpenGL 为例,经过各种图形阶段(stage)后,几何形状最终被转换成像素显示在屏幕上。设备屏幕坐标以像素为单位,是设备相关的。不同设备分辨率不一样,即使同一设备,不同窗口的大小也不一样。在不关注具体设备的情况下绘制几何形状,则需要设备无关坐标系统。OpenGL 标准化设备坐标空间(NDC)在 X 轴、Y 轴,Z 轴上是 [-1, 1] 。举个例子,不做任何坐标变换(transform)和视口变换(viewport),对于顶点坐标(-1.0f, -1.0f, 0.0f)、(1.0f, -1.0f, 0.0f)、(1.0f, 1.0f, 0.0f)、(-1.0f, 1.0f, 0.0f),调用 glDrawArrays 并指定 GL_TRIANGLE_FAN 绘制的长方形覆盖整个窗口。

Unity 提供的坐标单位(设置 Transform 组件各属性值,如 position)就是设备无关的。设置 Camera.orthographic = true 使用 2D 正交摄像机,假设屏幕宽高比为 aspect ,则正交摄像机 XY 平面矩形宽高分别为 cam.orthographicSize * 2.0f * apsectcam.orthographicSize * 2.0f

NGUI 2D UI 像素单位

使用菜单 NGUI|Create|2D UI 创建 2D UI 。具体的创建函数 NGUITools.CreateUI 有如下设置 2D UI 部分代码,并且摄像机处于(0, 0, 0)。则可以计算渲染矩形的范围(先忽略 Z 轴)。

cam.orthographic = true;
cam.orthographicSize = 1;
cam.nearClipPlane = -10;
cam.farClipPlane = 10;

假设屏幕宽高比 aspect = 1.778f 。由于摄像机处于中心,则渲染矩形的左下角世界坐标是(-1.778f, -1.0f),右上角世界坐标是(1.778f, 1.0f)。这个坐标范围与设备无关,处于这个范围内便可以被渲染。

再想一下,如果在这个坐标范围内再封装一层并且把 GameObject 的 Transform.localScale 属性设置为(1.0f, 1.0f, 1.0f)(避免受到被此属性影响),然后坐标轴都缩小 360 倍,为了使得 GameObject 仍能被渲染,则 GameObject 的坐标值要被放大 360 倍。则现在左下角坐标变成了(-640.0f, -360.0f),右上角为(640.0f, 360.0f),现在坐标范围变成了 1280 x 720,此时一张 1280 x 720 的图片则可以显示在整个窗口中。于是形成了以像素为单位的新的坐标系统,这样会比之前的设备无关坐标范围更容易理解和使用。

其实 NGUI 像素单位的本质就是选择一个缩放因子(factor)对坐标进行缩小,这样 GameObject 实际的坐标值和大小值便可以放大相应的倍数,便于使用。最终渲染时会再乘以 factor 得到实际的坐标值或者大小值。NGUI 是根据高度计算缩放因子的,上例中高度是 2.0f 且设置 aspect = 1.778f,缩放因子是 factor = 2.0f / 720,于是构造了 1280 x 720 虚拟分辨率。若设备屏幕大一些,则 2.0f 对应的高度便会大一些,图像也就显示的大一些,反之便显示的小一些。

屏幕适配

UIRoot 与缩放因子

前面介绍了缩放因子,那么 NGUI 中是如何处理的呢?使用菜单创建 UI 时,会创建两个 GameObject ,UIRootUIPanel添加到 UI Root 而 UICamera 添加到 Camera 。UIRoot 处理缩放逻辑,UIPanel 管理渲染,UICamera 管理消息处理。一个 NGUI 渲染实例在 Unity Inspector 面板中以树形结构具体表现,UIRoot 所在的 GameObject 为根节点(是其余所有 GameObject 直接或间接的 parent),其余 GameObject 都作为此根节点的直接或者间接子节点。多个 NGUI 渲染示例(UIRoot)不能有交集,不然其中一个作为另一个的 child 会导致缩放逻辑会出错。

缩放因子的计算与应用在 UIRoot.UpdateScale 函数中。其中两行如下。

float size = 2f / calcActiveHeight;
mTrans.localScale = new Vector3(size, size, size);

size 就是前面提到的缩放因子。calcActiveHeight 是考虑屏幕适配后计算的高度值(以像素为单位)。然后把 size 赋值给 localScale 。由于 UIRoot 附加到根节点,所以其他的所有 GameObject 都会受到此缩放因子的影响。

这里 2f 其实就是 2 * Camara.orthographicSize,由上面可知 orthographicSize 被设置成了 1f 。

不同的分辨率

实际开发时会选择一个标准分辨率,如 1280 x 720(aspect 为 16:9),并以此为标准设计美术资源,比如游戏背景图片为 1280 x 720 。对于手游,不同设备的分辨率也不同,屏幕适配就是为了把以开发时选择的标准分辨率为基准创建的游戏画面,更好的在不同的设备上显示。

假设 calcActiveHeight 返回的值就是 720(Scaling.Constrained 和 Constraint.FitHeight)。

  • 若设备屏幕宽高比是 16:9 则能完毕适配。实际高度是 2.0f,则根据宽高比计算宽度为 3.556f 。假如有一张显示在中心的图片,大小为 1280 x 720 像素,乘以缩放因子(2.0f / 720)后刚好与实际的宽度和高度一致,图片正常全屏显示。注意只要是宽高比是 16:9,不管设备是 1280 x 720 还是 640 x 320 或其他分辨率,都是能完美适配的。因为 Unity 会自动把宽度 3.556f 和 高度 2.0f 与设备窗口的宽和高映射,这就是设备无关坐标。
  • 若设备屏幕宽高比不是 16:9 比如 1024 x 768(4:3),则一张 1280 x 720 显示在中心的图片不能完全适配。实际高度是 2.0f, 宽度为 2.667f 。而缩放因子为 2.0f / 720,图片的宽和高乘以缩放因子得到宽和高分别为 3.556f 和 2.0f,和实际的宽度 2.667f 相比,图片更宽,所以图片会超出部分屏幕。如下图两种分辨率对比。
  • NGUI 提供了多种屏幕适配策略由 UIRoot.scalingStyleUIRoot.constraint 指定,这里就不深入分析了。基本的策略有如下。
  • 简单的完全适配宽度或者高度。当不能完美适配时,图片会在垂直或者水平方向超出。
  • 比较标准宽高比和设备的宽高比,来选择在水平还是垂直方向完全匹配。若不能完美适配时,图片会全部显示,只是会有一个方向会多出间隙。
  • NGUI 也提供了锚点功能。通过结合屏幕适配测试和锚点,来使图像更好的跨设备显示。

NGUIDiffReso

2D UI 还是 3D UI

假设标准分辨率是 1280 x 720,不使用锚点且 UIRoot 使用 Scaling.ConstrainedConstraint.FitHeight。有上图可知在 1024 x 768 的设备上,图片在水平方向会超出。若选择 Constraint.FitWidth 则 2D UI 可以完全显示图片,垂直方向会有一些间隙,但是 3D UI 不能。

具体的原因先不分析,简要介绍一下,2D UI 中缩放因子影响渲染矩形平面的缩放。而 3D UI 中缩放因子除了影响渲染平面,还影响渲染平面到摄像机的距离,所以会造成 UIRoot 选择不同的缩放策略而没有效果。

所以我觉得,当需要 3D 效果时才使用 NGUI 3D UI,默认就使用 2D UI 即可。

© 著作权归作者所有

共有 人打赏支持
ylme
粉丝 10
博文 39
码字总数 40752
作品 0
广州
程序员
高效的iPhone X适配技术方案(UGUI和NGUI)(转)

本文转自这里 适配来源: 按照苹果官方人机界面指南 : https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/ 在iPhone X 异形屏幕上,苹果提出了Safe Area安全区...

AngerCow
06/12
0
0
Unity 利用NGUI做屏幕分辨率适配+学习UIDraggablePanel的使用

大家使用unity,一定有看中其跨平台的强大功能,因此也难免会遇到不同屏幕分辨率适配的问题。 先说说UIRoot.在新版本的ngui中加入一个选择菜单,分别有PixelPerfect,FixedSize,FixedSizeOnM...

AveryHuo
2013/10/30
0
0
使用NGUINGUI的相关介绍

1.3 使用NGUI 要使用NGUI,需要首先为游戏项目导入NGUI插件资源,然后再创建UI Root对象,在这以后才可以添加各种UI控件,下面本节会详解介绍这些知识本文选自NGUI从入门到实战! 1.3.1 导入...

大学霸
2015/01/14
0
0
NGUI创建Camera参数为Simple 2D的UI UI对象的结构UI Root(2D)

NGUI创建Camera参数为Simple 2D的UI UI对象的结构UI Root(2D) 使用NGUI创建的Camera参数为Simple 2D的UI,会在游戏的场景中生成1个名为UI Root(2D)的游戏对象,且此对象下还包含了3个其它对象...

大学霸
2015/03/06
0
0
Unity3d + NGUI 的多分辨率适配

移动端的多机型适配 现在要介绍的是《锁链战记》这款游戏的适配方法,这种适配方法是UI是一个基础尺寸,背景是一个基础尺寸,背景比UI多出的部分是一些没有实际作用的部分,这样的适配方式避...

乐逍遥jun
2016/02/22
84
0
NGUI全面实践教程(大学霸内部资料)

NGUI全面实践教程(大学霸内部资料) 试读文档下载地址:链接:http://pan.baidu.com/s/1jGosC9g 密码:8jq5 介绍:NGUI全面实践教程(大学霸内部资料)本书是国内NGUI最新教程,以全新的3.8...

大学霸
2015/03/31
0
0
ngui3.5.7 版本Scroll View实现方法

现在网上的教材都是老版本的,现在的版本并没有Drag Panel Contents脚本,所以我对着现在的DEMO琢磨出了实现方法 第一,创建NGUI ui,其他组件不必创建,我只要NGUI这个摄影机,将这个NGUI设置...

qazqaz12378
06/26
0
0
Hierarchy视图里的Transform和Camera组件

Hierarchy视图里的Transform和Camera组件 在Hierarchy视图里,选中Camera,然后在Inspector视图里查看其各组件,如图1-8所示。对于Transform和Camera组件,对于使用过Unity的读者来说再熟悉不...

大学霸
2015/04/10
0
0
Unity-NGUI不规则点击碰撞处理

在开发过程中经常会遇到这样的问题,UI点击的地图是一个不规则形状的这是如何解决这类问题呢?这里提供两种解决问题的方案。 使用Unity内置的PloygonCollider碰撞体,进行碰撞检测。但是需要...

abaojin
2015/12/03
501
0
使用UNITY3d制作2048游戏

使用unity的插件NGUI,可以快速的制作2D游戏; 2048这个游戏主要的核心是算法,不管用cocos2d,erget还是其他的引擎,算法基本不变,细节有变化而已; 基本算法图: 数字代表XY坐标,每个格子...

安世博
2015/08/18
423
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

50 行 Python 代码,带你追到最心爱的人

程序员世纪难题 人们一提到程序员第一反应就是:我知道!他们工资很高啊!但大部分都是单身狗,不懂得幽默风趣,只是每天穿格子 polo 衫的宅男一个。甚至程序员自己也这样形容自己:钱多话少...

猫咪编程
4分钟前
0
0
JAVA知识点随心记

1.Switch case具体的支持类型? Q:支持byte、short、char、int基本类型,枚举类型和String类型(JDK7以上支持),四种基本类型的包装类型也支持,但是原因在于触发了自动拆箱,将包装类型拆成了基本...

勤奋的蚂蚁
15分钟前
0
0
NoSQL

一、NoSQL介绍 NoSQL属于非关系型数据,mysql属于关系型数据库。 对于关系型数据库来说,是需要把数据存储到库、表、行、字段里,查询的时候根据条件一行一行地去匹配,当数据量非常大的时候...

人在艹木中
20分钟前
0
0
第17章MySQL主从配置

mysql安装总结 mysql主从准备工作: 准备两台机器,每台机器安装msyql服务,并启动mysql服务 mysql详细安装 1.首先下载二进制免编译的包,下载到/usr/local/src/目录下 2.解压压缩包 3.解压完...

Linux学习笔记
24分钟前
0
0
Redis高可用及分片集群

一、主从复制 使用异步复制 一个服务器可以有多个从服务器 从服务器也可以有自己的从服务器 复制功能不会阻塞主服务器 可以通过服务功能来上主服务器免于持久化操作,由从服务器去执行持久化...

Java大蜗牛
27分钟前
0
0
前端面试题汇总

最近在复习,准备找工作了,特此总结一下前端的相关知识。 1.获取浏览器URL中查询字符的参数: function getQuery(name){    var reg = new RegExp("(^|&)"+name+"=([^&]*)"(&|$));...

凛冬来袭
今天
0
0
可持续发展的学习道路

与其要求别人,不如提升自己 内心渴望进步 经常做出改变现有模式,不断学习 寻找资源,整合资源,不断熟练这种模式 渠道很重要 先打开新世界的航路

狮子狗
今天
0
0
apollox-lua开源项目 示例codepen2

今天在示例上增加了几个功能, 首先添加js array的标准库。 所有js array的方法目前都支持了。 添加查看code模式。 点击查看code可以看到生成的lua代码。默认web模式需要把标准库连接进来, ...

钟元OSS
今天
0
0
javascript性能优化之避免重复工作

javascript最重要也最根本的性能优化标准之一是避免工作,避免工作又包括两点,第一,不做不必要的工作,第二,不做重复的已经完成的工作。第一部分可以通过代码重构完成,第二部分不做重复的...

老韭菜
今天
0
0
缓存穿透、并发和雪崩那些事

0 题记 缓存穿透、缓存并发和缓存雪崩是常见的由于并发量大而导致的缓存问题,本文讲解其产生原因和解决方案。 缓存穿透通常是由恶意攻击或者无意造成的;缓存并发是由设计不足造成的;缓存雪...

Java填坑之路
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部