【Unity Shader入门精要学习】高级(一)

2019-11-04  本文已影响0人  小王子称号发放NPC

屏幕后处理效果

屏幕后处理效果(screen post-processing effects),是游戏中实现屏幕特效的常见方法。屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,在对这个图像进行一系列操作,实现各种屏幕特效,如景深(Depth of Field),运动模糊(Motion Blur)。

void OnRenderImage(RenderTexture src, RenderTexture dest)

因此,想要实现屏幕后处理的基础在于得到渲染后的屏幕图像,Unity提供了方便的接口——OnRenderImage(只在摄像机脚本中生效),在OnRenderImage函数中,经常使用Graphics.Blit函数来完成对渲染纹理的处理:

public static void Blit(Texture source, RenderTexture dest);
public static void Blit(Texture source, RenderTexture dest, Material mat, int pass = -1);
public static void Blit(Texture source, Material mat, int pass = -1);
public static void Blit(Texture source, RenderTexture dest, Vector2 scale, Vector2 offset);
public static void Blit(Texture source, RenderTexture dest, int sourceDepthSlice, int destDepthSlice);
public static void Blit(Texture source, Material mat, int pass, int destDepthSlice);
public static void Blit(Texture source, RenderTexture dest, Vector2 scale, Vector2 offset, int sourceDepthSlice, int destDepthSlice);

在默认情况下,OnRenderImage函数会在所有不透明和透明的Pass执行完毕后被调用,以便对场景中所有游戏对象都产生影响。但有时,我们希望在不透明的Pass(即渲染队列小于等于2500的Pass,内置的Background、Geometry和AlphaTest渲染队列均在此范围内)执行完毕后立即调用OnRenderImage,从而不对透明物体产生任何影响。此时可以在OnRenderImage函数前添加ImageEffectOpaque属性来实现这样的目的:

    [ImageEffectOpaque]
    private void OnRenderImage(RenderTexture src, RenderTexture dest)

调整屏幕的亮度,饱和度,对比度

调整前
调整后

摄像机脚本

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

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class PostEffectsBase : MonoBehaviour
{
    protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
    {
        if (shader == null || !shader.isSupported)
        {
            return null;
        }

        if (shader.isSupported && material && material.shader == shader)
        {
            return material;
        }
        
        material = new Material(shader);
        material.hideFlags = HideFlags.DontSave;
        if (material)
        {
            return material;
        }
        else
        {
            return null;
        }
    }
}

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

public class BrightnessSaturationContrast : PostEffectsBase
{
    public Shader briSatConShader;

    protected Material briSatConMaterial;

    public Material material
    {
        get
        {
            briSatConMaterial = CheckShaderAndCreateMaterial(briSatConShader, briSatConMaterial);
            return briSatConMaterial;
        }
    }

    [Range(0.0f, 3.0f)] public float brightness = 1.0f;

    [Range(0.0f, 3.0f)] public float saturation = 1.0f;

    [Range(0.0f, 3.0f)] public float contrast = 1.0f;
    
    [ImageEffectOpaque]
    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
       // Debug.Log("BrightnessSaturationContrast OnRenderImage");
        if (material != null)
        {
            material.SetFloat("_Brightness",brightness);
            material.SetFloat("Saturation",saturation);
            material.SetFloat("_Contrast",contrast);
            
            Graphics.Blit(src,dest,material);
        }
        else
        {
            Graphics.Blit(src,dest);
        }
    }
}

对应Shader

Shader "Unlit/BrightnessSaturationConstrat"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Brightness("Brightness",float)=1
        _Saturation("Saturation",float)=1
        _Contrast("Contrast",float)=1
    }
    SubShader
    {
      //下面三项是屏幕后处理标配
        ZTest Always 
        Cull Off 
        ZWrite Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct v2f
            {
                float4 pos: SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Brightness;
            float _Saturation;
            float _Contrast;

            v2f vert (appdata_img v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 renderTex = tex2D(_MainTex, i.uv);

                fixed3 finalCol = renderTex.rgb * _Brightness;

                fixed luminance = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
                fixed3 luminanceColor = fixed3(luminance, luminance, luminance);
                finalCol = lerp(luminanceColor,finalCol,_Saturation);

                fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
                finalCol = lerp(avgColor, finalCol, _Contrast);
                
                return fixed4(finalCol, renderTex.a);  
            }
            ENDCG
        }
    }
}

上一篇下一篇

猜你喜欢

热点阅读