oynix

人生需要一些摸鱼时刻,做什么都可以,不做什么也可以

Unity截图功能

截图是个常见的需求,大概找了3种不同的方式,每种方式略有区别。

1. Texture转换

在此之前,先说下纹理转换。如果想把一个纹理存储到本地,就需要先拿到每个像素的数据,而能拿到数据的类型是Texture2D,如果要存储的纹理是其他类型,则需要先将其转换成Texture2D。

Texture2D之所以可以拿到像素数据,是因为在导入纹理时,如果勾选了read/write属性,就会在内存这边保留一份数据,导致运存和现存各有一份数据。Texture2D的read方法会从当前激活的RenderTexture中读取数据。

所以,如果需要转换的是RenderTexture,需将其设置到当前激活。如果是其他类型的Texture,则需要增加一步,创建一个RenderTexture,通过Graphic的Blit方法将数据复制到RenderTexture。

对于RenderTexture,使用RednerTexture.GetTemporaryRenderTexture.ReleaseTemporary进行创建和销毁,可以得到性能上的优化。

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
private static Texture2D GetTex2D(Texture tex)
{
var texture2D = new Texture2D(tex.width, tex.height, tex.graphicsFormat, TextureCreationFlags.None);
RenderTexture rt;
var release = false;
if (tex is RenderTexture texture)
{
rt = texture;
}
else
{
rt = RenderTexture.GetTemporary(tex.width, tex.height);
Graphics.Blit(tex, rt);
release = true;
}

var previousRt = RenderTexture.active;
RenderTexture.active = rt;
texture2D.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
texture2D.Apply();
RenderTexture.active = previousRt;

if (release)
{
RenderTexture.ReleaseTemporary(rt);
}

return texture2D;
}

2. 调用系统方法,截图全屏幕

这种方式方便且直接,调用一个方法即可

1
2
3
4
5
private void CaptureDefault()
{
var path = Path.Combine(Application.dataPath, "screenshoot.jpg");
UnityEngine.ScreenCapture.CaptureScreenshot(path);
}

3. 截取屏幕指定区域

相比于上面的方式,这种可以通过Rect来指定需要截取的区域,使用的方式是Texture2D在read数据时,可以指定区域范围,其中Rect的x和y指定的是区域起点的屏幕坐标,原点是屏幕左下角(0, 0),如下,则是从原点开始,截取一块长1800像素,高800像素的区域

1
2
3
4
5
6
7
8
9
10
11
12
13
private IEnumerator DoCaptureRect()
{
// 等待渲染完一帧
yield return new WaitForEndOfFrame();
var rect = new Rect(0, 0, 1800, 800);
var texture2D = new Texture2D((int) rect.width, (int) rect.height, TextureFormat.RGBA32, false);
texture2D.ReadPixels(rect, 0, 0);
texture2D.Apply();

var bytes = texture2D.EncodeToPNG();
var path = Path.Combine(Application.dataPath, "screenshoot.png");
File.WriteAllBytes(path, bytes);
}

4. 截取指定相机渲染的内容

上面两种方式使用的是场景主相机渲染的数据,但有时可能需要截取指定相机渲染出的纹理。Camera中有一个类型是RenderTexture的参数,默认值是null,如果设置了具体的值,相机会把渲染结果同时传给该RenderTexture。有了这个RenderTexture,就有了相机渲染的数据。该方式很灵活,定制型很强,可以按需实现多种截屏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private IEnumerator DoCaptureCamera()
{
// 照常等待一帧
yield return new WaitForEndOfFrame();
var renderTexture = RenderTexture.GetTemporary(Screen.width, Screen.height);
var c = Camera.main;
c.targetTexture = renderTexture;
c.Render();
c.targetTexture = null;

var texture2D = GetTex2D(renderTexture);
renderTexture.Release();

var bytes = texture2D.EncodeToPNG();
var path = Path.Combine(Application.dataPath, "screenshoot.png");
File.WriteAllBytes(path, bytes);
}

参考

  • https://www.twblogs.net/a/5b8b2d372b717718832ddc37
  • https://blog.csdn.net/s15100007883/article/details/80411638
  • https://juejin.cn/post/6994604377059098631
------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.net/2024/03/be7f59aff3b8/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道