简介

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

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自带的截屏功能太寒掺咯~~~~

Unity通过指定摄像机截屏的更多相关文章

  1. 纯C#实现屏幕指定区域截屏

    以前在别的地方见过一个通过调用系统API实现屏幕截图的例子,从内心来说我不太喜欢在C#代码中出现这种情况,现在什么都讲“和谐”,我觉得这种做法就是破坏了我们的“和谐”代码,呵呵,开玩笑,有的时候,不通 ...

  2. C#实现屏幕指定区域截屏

    //string Opath = @"C:/Picture";            //if (Opath.Substring(Opath.Length - 1, 1) != @ ...

  3. unity中编辑器直接截屏代码

    using UnityEngine; using System.Collections; using System.Windows.Forms; public class screenshots : ...

  4. javascript实现当前页面截屏

    javascript实现当前页面截屏 一.前言 有客户要求能对用户当前页面进行指定区域截屏,类似qq截屏的实现效果.比如用户在处理工作的时候,将当前页面录入后的一些信息进行截图下载保存.但又不能安装任 ...

  5. unity之截屏功能

    1.全屏截图 方法一:在unity的API中,unity给我们提供了一个现成的API  :  Application.CaptureScreenshot(imagename). 但是这个API虽然简单 ...

  6. 关于Unity中GrabPass截屏的使用和Shader的组织优化

    GrabPass截屏 可以用来截屏,截屏后把纹理传给下一个通道使用. 1:使用抓屏通道, GrabPass {} 或 GrabPass { “ 纹理名称”}; 使用GrabPass {}后,可以用_G ...

  7. Unity三种截屏方法(非自带API)

    者利用了三种表现形式: 1,选择截图路径的方法 2,直接截取截屏的方法 3,截取鼠标圈选区域. 上代码,: 第一种是调用.net的类库,需要引用System.Windows.Forms.dll,在As ...

  8. unity 截屏总结

    转载与https://www.cnblogs.com/MissLi/p/8005342.html 1.针对指定的相机进行截屏 此中方式要添加yield return waitfortheEndofFr ...

  9. 一个类实现Java截屏并保存到指定文件夹

    不知小伙伴们有没有遇到过使用java来截屏的需求,截屏后保存到指定的目录,在桌面上没有任何体现,完全不知道已经被截屏了.至于截屏后怎么做,可能有的老铁只是好奇想知道某人在干啥?也有的老铁可能想进行文字 ...

随机推荐

  1. Java Arrays.sort相关用法与重载

    Java Arrays.sort() Java中的数组排序函数, 头文件 import java.util.Arrays; 相关API Arrays.sort(arys[]) Arrays.sort( ...

  2. PAT 1131 Subway Map

    In the big cities, the subway systems always look so complex to the visitors. To give you some sense ...

  3. HDU 4598 Difference

    Difference Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total ...

  4. java数组知识总结(一)//按类

    在线api  目录: 零/数组(基本元素) 1.  声明一个数组 2.  创建一个数组 3.  数组名.length 4.  数组的引用 一/java.lang.reflect.Array     / ...

  5. lombok中的@ToString注解作用

    Lombok是一个很好的工具,节省了很多重写方法,而@ToString就是节省了ToString方法,lombok中@ToString就是节省了我们在模型中的冗余代码下面就来举个例子 import j ...

  6. Ubuntu 16.04安装Synaptic Package Manager图形化APT管理工具

    安装: sudo apt-get install synaptic 启动:

  7. 察看linux 发行版

    好像没有太通用的方法. 看一下/etc/redhat-release.  redhat 系列(包括centos) 会有如下内容 [root@localhost ~]# cat /etc/redhat- ...

  8. spring boot日期转换

    spring boot 作为微服务简易架构.拥有其自身的特点.快速搭建架构 简单 快捷.这里我只是简单的介绍下我遇到的其中的  两个问题.第一前台页面传递的时间类型 无法自动映射到Java的 Date ...

  9. [C++]_[获取Utf8字符串的字符个数和子字符串]

    场景: 1.有时候须要统计utf8字符串的个数,单纯统计字节个数是不行的. 2.有时候也须要获取从某个位置開始的n个连续字符用于显示或计算. static int GetUtf8LetterNumbe ...

  10. 性能测试实战-XYB项目-内网访问

    使用内网服务器,linux host绑定域名,相当于ip地址+域名的host绑定,只不过这里的ip是yc-sparks.schoolis.cn