Unity RenderTexture的保存和多线程

2024-03-30 16:08

本文主要是介绍Unity RenderTexture的保存和多线程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在Unity中如果要保存相机图片,我们最常用的方法是首先把RenderTexture转化成Texture2D,如下:

Texture2D texture2D = null;
texture2D = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false);
var previous = RenderTexture.active;
RenderTexture.active = renderTexture;
texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
RenderTexture.active = previous;
texture2D.Apply();
void Awake()
{targetRenderTexture = new RenderTexture((int)(normalSize), (int)(normalSize), 0 , RenderTextureFormat.ARGB32);//, RenderTextureFormat.Defaultint quality = QualitySettings.GetQualityLevel();if (quality > 0)targetRenderTexture.antiAliasing = 4;elsetargetRenderTexture.antiAliasing = 1;
}

RenderTexture创建部分

然后再把图片保存成二进制格式进行保存,如下:

byte[] bytes = txtureSmall.EncodeToPNG();
try
{string forder = GetFileDirectory(path);bool exists = System.IO.Directory.Exists(forder);if (!exists)System.IO.Directory.CreateDirectory(forder);System.IO.File.WriteAllBytes(path, data);
}
catch (Exception ee)
{Debug.Log("文件写入失败:" + path + " Error:" + ee.Message);
}

如果是在保存进度,场景切换等允许卡顿的地方操作是没有问题的。

如果是在不允许有卡顿感的操作中就是大问题了。

经过分析主要来自EncodeToPNG函数,耗费了大量CPU。

那么如果我们让他在别的进程运行,游戏就不会有卡顿感了。

马上进行测试:

		new System.Threading.Thread(() =>{这里处理上面的逻辑。}).Start();

发现不能在其他进程里处理RenderTexture,txtureSmall.EncodeToPNG,会报出
…… can only be called from the main thread.

那么怎么做呢,其实Unity提供了其他的方法来做这样事情。

下面做一个记录

		int nw = rendertxture.width;int nh = rendertxture.height;//filesavepath = filename;GraphicsFormat format = rendertxture.graphicsFormat;UnityEngine.Rendering.AsyncGPUReadbackRequest request = UnityEngine.Rendering.AsyncGPUReadback.Request(rendertxture, 0 );yield return 0;while (!request.done){yield return new WaitForEndOfFrame();}if (request.hasError){Debug.Log("GPU readback error detected.");yield break;}byte[] array = request.GetData<byte>().ToArray();Task.Run(() =>{
#if UNITY_EDITORDebug.Log("保存进度图:" + filename);
#endifbyte[] datas = ImageConversion.EncodeArrayToPNG(array, format, (uint)nw, (uint)nh);CFunc.StreamWriter(filename, datas);});

这样主线程就不会卡顿了。

经过一段时间测试后发现
AsyncGPUReadbackRequest的函数,可能会出现报错 This GfxDevice does not support asynchronous readback
发现报错了图片也能显示出来。匪夷所思
然后通过SystemInfo.supportsAsyncGPUReadback函数来判断发现也是False,说明不支持,不支持为说明图可以显示出来呢。

所以研究了下,直接可以通过拿出RenderText的Texture2D,获取到GetPixeds32,然后再放入多线程处理。代码如下,可能速度稍微慢一些。

	Texture2D saveToTexture(RenderTexture renderTexture){Texture2D texture2D = null;texture2D = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false);var previous = RenderTexture.active;RenderTexture.active = renderTexture;texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);RenderTexture.active = previous;texture2D.Apply();return texture2D;}Texture2D txture = saveToTexture(targetRenderTexture);Color32[] array = txture.GetPixels32();//这里如果renderTexture不是RenderTextureFormat.ARGB32,在IOS中好像是BGRA,会导致获取保存的颜色变色,原因未知.GameObject.DestroyImmediate(txture);Task.Run(() =>{
#if UNITY_EDITORDebug.Log("保存进度图:" + filename);
#endifbyte[] bytes = ImageConversion.EncodeArrayToPNG(array, format, (uint)nw, (uint)nh);CFunc.StreamWriter(filename, bytes);pone.ok = true;});

相关技术资料
https://docs.unity3d.com/ScriptReference/ImageConversion.EncodeArrayToPNG.html
https://forum.unity.com/threads/asyncgpureadbackrequest-and-encodetopng.551314/
https://forum.unity.com/threads/using-the-job-system-to-save-images.522837/

这篇关于Unity RenderTexture的保存和多线程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/861948

相关文章

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

使用C++将处理后的信号保存为PNG和TIFF格式

《使用C++将处理后的信号保存为PNG和TIFF格式》在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示,C++提供了多种库来处理图像数据,本文将介绍如何使用stb_ima... 目录1. PNG格式保存使用stb_imagephp_write库1.1 安装和包含库1.2 代码解

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

vscode保存代码时自动eslint格式化图文教程

《vscode保存代码时自动eslint格式化图文教程》:本文主要介绍vscode保存代码时自动eslint格式化的相关资料,包括打开设置文件并复制特定内容,文中通过代码介绍的非常详细,需要的朋友... 目录1、点击设置2、选择远程--->点击右上角打开设置3、会弹出settings.json文件,将以下内

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

多线程解析报表

假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。 Way1 join import java.time.LocalTime;public class Main {public static void main(String[] args) thro

Java 多线程概述

多线程技术概述   1.线程与进程 进程:内存中运行的应用程序,每个进程都拥有一个独立的内存空间。线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换、并发执行,一个进程最少有一个线程,线程实际数是在进程基础之上的进一步划分,一个进程启动之后,进程之中的若干执行路径又可以划分成若干个线程 2.线程的调度 分时调度:所有线程轮流使用CPU的使用权,平均分配时间抢占式调度

Java 多线程的基本方式

Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

JAVA- 多线程

一,多线程的概念 1.并行与并发 并行:多个任务在同一时刻在cpu 上同时执行并发:多个任务在同一时刻在cpu 上交替执行 2.进程与线程 进程:就是操作系统中正在运行的一个应用程序。所以进程也就是“正在进行的程序”。(Windows系统中,我们可以在任务管理器中看 到进程) 线程:是程序运行的基本执行单元。当操作系统执行一个程序时, 会在系统中建立一个进程,该进程必须至少建立一个线