Unity如何保存拍摄的照片/屏幕截图

需要保存照片文件,首先需要能获取到图像,关于如何获取外部设备的图像,可以参考以下链接:

Unity控制佳能单反拍照及数据获取

Unity调用外部摄像头/网络摄像头/手机摄像头

Unity体感应用开发——Kinect V2 获取彩色摄像头数据

一般我会使用以下三种方式去获取图片:

1 ScreenCapture.CaptureScreenshot

目前我使用的Unity2018,Application.CaptureScreenshot已经过时不可以使用,现在是ScreenCapture类。

    void Start()
    {
        ScreenCapture.CaptureScreenshot(Application.streamingAssetsPath + "/demo.png", 0);
    }

第一个参数是文件名:如果不写全路径,windows默认在项目的根目录下,移动端默认在Application.persistentDataPath下。文件是以PNG形式保存,但不是不可以命名为JPG。

第二个参数可以是数字,那就表示放大系数,0和1是一样的就是Editor Game设置的分辨率,或是exe被打开时的分辨率,如果是2,表示2*2,4倍于原始大小。实践证明,单纯的放大像素等级,并不能提升画质,画质如果差,生成4k的图片一样差。第二参数也可以是ScreenCapture.StereoScreenCaptureMode的枚举值,从参数上看像是为cardboard vr准备的,由于没有使用过,无法确定。

这个方法多用在整个画面都有截取需要,不存在某些需要进入画面,某些不要。

好处就是写法简单,坏处就是不能定义区域,不能根据可见内容截图,而且语句执行结束到产生完整文件,会有一定的延迟。

基于RenderTexture

       全屏截取(即可区域截取)

Texture2D CaptureScreen(Rect rect)   
{  
    Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24,false);  
  
    // 读取屏幕像素
    screenShot.ReadPixels(rect, 0, 0);  
    screenShot.Apply();  
  
    // 文件生成  
    byte[] bytes = screenShot.EncodeToPNG();  
    string filename = Application.streamingAssetsPath + "/demo.png";  
    System.IO.File.WriteAllBytes(filename, bytes);  

    return screenShot;  
}  

      改变Rect可以定义截取区域,但是我几乎不用。

基于camera(即有可见层的配置,有区域截取)

常用这个方法,因为可以通过设置Camera的Culling Mask,决定哪些被截屏进去,哪些不截取。

/// 要被截屏的相机  
/// 截屏的区域  
Texture2D CaptureCamera(Camera camera, Rect rect)   
{  
    // 创建RenderTexture
    RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 0);  
    // 临时设置相关相机的targetTexture为rt, 并手动渲染相关相机  
    camera.targetTexture = rt;  
    camera.Render();  
  
    // 激活rt读取像素。  
    RenderTexture.active = rt;  
    Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24,false);  
    screenShot.ReadPixels(rect, 0, 0);
    screenShot.Apply();  
  
    // 重置
    camera.targetTexture = null;  
    RenderTexture.active = null; 
    GameObject.Destroy(rt);

    // 最后将这些纹理数据,成一个png图片文件  
    byte[] bytes = screenShot.EncodeToPNG();  
    string filename = Application.streamingAssetsPath+ "/demo.png";  
    System.IO.File.WriteAllBytes(filename, bytes);  

    return screenShot;  
}  

      可能会出现的问题

             1 使用基于Camera的方法,我记得出现过当场景中3D物体,又有UGUI物体的时候,3D物体始终会被拍进去的情况。这个问题后续再遇到,我再补充。

             2 我的画幅是16:9,但是我只想得到一张9:16的照片,那么方法就是改变Rect,比如

screenShot.ReadPixels(new Rect(0,r.height*(1f-scaleParm)/2f,screenShot.width,screenShot.height), 0, 0);
            screenShot.Apply();
//scaleParm是横边的比例,比如 1-9/(16/9)/16

基于硬件sdk

为什么会有这个需求,是因为有的时候你的设备获取的画质可能是2k以上,但是你的屏幕最高分辨率就到2k,上述方法没有办法真的给你原画质的照片,你就是需要原始的数据。

      如果使用单反,参考:Unity控制佳能单反拍照及数据获取

      如果使用网络摄像头,比如C1000e能到4k(实际上到了4k会延迟),目前没有办法,除非摄像头有SDK

      如果使用kinect,而你的屏幕连1920*1080都没有,或者你用了Kinect Azure,可以获取到ColorImage之后,通过texture2d转bytes,转文件。

 

 

你可能感兴趣的:(Unity3D)