【《Unity着色器和屏幕特效开发秘笈》】学习整理:关于屏幕特效【1】

屏幕特效也被成为后期特效,通过抓取整个屏幕的画面,并对其进行渲染,可以实现诸如Bloom特效、运动模糊、HDR效果、景深效果等。
由于需要对Unity摄像机的画面进行渲染,所以我们在制作屏幕特效时都需要将一个特制的脚本挂在摄像机上,通过这个脚本将渲染纹理传递给着色器。

通用脚本

首先记录一下脚本的基础结构。

[ExecuteInEditMode] //添加此特性后,这个脚本就可以在编辑状态下运行
public class MyTestRenderImageBase : MonoBehaviour
{
    //当前的着色器
    public Shader curShader = null;
    //当前的材质球
    private Material curMaterial = null;
    private Material CurMaterial
    {
        get
        {
            if(curMaterial == null)
            {
                //如果没有材质球,则创建一个使用curShader的材质球
                curMaterial = new Material(curShader);
                curMaterial.hideFlags = HideFlags.HideAndDontSave;
            }
            return curMaterial;
        }
    }

    private void Start()
    {
        //容错处理
        if(!SystemInfo.supportsImageEffects)
        {
            enabled = false;
            return;
        }
        if(!curShader && !curShader.isSupported)
        {
            enabled = false;
        }
    }

    /// <summary>
    /// Unity提供的屏幕特效处理接口
    /// </summary>
    /// <param name="source">源纹理,通常就是当前屏幕的渲染纹理,或者上一步处理后得到的渲染纹理</param>
    /// <param name="destination">目标渲染纹理</param>
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if(curShader)
        {
        //如果着色器存在,就是用着色器渲染当前纹理
            Graphics.Blit(source, destination, CurMaterial);
        }
        else
        {
            //着色器不存在时,就直接将当前纹理覆盖传递给目标纹理
            Graphics.Blit(source, destination);
        }
    }

    private void OnDisable()
    {
        if(curMaterial)
        {
            //由于使用了HideFlags.HideAndDontSave标签,所以必须手动销毁此对象
            DestroyImmediate(curMaterial);
        }
    }
}

通过上面的代码可以看出来,大体结构就是获取一个Shade→获取材质球→使用这个材质球渲染当前的屏幕画面。
Start()中的代码基本都是容错用的。
比如通过使用SystemInfo.supportsImageEffects来检测系统是否支持屏幕特效处理。
通过!curShader && !curShader.isSupported来判断当前Shader是否可用。

Graphics.Blit这个函数负责使用特定的Shader来渲染当前图像。
可能用到的有一下几种:

public static void Blit(Texture source, RenderTexture dest);
public static void Blit(Texture source, RenderTexture dest, Material mat);
public static void Blit(Texture source, Material mat, int pass = -1);

其中pass默认值为-1表示将会依次调用Shader内的所有Pass,否则只会调用指定索引的Pass。

需要注意的是对于一些复杂的屏幕特效,我们可能需要多次调用Graphics.Blit函数来对上一步的输出结果进行下一步处理。

其他的屏幕特效处理脚本也基本都是以此脚本为根基进行修改。

猜你喜欢

转载自blog.csdn.net/EverNess010/article/details/79833626
今日推荐