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

一个简单的屏幕效果

屏幕特效通用脚本的基础上,制作一个简单的灰度效果。
首先是使用的挂在摄像机上面的脚本:

[ExecuteInEditMode]
public class MyTestRenderImage : MonoBehaviour
{
    public Shader curShader = null;

    [Range(0f, 1f)]//添加此特性后可在Inspector面板中使用滑动条控制grayScaleAmount
    //控制灰度值
    public float grayScaleAmount = 1.0f;

    private Material curMaterial = null;
    private Material CurMaterial
    {
        get
        {
            if(curMaterial == null)
            {
                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;
        }
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if(curShader)
        {
            //使用grayScaleAmount控制着色器中对应的属性数值
            CurMaterial.SetFloat("_LuminosityAmount", grayScaleAmount);
            Graphics.Blit(source, destination, CurMaterial);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }

    private void Update()
    {        
        //检查并将grayScaleAmount的值限定在0到1之间
        grayScaleAmount = Mathf.Clamp01(grayScaleAmount);
    }

    private void OnDisable()
    {
        if(curMaterial)
        {
            DestroyImmediate(curMaterial);
        }
    }
}

通过和之前基本结构的对比,可以看出此脚本只是多了对于grayScaleAmount这一灰度数值相关的代码。
通过CurMaterial.SetFloat("_LuminosityAmount", grayScaleAmount);可以实现外部对于着色器的控制,从而直接看到屏幕效果的变化。
当然如果为了简便也可以通过继承的方式,将基本结构作为父类,改写其中相应的函数来简化代码,此处为了进行对比,所以还是直接将其直接写了出来。

下面是用到的shader代码:

Shader "RenderImage/MyTestRenderImage" 
{
    Properties 
    {
        _MainTex("Base Tex", 2D) = "white"{}
        _LuminosityAmount("GrayScale Amount", Range(0.0, 1)) = 1.0
    }

    SubShader 
    {
        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            fixed _LuminosityAmount;

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

            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);

                float luminosity = 0.299 * renderTex.r + 0.587 * renderTex.g + 0.114 * renderTex.b;
                fixed4 finalColor = lerp(renderTex, luminosity, _LuminosityAmount);

                return finalColor;
            }

            ENDCG
        }
    }

}   //end shader

在此Shader中,使用了Unity内置的appdata_img结构体作为顶点着色器的输入。
此结构体位于UnityCG.cginc中,只包含图像处理时必须的定点坐标和纹理坐标等变量。

struct appdata_img
{
    float4 vertex : POSITION;
    half2 texcoord : TEXCOORD0;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

vert顶点着色器中,仅进行了必要的顶点变换和uv坐标的赋值。
frag片元着色器中,通过lerp差值返回最终的屏幕颜色。
其中需要注意的是以下代码:

float luminosity = 0.299 * renderTex.r + 0.587 * renderTex.g + 0.114 * renderTex.b;

此代码中的(0.299, 0.587, 0.114)并不是随意写上去的,经过查询资料显示,这个是一个经典的色彩心理学公式。

Gray = R*0.299 + G*0.587 + B*0.114

目的是将彩色转化为灰度,是国际公认的一个公式。其中Gray是最终的灰度值,R代表红色通道、G代表绿色通道、B代表蓝色通道。
知道了这个公式,片元着色器中的代码意义也就可以很轻松的理解了。

//根据uv获取相应像素的颜色值
fixed4 renderTex = tex2D(_MainTex, i.uv);
//按照公式,将颜色值转化为对应的灰度值    
float luminosity = 0.299 * renderTex.r + 0.587 * renderTex.g + 0.114 * renderTex.b;
//通过差值,返回经过_LuminosityAmount控制的最终颜色
fixed4 finalColor = lerp(renderTex, luminosity, _LuminosityAmount);

以下是此Shader的效果

grayScaleAmount = 0

这里写图片描述

grayScaleAmount = 0.25

这里写图片描述

grayScaleAmount = 0.5

这里写图片描述

grayScaleAmount = 0.75

这里写图片描述

grayScaleAmount = 1.0

这里写图片描述

grayScaleAmount = 0时,最终展示的是正常的彩色效果图像。
grayScaleAmount = 1时,最终展示的是完全的灰度效果图像。

由于此Shader是书中学习使用的,所以其中仅有达到效果所需的必要代码,但是实际项目过程中需要对Shader进行优化后才能使用。

猜你喜欢

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