• Unity 截取3D图像 与 画中画PIP的实现


    1 前言

    在Unity中要得到某些3D游戏对象的截图,是比较容易的,本文来讨论一下。

    实现的核心方案,是新建一个Camera,Camera指向目标对象。Camera有个参数是TargetTexture,叫目标渲染纹理,提取该纹理的像素,生成图片

    来看一下Camera的属性:
    在这里插入图片描述

    一般情况下,摄像机直接渲染到屏幕,即,当 targetTexture 为 null 时,摄像机渲染到屏幕。但如果创建一个 RenderTexture 对象, 在摄像机上将其设置为 targetTexture,则摄像机就会渲染到 该纹理。当渲染到纹理时,摄像机始终渲染到整个纹理中。 这有一种离屏渲染FBO的味道了^^

    再补充一下RenderTexture的知识。RenderTexture即,渲染纹理,是指可对其进行动态渲染的纹理。

    它们可用于实现基于图像的渲染特效、动态阴影、 投影器、反射或监视摄像机。
    渲染纹理的一个典型用法是将其设置为 摄像机的“目标纹理”属性 (Camera.targetTexture),这将使摄像机渲染到纹理, 而不是渲染到屏幕。

    2 具体实现

    背景:有如下一个简单的3D世界,包括一个Cube正方体,一个Plane 绿色平板,一个Plane白色平板。
    目标:把Cube和绿色平板一起截取下来。
    在这里插入图片描述

    2.1 新建离屏渲染Camera

    新建一个Camera,视锥Projection设置为正交投影Orthographic,位置放在3D对象的后方,使其可以照射到目标游戏对象,具体如下:
    在这里插入图片描述
    选中Camera对象,会有个小窗口,如图中的箭头,可以看到Camera所得到的实际视图,方便你的调试位置,大小。

    如果要调整Camera的视锥范围,可以修改参数中的Size

    接下来,就可以写代码,去截图了。

    2.2 代码实现

    具体如下:

    using Assets.Scripts;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Get3DImage : MonoBehaviour
    {
        private RenderTexture shortcutRenderTexture;
        private Camera cutImageCamera;
        // Start is called before the first frame update
        void Start()
        {
            cutImageCamera = GameObject.Find("CutImageCamera").GetComponent<Camera>();
            init();
        }
    
        // Update is called once per frame
        void Update()
        {
            
        }
    
        private void init()
        {
            shortcutRenderTexture = RenderTexture.GetTemporary(600, 600, 16, RenderTextureFormat.Default, RenderTextureReadWrite.Linear);
            shortcutRenderTexture.enableRandomWrite = true;
            cutImageCamera.targetTexture = shortcutRenderTexture;
        }
    
        public void StartCutImage()
        {
            // Create a new Texture2D and read the RenderTexture image into it
            RenderTexture.active = shortcutRenderTexture;
            Texture2D drawTexture2D = new Texture2D(shortcutRenderTexture.width, shortcutRenderTexture.height, TextureFormat.RGB24, false);
            drawTexture2D.ReadPixels(new Rect(0, 0, shortcutRenderTexture.width, shortcutRenderTexture.height), 0, 0);
            drawTexture2D.Apply();
    
            TextureUtils.saveTextureToFile(drawTexture2D, "SaveShortcut");
        }
    
        private void OnDestroy()
        {
            RenderTexture.ReleaseTemporary(shortcutRenderTexture);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    核心代码

    RenderTexture.active = shortcutRenderTexture;

    上面的核心代码,表示设置当前的激活态的RenderTexture为 Camera所指向的RenderTexture(同样游戏场景中可能有多个RenderTexture)。此时可以新建一个Texture2D,调用ReadPixels,即会读取激活态的RenderTexture的内容。

    接下来就简单了,把Texture2D保存即可。代码如下:

    using System.IO;
    using UnityEngine;
    
    namespace Assets.Scripts
    {
        class TextureUtils
        {
            public static Texture2D DeCompress(Texture2D source)
            {
                RenderTexture renderTex = RenderTexture.GetTemporary(
                            source.width,
                            source.height,
                            0,
                            RenderTextureFormat.Default,
                            RenderTextureReadWrite.Linear);
    
                Graphics.Blit(source, renderTex);
                RenderTexture previous = RenderTexture.active;
                RenderTexture.active = renderTex;
                Texture2D readableText = new Texture2D(source.width, source.height);
                readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
                readableText.Apply();
                RenderTexture.active = previous;
                RenderTexture.ReleaseTemporary(renderTex);
                return readableText;
            }
    
    
            public static string saveTextureToFile(Texture2D texture, string fileName)
            {
                if (texture == null)
                {
                    return "";
                }
    
                byte[] bytes = TextureUtils.DeCompress(texture).EncodeToPNG();
                string filename = Application.persistentDataPath + "/" + fileName + ".png";
                Debug.Log("DrawManager::saveTextureToFile = " + filename);
                File.WriteAllBytes(filename, bytes);
                return filename;
            }
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    3 用RenderTexture实现画中画

    本文使用到了RenderTexture,且是代码动态创建的。我们也可以在菜单中创建,甚至还可以做一个画中画PIP的功能,比较有意思,顺着思路,我们来聊一下画中画的实现。

    3.1 建RenderTexture

    在Assets目录下,右键,Create – RenderTexture,新建一个渲染纹理。
    然后,把Size参数设置为和屏幕宽高一样,例如1920x1080.
    在这里插入图片描述

    3.2 建材质

    接着,右键,Create – Material,新建一个材质。Shader选为Unlit/Texture。然后,如下右边箭头,把材质所使用的纹理,选择为上面新建的RenderTexture。
    在这里插入图片描述

    有了材质,就可以用在游戏场景中了!

    3.3 建Image作为PIP窗口

    新建一个2D Image,然后把Image的材质,设置为3.2所建的材质。

    好了,运行起来,效果如下:
    请添加图片描述

    最后,上代码:
    TestGet3DImage

  • 相关阅读:
    Tkinter制作股票数据抓取小程序,有点秀!
    spring boot jwt完整过程
    【JavaEE】计算机是如何工作的
    leetCode-栈类型详解
    使用SystemParametersInfo访问用户界面设置
    Plant Simulation双深位库堆垛库
    mysql数据库之必备知识
    Airtest手机APP自动化操作微信
    对本地存储的有效期的理解
    Oracle主机变量锚定、游标变量
  • 原文地址:https://blog.csdn.net/newchenxf/article/details/126055043