unity如何让某个物体永远显示在最前面(3D层)并保存成型后的图像(不显示UI层)(多个摄像头的用法、三种截图)

前言
公司经营一款绘图相关的软件,近期有客户反映,尺寸标尺会被画图数据挡住。现在就来解决一下这个问题。
遮挡分为两种情况,一种是UI界面下的组件遮挡(即Canvas画布下),另一种是3D层靠近摄像头的物体遮挡后方的物体。
UI层的很好解决,越下层的物体越是最后渲染,只需要将显示在前方的物体放在最下面即可。
重点介绍3D层如何将物体显示在最前方。

首先:我们要知道3D层的渲染顺序,离摄像机距离越近,越是显示在最前方。即和人眼观察物体一样,假设有一杯子和一张桌子,杯子放在桌子前,我们会先看到杯子,然后在看到桌子。如果桌子在前,杯子在后,那么我们只能看到桌子。所以最简单的第一种方法:将想显示的物体放到最前方,即调整到Camera的距离(通常是Z轴),但是这会引发一系列的问题,例如:靠的越近,物体显示越大,在整个场景中格格不入,而且因为改了Z轴,空间位置也发生了改变,就显示在了其他的地方。所以放弃这一种方法,采用第二种:多个Camera渲染。

先来看一下我们需要用到的Camera参数。
在这里插入图片描述
Skybox(天空盒):默认项,在屏幕空白处显示当前摄像机的天空盒
SolidColor:屏幕空白处填充背景色
Depth only:仅深度,当前渲染的物体永远显示在最前方,会遮挡同位置的其他像素,我们需要用到的模式(显示在最前方的物体)
Don’t Clera:不清除,该模式不清楚任何颜色和深度缓存,即每一帧渲染结果叠加在上一帧之上。
在这里插入图片描述
Culling Mask:需要渲染的层级

在这里插入图片描述
渲染深度:值越小,越先渲染。

看到这里,想必你已经知道如何实现了。先用一个主摄像头渲染除了你想显示在最前端的所有物体(通过图层筛选)。然后单独的用一个摄像头,Clear Flags模式为Depth only,CullingMask 为你想渲染的那个图层(游戏物体需要指定为这个图层),depth深度值为最大,即可实现效果。
效果如下:
在这里插入图片描述
在这里插入图片描述
虽然球在Cube后,但是在Game视角下看还是球在前,Cube在后。

现在解决了物体被遮挡问题,但是公司软件还有分享图片的功能,如何将成像后的图片保存下来则成了问题。因为是绘图相关软件,所以不能显示UI层,只需要保留用户绘的图片,于是又在网上搜索了不少unity截屏相关方法。

第一种
调用unity自带的ScreenCapture类,里面有一个保存当前全屏图像的方法,但是无法局部截图,也无法筛选UI层,不满足我们的要求,PASS。

    //Unity自带的截屏功能,保存当前画面,无法进行筛选
    public void CaptureFunc1(string filePath)
    {
        ScreenCapture.CaptureScreenshot(filePath);
        Debug.Log("文件路径保存在" + filePath);
    }

第二种
使用Texture2D读取屏幕像素,画了一张图片方便理解,先定义一个Rect,定义要截取的范围,从左下角开始,设置好要偏移的X、Y轴的量,然后是设定宽高截取。画了一张图方便大家理解。另外,这个需要用协程,否则会报错ReadPixels was called to read pixels from system frame buffer, while not inside drawing frame。具体原因可以参考截屏报错。此处不过多赘述。

       public IEnumerator CaptureFunc2(string filePath)
    {
        yield return new WaitForEndOfFrame();
        //起始的X坐标,Y坐标,宽,高
        var rect = new Rect(Screen.width / 4, Screen.height / 4, Screen.width/2, Screen.height/2);
        Texture2D tex = new Texture2D((int)rect.width, (int)rect.height);
        //读取像素、后面两个参数分别是X轴的偏移量,Y轴偏移量、暂且不知道用处
        tex.ReadPixels(rect,0,0);
        //保存数据
        tex.Apply();
        //将数据转换成PNG数据
        byte[] bytes = tex.EncodeToPNG();
        //将数据写成文件
        File.WriteAllBytes(filePath,bytes);
        Debug.Log("Texture2D截图文件路径保存在" + filePath);
        //刷新unity目录
        RefreshResource();
    }

在这里插入图片描述
第三种:获取摄像机屏幕截图
这种方法是额外设置一个摄像机,对准想要截图的区域。
代码如下:

public void CameraCapture(string filePath)
    {
        
        var camera = mainCamera;  //设置截图相机
        var rect = new Rect(0, 0, Screen.width, Screen.height);
        RenderTexture renderTexture = new RenderTexture((int)rect.width, (int)rect.height,32);     //最后一个参数不要设置为0或者-1,会导致部分物体无法渲染
        camera.targetTexture = renderTexture;  //设置相机的renderTexture
        camera.Render();        //手机开启相机的渲染
        RenderTexture.active = renderTexture;        //当前活动的渲染纹理
        Texture2D tex = new Texture2D((int)rect.width, (int)rect.height);
        tex.ReadPixels(rect, 0, 0);
        tex.Apply();
        RenderTexture.active = null;        //重置当前活动的渲染纹理
        camera.targetTexture = null;        //重置相机的targetTexture


        //设置第二个截图相机
        camera = extraCamera;
        camera.targetTexture = renderTexture;
        camera.Render();
        RenderTexture.active = renderTexture;
        tex.ReadPixels(rect, 0, 0);
        tex.Apply();
        //重置当前活动的渲染纹理
        camera.targetTexture = null;
        camera = null;
        RenderTexture.active = null;
        //删除RenderTexture对象
        Destroy(renderTexture);
        //写成图片文件
        byte[] bytes = tex.EncodeToPNG();
        File.WriteAllBytes(filePath, bytes);
        Debug.Log("Texture2D截图文件路径保存在" + filePath);


        //刷新unity目录
        RefreshResource();
        //回收垃圾
        Resources.UnloadUnusedAssets();
        GC.Collect();      
    }

使用摄像机截图的几个关键点:
1、如果需要将Z轴靠后的物体显示,但是前面有物体怎么办?
答:使用多摄像机,分别获取图像,然后赋予同一个Texture2D对象,代码在案例中有,注意点,RenderTexture第三个参数不能设置为0或者-1,否则会导致部分物体无法渲染(暂不知原理,百度相关参数也没有说明)
2、为什么我多摄像机成像后图片是倒过来的?
修改Camer相关参数
在这里插入图片描述
这几个勾项全部取消,可能会导致图片旋转,单摄像机截图没问题,多摄像机截图后合并可能会出现旋转,(暂不知原理,百度相关参数没有详细的相关说明,以后有空再琢磨)。
案例Demo
PS:这里是U3D程序员一只,日常分享工作中遇到的问题和学习笔记。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值