当前位置: 首页 > article >正文

屏幕后期处理

1、屏幕后期处理效果

屏幕后期处理效果( Screen Post-Processing Effects)是一种在渲染管线的最后阶段应用的视觉效果,允许在场景渲染完成后对最终图像进行各种调整和效果处理,从而增强视觉体验
常见的屏幕后期处理效果有:景深、模糊、色彩调整 等等

2、Unity中 屏幕后期处理效果的 基本实现原理

想要完成屏幕后期处理效果
最关键的问题在于

  • 如何获取 游戏画面渲染完毕后的画面信息
  • 如何为 获取到的画面信息添加自定义效果

只要搞清楚这两点,自然就明白了基本实现原理

(1)如何获取 游戏画面渲染完毕后的画面信息
 在Unity中获取渲染纹理的常用方法有三种:RenderTexture、GrabPass、OnRenderImage
在处理屏幕后期处理效果时会使用OnRenderImage函数来获取 游戏画面渲染完毕后的画面信息

(2)如何为 获取到的画面信息添加自定义效果
主要思路是将获取到的游戏画面作为 自定义Shader的主纹理,通过自定义Shader利用捕获的画面来实现自定义效果

3、捕获画面的关键——OnRenderImage函数

OnRenderImage函数
它是在继承了MonoBehaviour的脚本中能够被自动调用的函数(类似生命周期函数),它会在图像的渲染操作完成后调用
它的固定写法是:

void OnRenderImage(RenderTexture source, RenderTexture destination)
第一个参数:源渲染纹理,当前渲染得到的屏幕图像存储在该参数当中
第二个参数:目标渲染纹理,将经过处理后的图像写入到目标纹理中用于最终的显示

通过该函数我们便可以得到当前渲染的游戏画面,并在该函数中对画面对应的渲染纹理进行处理后用于最终显示

注意:
该函数得到的源纹理默认是在所有的不透明和透明的Pass执行完毕后调用的,基于该源纹理进行修改会对游戏场景中所有游戏对象产生影响,如果你想要在不透明的Pass执行完毕后就调用该函数,只需要在该函数前加上特性 [ImageEffectOpaque] 这样就不会对透明物体产生影响

//加入该特性 就不会对透明物体产生影响
//[ImageEffectOpaque]
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
    1.将源纹理直接复制到目标纹理
    //Graphics.Blit(source, destination);
    //把源纹理 通过 材质球当中的Shader进行效果处理 然后写入到目标纹理中 最终呈现在屏幕上
    Graphics.Blit(source, destination, material);
}

4、实现效果的关键——Graphics.Blit函数

Graphics.Blit函数用于将一个图像从一个纹理复制到另一个纹理,同时可以在这个过程中用着色器对图像进行处理,它有很多重载,主要讲解几个常用的:

(1)将源纹理直接复制到目标纹理

Graphics.Blit(Texture source, RenderTexture dest)

(2)将源纹理复制到目标纹理并应用一个材质

Graphics.Blit(Texture source, RenderTexture dest, Material mat, int pass = -1);

source源纹理会被传递给mat材质中Shader中名为_MainTex的纹理属性用于进行处理
pass参数默认值为 - 1,表示会依次调用Shader内的所有Pass进行处理,否则,只会调用给定索引的Pass

5、屏幕后处理基类

补充:

(1)Shader.isSupported
通过获取Shader对象中的isSupported属性判断Shader在目标平台和硬件上是否能正确运行

(2)[ExecuteInEditMode]特性
用于使脚本在编辑器模式下也能执行

(3)[RequireComponent(typeof(组件名))]特性
指定某个脚本所依赖的组件,它确保当你将脚本附加到游戏对象时,所需的组件也会自动添加到该游戏对象中,如果这些组件已经存在,它们不会被重复添加,因为后处理脚本一般添加到摄像机上,因此我们用于依赖摄像机

(4)材质球中的 HideFlags 枚举
从材质球对象中可以点出 HideFlags 枚举

  • HideFlags.None: 对象是完全可见和可编辑的。这是默认值。
  • HideFlags.HideInHierarchy: 对象在层级视图中被隐藏,但仍然存在于场景中。
  • HideFlags.HideInInspector: 对象在检查器中被隐藏,但仍然存在于层级视图中。
  • HideFlags.DontSaveInEditor: 对象不会被保存到场景中。适用于编辑器模式,不会影响播放模式。
  • HideFlags.NotEditable: 对象在检查器中是只读的,不能被修改。
  • HideFlags.DontSaveInBuild: 对象不会被包含在构建中。
  • HideFlags.DontUnloadUnusedAsset: 对象在资源清理时不会被卸载,即使它没有被引用。
  • HideFlags.DontSave: 对象不会被保存到场景中,不会在构建中保存,也不会在编辑器中保存。这是 DontSaveInEditor | DontSaveInBuild | DontUnloadUnusedAsset 的组合。

    如果想要设置枚举满足多个条件 直接多个枚举 进行位或运算即可 |

为什么要实现屏幕后处理基类

原因一:为了实现屏幕后期处理效果,每次都需要做的事情一定是

  • 实现一个继承子MonoBehaviour的自定义C#脚本
  • 关联对应的材质球或者Shader
  • 实现OnRenderImage函数
  • 在OnRenderImage函数中使用Graphics.Blit函数

那么这些共同点我们完全可以抽象到一个基类中去完成,以后只需要在子类中实现各自的基本逻辑即可

原因二:可以在基类中用代码动态创建材质球,不需要为每个后处理效果都手动创建材质球,只需要在Inspector窗口关联对应使用的Shader即可

原因三:在进行屏幕后处理之前,往往需要检查一系列条件是否满足,比如:
当前平台是否支持当前使用的Unity Shader,我们可以在基类中进行判断,避免每次书写相同逻辑

注意:
在一些老版本中,你可能还会在基类中判断目标平台是否支持屏幕后处理和渲染纹理,一般通过Unity中的SystemInfo类判断,该类可以用于确定底层平台和硬件相关的功能是否被支持
官方说明:https://docs.unity.cn/cn/2022.3/ScriptReference/SystemInfo.html

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class PostEffectBase : MonoBehaviour
{
    // 屏幕后处理效果会使用的Shader
    public Shader shader;
    // 动态创建的材质球
    private Material _material;

    protected Material material {
        get {
            if (shader == null || !shader.isSupported)
                return null;
            else {
                if (_material != null && _material.shader == shader)
                    return _material;

                // 用支持的 Shader 动态创建一个材质球用于渲染
                _material = new Material(shader);
                _material.hideFlags = HideFlags.DontSave;
                return _material;
            }
        }
    }

    protected virtual void OnRenderImage(RenderTexture source, RenderTexture destination) {
        UpdateProperty();

        if (material != null)
            Graphics.Blit(source, destination, material);
        else
            Graphics.Blit(source, destination);
    }

    protected virtual void UpdateProperty() {

    }
}


http://www.kler.cn/a/388988.html

相关文章:

  • 2024 kali操作系统安装Docker步骤
  • 测试实项中的偶必现难测bug--验证码问题
  • 免费HTML模板和CSS样式网站汇总
  • Mysql 8迁移到达梦DM8遇到的报错
  • 单例模式详解:如何优雅地实现线程安全的单例
  • DAY6 线程
  • 深度学习之卷积问题
  • Flutter鸿蒙next 使用 BLoC 模式进行状态管理详解
  • 【Axure视频教程】多选按钮控制元件显示和隐藏
  • 汽车共享管理:SpringBoot技术深度解析
  • 【Spring 框架】初识 Spring
  • 鸿蒙系统:安卓与iOS的强劲对手
  • Python与Excel交互:pandas库安装及基本用法
  • 专业140+总分410+东北大学841考研经验东大电子信息与通信工程通信专业基础真题,大纲,参考书
  • SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记
  • ThingsBoard规则链节点:Clear Alarm节点详解
  • Spark SQL大数据分析快速上手-DataFrame应用体验
  • jmeter常用配置元件介绍总结之用linux服务器压测
  • 如何让ffmpeg运行时从当前目录加载库,而不是从/lib64
  • React的概念以及发展前景如何?
  • 2024-2025第九届华为ICT大赛中国创新赛问题解答
  • 【Python】Pygame实战:实现基础跑酷游戏机(附源码)
  • Redis设计与实现 学习笔记 第十六章 Sentinel
  • 前端实现文件下载常用几种方式
  • 计算机课程管理:Spring Boot实现的工程认证解决方案
  • 中仕公考:2025年各地区公务员招考公告汇总