截图是个常见的需求,大概找了3种不同的方式,每种方式略有区别。
1. Texture转换
在此之前,先说下纹理转换。如果想把一个纹理存储到本地,就需要先拿到每个像素的数据,而能拿到数据的类型是Texture2D,如果要存储的纹理是其他类型,则需要先将其转换成Texture2D。
Texture2D之所以可以拿到像素数据,是因为在导入纹理时,如果勾选了read/write属性,就会在内存这边保留一份数据,导致运存和现存各有一份数据。Texture2D的read方法会从当前激活的RenderTexture中读取数据。
所以,如果需要转换的是RenderTexture,需将其设置到当前激活。如果是其他类型的Texture,则需要增加一步,创建一个RenderTexture,通过Graphic的Blit方法将数据复制到RenderTexture。
对于RenderTexture,使用RednerTexture.GetTemporary
和RenderTexture.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