Unity NGUI元素位置计算与截图

Rect

Unity中的Rect包含x, y, width, height四个参数,分别是到屏幕左侧的距离、到屏幕底部的距离以及矩形的宽和高,需要注意的是这就代表着Rect是从左下角开始计算的。

Hf4ff9fee20b549b28386b21b65eb39e4h

屏幕尺寸计算

NGUI自带计算屏幕尺寸的函数,不过只能在编辑器模式下使用,如果在手机上会报错。

下面代码都是写成编辑器里面的脚本的,所以都是static。复习一下static:

静态类只包含静态成员,无法实例化,不能被继承,不能包含实例构造函数,如果一个类下所有成员都需要被共享则可以定义为静态类。

静态成员属于类,只会被创建一次;而相对的实例成员属于对象,有多少个对象就有多少份实例成员。

静态方法只能被重载,不能被重写。虽然字段不能声明为static const,但const本质上是静态的。

静态方法部署于特定对象,可以访问静态成员,不能直接访问实例成员,不过可以在实例函数调用的情况下把实例成员作为参数接受。

1
2
public static int screenWidth = (int)NGUITools.screenSize.x;
public static int screenHeight = (int)NGUITools.screenSize.y;

另一种计算方式,只能在手机上使用,编辑器中计算出来的不准确。

1
2
3
4
5
6
7
8
9
public static int width = 0;
public static int height = 0;
UIRoot root = GameObject.FindObjectOfType<UIRoot>();
if (root != null)
{
float s = (float)root.activeHeight / Screen.height;
width = Mathf.CeilToInt(Screen.width * s);
height = Mathf.CeilToInt(Screen.height * s);
}

NGUI元素位置计算

最近在做一个截图功能,自定义截图大小,使用的是Texture2D.ReadPixels(new rect(x,y,width,height),0,0)这个方法,奈何始终截不到需要的图。我们知道Unity的Rect是从左下开始算,但是反人类的是ReadPixels是从左上角开始计算,也就是说这里y的值需要换成屏幕高度减去原来的y再减去矩形高度。用代码来看更直观一些。

1
2
3
4
5
6
7
8
9
10
11
//计算NGUI元素在相机屏幕中的矩形位置
private static Rect NGUIObjectToRect(Camera camera, GameObject go)
{
Bounds bounds = NGUIMath.CalculateAbsoluteWidgetBounds(go.transform);
Vector3 min = camera.WorldToScreenPoint(bounds.min);
Vector3 max = camera.WorldToScreenPoint(bounds.max);
//正常的rect
//return new Rect(min.x, min.y, (max.x - min.x), (max.y - min.y));
//readpixels需要的rect (从左上角开始计算)
return new Rect(min.x, (screenHeight - max.y), (max.x - min.x), (max.y - min.y));
}

简单来说就是ReadPixels需要的Rect不是Unity用的Rect,这也太反人类了。。。

指定区域截图

截图功能可以这么思考,创建一个RenderTexture,然后赋值给摄像机的目标Texture,让摄像机拍的东西渲染在上面,接着再按照Rect裁剪这个RenderTexture就可以了,通过一个函数就可以做到。注意的是这里的Rect是给ReadPixels用的,所以传进来的时候记得按照上面写的函数写返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static Texture2D GetTex(Camera camera, Rect rect)
{
// 创建一个RenderTexture对象
RenderTexture rt = new RenderTexture(screenWidth, screenHeight, -1);
camera.targetTexture = rt;
camera.Render();
// 激活这个rt 并从中读取像素
RenderTexture.active = rt;
Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
// 从RenderTexture.active中读取像素
screenShot.ReadPixels(rect, 0, 0);
screenShot.Apply();
// 重置参数
camera.targetTexture = null;
RenderTexture.active = null;
GameObject.DestroyImmediate(rt);

return screenShot;
}

Texture2D转PNG图片

截图之后把最终的结果保存为图片,很简单,只需要T2D和一个路径就可以。

1
2
3
4
5
6
public static bool Save2Png(Texture2D t2d, string path)
{
byte[] bytes = t2d.EncodeToPNG();
System.IO.File.WriteAllBytes(path, bytes);
return true;
}