UnityShader19:渲染纹理(上)之截屏功能实现

一、渲染到 RT

渲染纹理(Render Texture) 就是游戏开发中经常被提到的 RT,渲染到 RT 本质上就是不将渲染的结果直接显示的屏幕上,而是存至一张指定的纹理中

在 Unity 中最简单的操作(三步实现渲染到 RT,无需写代码)

这样这台摄像机的渲染结果就会存入你设置的 RT 中,而不再显示在屏幕上

这个设置转成代码就是:

_renderTexture = new RenderTexture(width, height, 8);
_camera.targetTexture = _renderTexture;

二、FBO 与渲染到 RT 的原理

1):纹理从 CPU 到 GPU:

所有的贴图资源最开始都是存在 CPU 的内存中的,在渲染的过程中它会被送到 GPU 的内存里,在这之后 GPU 才能使用它进行渲染

2):再提 FBO

帧缓冲(FrameBufferObject, FBO)的详细介绍可以参考下面三章:

关于 FBO 本质上就是 GPU 渲染结果的目的地,我们绘制的所有结果:包括颜色、深度等信息都最终存在这个这里

现在的 GPU 当然可以创建多个 FBO,其中有个默认的 FBO 直接连着我们的显示器窗口区域,而其它的 FBO 存在的目的就是允许我们将渲染结果保存在 GPU 的一块存储区域以待之后使用

3):FBO 里面的内容,怎么用?

  1. 通过 ReadPixels() 方法将 FBO 里面的内容拷回 CPU,这可以用来实现经典的截屏操作
  2. 将 FBO 里面的内容拷贝到一张 GPU 上的 Texture 中
  3. 省去拷贝流程,直接将这个 FBO 关联到对应的 Texture,这样就等于在绘制时就直接绘制到这个 Texture 上,这即是 Unity RT 的实现原理

一个很经典的函数是 Graphics.Blit(src, target, mat):其内部使用 mat 材质用 src 做 mainTex,clear 为 black 后渲染到 target 上,mat 留空可以理解为直接拷贝纹理,一般都是使用这种方法渲染到 RT,在做一些屏幕后处理时这个方法几乎是必用到的

三、实现截屏功能

按下 S 键就可以将当前的游戏画面保存到 D 盘的根目录下:

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public class ScreenShot : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.S))
        {
            Debug.Log("Save");
            Save();
        }
    }

    private RenderTexture TargetTexture;
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        TargetTexture = source;
        Graphics.Blit(source, destination);
    }

    private void Save()
    {
        RenderTexture.active = TargetTexture;
        int width = RenderTexture.active.width;
        int height = RenderTexture.active.height;

        //↑ 把当前的fbo设为可读的对象 ↓ 调用ReadPixels操作将其读回内存
        Texture2D png = new Texture2D(width, height, TextureFormat.ARGB32, true);
        png.ReadPixels(new Rect(0, 0, width, height), 0, 0);
        byte[] bytes = png.EncodeToPNG();
        string file = string.Format(@"D:\TestPic.png");
        System.IO.File.WriteAllBytes(file, bytes);
        Debug.Log("Save Down");
    }
}

关于 Unity 内置的 OnRenderImage() 函数:

该脚本必须挂载在有相机组件的游戏对象上,该函数在所有的渲染完成后由 monobehavior 自动调用,其允许我们使用着色器滤波操作来修改最终的图像,第一个参数 source 为输入原图像,第二个参数 desitination 为输出的图象

还需要注意的点:

若要将 RenderTexture 拷贝回 CPU 内存,那么拷贝前后的 Tex 的格式必须匹配,且必须是 RGBA32 这种基本类型,要注意的是很多机器支持 ARRBHALF 或者 ARGBFLOAT 这样的浮点格式来存储其它非颜色信息(例如 uv 坐标),这种不能直接拿来当 256 位颜色信息使用

参考文章:

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/113566766