56.屏幕后期处理效果基本实现原理

56.屏幕后期处理效果-基本实现原理


56.1 知识点

什么是屏幕后期处理效果

屏幕后期处理效果(Screen Post-Processing Effects)是一种在渲染管线的最后阶段应用的视觉效果。它允许你在场景渲染完成后对最终图像进行各种调整和效果处理,从而增强视觉体验。

常见的屏幕后期处理效果包括景深、模糊、色彩调整等。

说人话:
屏幕后期处理效果就是在游戏画面渲染完毕后,通过获取到该画面信息进行额外的效果处理。

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

屏幕后期处理效果的实现分为两大核心问题:

  1. 如何获取游戏画面渲染完毕后的画面信息
    Unity中有三种常用方法来获取渲染纹理:

    • RenderTexture
    • GrabPass
    • OnRenderImage

    在屏幕后期处理中,主要使用 OnRenderImage 函数获取渲染后的画面信息。

  2. 如何为获取到的画面信息添加自定义效果
    主要思路是将获取到的游戏画面作为自定义Shader的主纹理,通过Shader实现自定义的视觉效果。

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

OnRenderImage 是 Unity 提供的一个在继承自 MonoBehaviour 的脚本中被自动调用的函数(类似生命周期函数)。它会在图像的渲染操作完成后调用,主要作用是捕获当前渲染的画面并对其进行处理。

函数定义

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

通过该函数,可以获取当前渲染的游戏画面,并对对应的渲染纹理进行处理,最终显示在屏幕上。

注意事项

  • 该函数默认在所有的不透明和透明的 Pass 执行完毕后调用,基于源纹理的修改会对游戏场景中的所有对象产生影响。
  • 如果希望只在不透明的 Pass 执行完毕后调用该函数,可在函数前添加特性 [ImageEffectOpaque],这样就不会对透明物体产生影响。

在 MonoBehaviour 脚本中实现 OnRenderImage 函数

[ImageEffectOpaque] // 加入该特性,避免影响透明物体
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
    // 目前未做任何处理
}

挂载到摄像机上,发现Game窗口黑屏,是因为我们没有在函数中做任何处理,函数中若未对 destination 做处理,画面将显示为黑屏。

实现效果的关键——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 属性。
    • mat: 材质,包含处理效果的 Shader。
    • pass: 默认值为 -1,表示依次调用 Shader 内的所有 Pass;否则,仅调用指定索引的 Pass。

使用示例

  1. 直接复制源纹理到目标纹理

    [ImageEffectOpaque]
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        // 将源纹理直接复制到目标纹理,显示正常画面
        Graphics.Blit(source, destination);
    }
    

  2. 使用材质处理源纹理并复制到目标纹理

    [ImageEffectOpaque]
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        // 将源纹理通过材质中的 Shader 进行效果处理后写入目标纹理
        Graphics.Blit(source, destination, material);
    }
    

    通过设置 material 的 Shader,可以实现各种自定义的屏幕后期效果。

总结

屏幕后期处理效果的基本实现原理是利用 OnRenderImage 函数Graphics.Blit 函数,捕获当前屏幕画面并通过 Shader 对该纹理进行自定义处理,最终呈现特殊的视觉效果。


56.2 知识点代码

Lesson56_屏幕后期处理效果_基本实现原理.cs

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

public class Lesson56_屏幕后期处理效果_基本实现原理 : MonoBehaviour
{
    public Material material;

    void Start()
    {
        #region 知识点一 什么是屏幕后期处理效果

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

        //说人话:
        //屏幕后期处理效果就是当游戏画面渲染完毕后
        //通过获取到该画面信息进行额外的效果处理

        #endregion

        #region 知识点二 Unity中 屏幕后期处理效果的 基本实现原理

        //从知识点一中我们可以知道
        //想要完成屏幕后期处理效果
        //最关键的问题在于
        //1.如何获取 游戏画面渲染完毕后的画面信息
        //2.如何为 获取到的画面信息添加自定义效果
        //只要搞清楚这两点,自然就明白了基本实现原理

        //1.如何获取 游戏画面渲染完毕后的画面信息
        //  我们之前在学习渲染纹理时学习过
        //  在Unity中获取渲染纹理的常用方法有三种
        //  RenderTexture、GrabPass、OnRenderImage
        //  我们在处理屏幕后期处理效果时会使用
        //  OnRenderImage函数来获取 游戏画面渲染完毕后的画面信息

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

        #endregion

        #region 知识点三 捕获画面的关键——OnRenderImage函数

        //OnRenderImage函数
        //它是在继承了MonoBehaviour的脚本中能够被自动调用的函数(类似生命周期函数)
        //它会在图像的渲染操作完成后调用
        //它的固定写法是:
        //void OnRenderImage(RenderTexture source, RenderTexture destination)
        //第一个参数:源渲染纹理,当前渲染得到的屏幕图像存储在该参数当中
        //第二个参数:目标渲染纹理,将经过处理后的图像写入到目标纹理中用于最终的显示

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

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

        #endregion

        #region 知识点四 实现效果的关键——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的纹理属性用于进行处理(就算没有_MainTex也可能起作用)
        //  pass参数默认值为-1,表示会依次调用Shader内的所有Pass进行处理,否则,只会调用给定索引的Pass

        #endregion

        #region 总结

        //屏幕后期处理效果的基本实现原理
        //就是利用 OnRenderImage函数 和 Graphics.Blit函数
        //来获取当前屏幕画面并利用Shader对该纹理进行自定义处理

        #endregion
    }

    //加入该特性 就不会对透明物体产生影响
    //[ImageEffectOpaque]
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        // //1.将源纹理直接复制到目标纹理 这样可以让画面正常显示
        // Graphics.Blit(source, destination);
        
        //2.将源纹理复制到目标纹理并应用一个材质
        //把源纹理 通过 材质球当中的Shader进行效果处理 然后写入到目标纹理中 最终呈现在屏幕上
        //  source源纹理会被传递给mat材质中Shader中名为_MainTex的纹理属性用于进行处理
        //  pass参数默认值为-1,表示会依次调用Shader内的所有Pass进行处理,否则,只会调用给定索引的Pass
        Graphics.Blit(source, destination, material);
    }
}

// 知识点代码块

// 知识点代码块


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏