视觉效果

《Shader 入门精要》之后处理

2020-12-13  本文已影响0人  烂醉花间dlitf

后处理就是在相机在最终渲染之前再对这个图片做一个整体处理。主要用到 OnRenderImage 函数和 Graphics.Blit

颜色矫正

明度调节 饱和调节 对比调节

代码比较简单,书中将整个屏幕后处理都提出了一个父类出来,当然也可以直接像我这样。

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

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class ColorCorrectCtl : MonoBehaviour {
    public Shader colorCorrectShader;
    private Material material;
    
    [Range(0,5)]
    public float brightness = 1;

    [Range(0, 5)]
    public float saturation = 1;

    [Range(0, 5)]
    public float contrast = 1;


    // Use this for initialization
    private void Start () {
        Init();
    }

    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        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);
        }
    }


        /// <summary>
        /// 检查 Shader 是否可用并且创造材质球
        /// </summary>
        /// <returns></returns>
        private bool Init()
    {
        if (colorCorrectShader.isSupported)
        {
            material = new Material(colorCorrectShader);
            return true;
        }
        else
        {
            Debug.LogError("Shader 不支持", gameObject);
            return false;
        }
    }
}

Shader "ZhangQr/ColorCorrect"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        // 因为那几个参数不用在 Shader 的界面控制,所以不需要写
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            ZWrite Off // 不然如果不透明的物体渲染在后处理之后,那么就会出错
            Cull Off // 其实不关也可以吧
            ZTest Always // 这句不写的话,不能在编辑器模式下运行,即便在脚本中写了 [ExecuteInEditMode]
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"



            
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Brightness; // 亮度
            float _Saturation; // 饱和度
            float _Contrast; // 对比色
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);

                // 亮度
                fixed3 retCol = col.rgb * _Brightness;

                // 对比度 
                float luminance = 0.2125f * col.r + 0.7154f * col.g + 0.0721f * col.b;
                fixed3 saturation = fixed3(luminance,luminance,luminance);
                retCol = lerp(saturation,retCol,_Saturation);
                
                // 对比度
                fixed3 contrast = fixed3(0.5,0.5,0.5);
                retCol = lerp(contrast,retCol,_Contrast);
                
                UNITY_APPLY_FOG(i.fogCoord, col);
                return fixed4(retCol,col.a);
            }
            ENDCG
        }
    }
}

Shader 里面的 lerp 跟 C# 里面的还是有点不一样,后者 t 只能从 0-1,但前者应该是 0-正无穷吧。所以其实对于饱和和对比来说,都是只需要知道一个下限然后使用插值就能自动弥补一些东西,做成非常好看的效果,饱和的下限是一张黑白图:

黑白图
它是根据人眼对于颜色的敏感度不同计算出来的,也就是 float luminance = 0.2125f * col.r + 0.7154f * col.g + 0.0721f * col.b
对比的下限是灰色,也就是 0.5r,0.5g,0.5b。如下图:
灰色
总结一下就是插值真是个好东西。
上一篇下一篇

猜你喜欢

热点阅读