Fork me on GitHub

Unity3D截屏/获取物体快照

原创文章,未经允许,请勿转载

void OnClick ()
{
    StartCoroutine(CaptureScreen());
}

IEnumerator CaptureScreen()
{
    yield return new WaitForEndOfFrame();

    Texture2D t = new Texture2D(Screen.width, Screen.height);
    //截取的区域,使用像素空间坐标 (0,0)是屏幕左下角
    t.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0, false);
    t.Apply();
    //把纹理数据转换为PNG格式
    byte[] bytes = t.EncodeToPNG();
    //保存
    System.IO.File.WriteAllBytes(Application.dataPath + "/" + Time.time + ".png", bytes);
}

主要用到了Texture2D.ReadPixels这个API,看一下来自ceeger的API说明

Texture2D.ReadPixels 读取像素 function ReadPixels (source : Rect, destX : int, destY : int, recalculateMipMaps : bool = true) : void

Read screen pixels into the saved texture data.

读取屏幕像素信息并存储为纹理数据

This will copy a rectangular pixel area from the currently active RenderTexture or the view (specified by /source/) into the position defined by destX and destY. Both coordinates use pixel space - (0,0) is lower left.

这将从当前处于激活状态的 RenderTexture 或视图(由/source/指定)复制一个由destX和destY指定的矩形像素区域。这两个坐标使用像素空间坐标 (0,0)是屏幕左下角。

If recalculateMipMaps is set to true, the mip maps of the texture will also be updated. If recalculateMipMaps is set to false, you must call Apply to recalculate them.

如果 recalculateMipMaps 设置为真,这个贴图的mipmaps就会更新

如果 recalculateMipMaps设置为假,你需要调用Apply重新计算它们

This function works only on ARGB32 and RGB24 texture formats. The texture also has to have Is Readable flag set in the import settings.

这个函数只工作在格式为ARGB32 和 RGB24纹理上,另外这个纹理的导入设置需要设置为 Is Readable(可读)

还有一个API更方便,但只能存到文件:

    Application.CaptureScreenshot(Application.dataPath + "/snap.png");

那么怎么截取某个3D物体快照呢?下面的代码可以静默截取物体快照,物体可以放在任意位置,不影响屏幕显示。和之前那个截屏不同,这次使用了RenderTexture。其中难点在于,要把相机放到合适的位置才能观察到物体的全貌,具体可以看代码注释。 另外有个技巧,如果不想要背景和其他物体,只要该物体的截图,可以在调用前把物体放置到一个非常远的位置(比如世界坐标y=-1000),调用完后再恢复位置。

    /// <summary>
    /// 保存物体快照到PNG文件
    /// </summary>
    /// <author>yoyo(//yoyo.play175.com)</author>
    /// <param name="targetObject">需要快照的物体</param>
    /// <param name="filePath">文件路径</param>
    /// <param name="imageSize">照片像素大小(正方形照片)</param>
    public static void SnapshotToFile(GameObject targetObject,string filePath,int imageSize = 256)
    {
        Camera cam = Camera.main;

        //记录相机位置
        Vector3 opos = cam.transform.position;
        Vector3 oscale = cam.transform.localScale;
        Quaternion orot = cam.transform.localRotation;

        //计算物体包围盒
        Renderer[] renderers = targetObject.GetComponentsInChildren<Renderer>();
        Vector3 min = targetObject.transform.position, max = targetObject.transform.position;
        for (int i = 0; i < renderers.Length; i++)
        {
            min = Vector3.Min(renderers[i].bounds.min, min);
            max = Vector3.Max(renderers[i].bounds.max, max);
        }

        //把相机放到合适位置
        Vector3 center = new Vector3((max.x + min.x) / 2, (max.y + min.y) / 2, (max.z + min.z) / 2);//中心点
        Vector3 step = (max - center).normalized;//相对于中心点的单位向量

        //先放到中心点的前右上角
        cam.transform.position = center + step;
        //拉到合适距离
        cam.transform.position = cam.transform.position + step * (max - min).magnitude * 50 / cam.fieldOfView;
        //旋转方向以便看到目标
        cam.transform.LookAt(center);

        RenderTexture rt = new RenderTexture(imageSize, imageSize, 24);
        cam.targetTexture = rt;
        cam.Render();

        RenderTexture.active = rt;//关键点,有点类似make current 的意思

        Texture2D t = new Texture2D(imageSize, imageSize, TextureFormat.RGB24, false);//false代表不需要使用mipmaps
        t.ReadPixels(new Rect(0, 0, imageSize, imageSize), 0, 0);

        RenderTexture.active = null;//置空,以免出错
        GameObject.Destroy(rt);

        //恢复相机位置
        cam.targetTexture = null;
        cam.transform.position = opos;
        cam.transform.localScale = oscale;
        cam.transform.localRotation = orot;

        //转为png数据
        byte[] b = t.EncodeToPNG();
        GameObject.Destroy(t);

        //保存文件
        System.IO.File.WriteAllBytes(filePath, b); 
    }

    //调用举例:SnapshotToFile(gameobj, Application.dataPath + "/snap.png");

来源:悠游悠游,2016-10-11,原文地址:https://yymmss.com/p/unity-captrue-screen.html