• Unity通过指定摄像机截屏


    简介

    介于照抄网上之前的截图教程,然后在实际应用过程中出现了一些小小的问题,修正了一下下,特此分享一下
    PS:代码在后面

    原理

    原理很简单,就是将一个相机的内容渲染到一个贴图上,然后将贴图保存为图片

    坑s

    1.摄像机截图发现内容不全(比如3D模型丢失)

    摄像机渲染的对象是一个RenderTexture,然后RenderTexture的构造函数大体上是这样的:
    RenderTexture(int width, int height, int depth, RenderTextureFormat format, RenderTextureReadWrite readWrite);
    最后两个参数就不解释了,width 和 height就是宽和高的分辨率,也不用解释,比较坑的是depth
    官方的解释是:Number of bits in depth buffer (0, 16 or 24). Note that only 24 bit depth has stencil buffer
    大概意思就是这个是位图深度,只能是0、16、24三个参数,然后如果你的深度不够的话,就会出现部分模型不显示,具体原因我也不知道,只能臆测是unity渲染是把不同layer的物体渲染到不同的深度上吧
    然后由于之前抄的教程构造函数是这样写的:new RenderTexture((int)rect.width, (int)rect.height, 0),导致截图内容只有UI层,其他层一概不显示
    最终解决方案是:new RenderTexture((int)rect.width, (int)rect.height, 24);把最后一个参数改成24就好了。

    2.截屏无法分享(文件无法访问)

    其实这个是自己的问题,在传入路劲的时候使用了Application.dataPath.......
    这个路径返回的是asset下的路劲,无法进行读写,导致在分享的时候操作失败(估计也没有写入成功,因为按照原理这个路径应该是打包进入apk里面的)
    解决方案很简单,换成Application.persistentDataPath就可以了

    3.截屏卡顿

    这个问题捣鼓了很久,至少两个小时以上.......
    先是把截屏弄成了协程,然后分别放到了独立帧,然后把文件IO改成了buffer的,最后发现还是卡
    然后辗转反侧,反侧辗转,突然发现手机上的截图文件巨大无比(手机分辨率太高了.......截图的时候是按照屏幕分辨率来的)
    然后就得出了以下解决方案:

    float tempScale = SCREEN_SHOT_WIDTH / Screen.width;
    StartCoroutine(CaptureCamera(captureCamera, new Rect(0, 0, Screen.width * tempScale, Screen.height * tempScale), mPicturePath));
    

    应该都看的懂吧,就是先指定一个分辨率,然后把截图尺寸缩放一下,然后截图,这样就可以流畅的截图了

    4.截图无法截取UGUI的元素

    目前这个问题的解决方案依然不是很完善,不知道后续会不会变好
    目前有两个解决方案:
    1.将UGUI设置为word Space 模式,这样UI元素就是3D场景咯,就可以直接截图了,但是这样的弊端是UI需要自己去让他跟随摄像机(其实解决也很简单,扔到摄像机下面就行了)
    2.重新弄一个3D TEXT,因为截屏的时候一般都是纯的游戏场景加部分特殊UI,所以可以只在截图层加一个特殊的3D文字或者直接扔一张图片也可以,这样就不用改动原来的UI了

    代码

    代码比较拙计,但是好歹能用,先这样吧...... 下班咯.......

    using UnityEngine;
    using System.Collections;
    using System.IO;
    
    public class ScreenShotUtil : MonoBehaviour
    {
    
        private const float SCREEN_SHOT_WIDTH = 400;
    
        private static ScreenShotUtil mInstance;
    
        private static string mPicturePath;
    
        public Camera captureCamera;
    
        void Awake()
        {
            mInstance = this;
    
            // 获取对应平台的可访问路径
            mPicturePath = Application.persistentDataPath + "/screenshot.png";
        }
    
        public static void Shot()
        {
            mInstance.TackCapture();
        }
    
        /// <summary>
        /// 截屏操作
        /// </summary>
        private void TackCapture()
        {
            float tempScale = SCREEN_SHOT_WIDTH / Screen.width;
            StartCoroutine(CaptureCamera(captureCamera, new Rect(0, 0, Screen.width * tempScale, Screen.height * tempScale), mPicturePath));
        }
    
        IEnumerator CaptureCamera(Camera camera, Rect rect, string imgPath)
        {
            yield return new WaitForEndOfFrame();
            // 创建一个RenderTexture对象
            RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 24);
            // 临时设置相关相机的targetTexture为rt, 并手动渲染相关相机
            camera.targetTexture = rt;
            camera.Render();
            yield return new WaitForEndOfFrame();
    
            // 激活这个rt, 并从中中读取像素。
            RenderTexture.active = rt;
            Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
            screenShot.ReadPixels(rect, 0, 0);// 注:这个时候,它是从RenderTexture.active中读取像素
            screenShot.Apply();
            // 重置相关参数,以使用camera继续在屏幕上显示
            camera.targetTexture = null;
            RenderTexture.active = null; // JC: added to avoid errors
            GameObject.Destroy(rt);
            yield return new WaitForEndOfFrame();
    
            // 最后将这些纹理数据,成一个png图片文件
            byte[] bytes = screenShot.EncodeToPNG();
            string filename = imgPath;
            File.WriteAllBytes(filename, bytes);
    
            SDKUtils.ShowToast(filename);
        }
    
        public static string GetPicturePath()
        {
            return mPicturePath;
        }
    
    }
    
    

    总结

    其实没啥总结的,只是想说unity自带的截屏功能太寒掺咯~~~~

  • 相关阅读:
    Flash 终将谢幕:微软将于年底( 2020 年 )停止对 Flash 的支持
    分布式id生成方案总结
    如何设计一个亿级网关(API Gateway)?
    服务之间的调用为啥不直接用 HTTP 而用 RPC?
    Dubbo 总结:关于 Dubbo 的重要知识点
    CAP理论解读
    单点登录(SSO)的设计与实现
    入职微软三个月把老板炒了,七个月自己跑路是一种怎样的体验?
    有关链表的小技巧,我都给你总结好了
    排序算法入门之「选择排序」
  • 原文地址:https://www.cnblogs.com/coldcode/p/5029890.html
Copyright © 2020-2023  润新知