C for Graphic:屏幕特效原理及应用(一)

     刚好最近独立游戏中写了一个简单的屏幕后期特效,所以开一篇聊聊所谓的引擎中屏幕后期特效处理。

     一般这个词美术用的比较多,什么影视CG视频后期特效、后期处理啊。原理上来说就是在视频成品的基础上进行帧图像的纹理处理,比如一帧视频纹理上叠加一个特效图片、或者做人物抠图、或者做绿布替换等。

     那么在我们的三维引擎中,屏幕特效意味着什么呢?其实就是eyeCamera渲染到的场景最后提交颜色缓冲区的那一帧图像,然后我们对那一帧图像进行着色器层面的再操作。三维场景经过建模/世界/视口/裁剪/标准设备等空间,最后经过视图/深度变换到最终的画面,而我们开发就将最终的画面进行再处理,得到最最终的画面再提交显示硬件。

     unity因为其良好的构架设计,直接提供完善的接口供我们开发进行屏幕特效制作,c#函数如下:

     

     函数明确的意义就是提供给我们开发source(源渲染画面)进行shader层面的操作后绑定到destination(目标渲染图像),最后提交渲染。

     同时unity也直接提供给我们创建ImageEffectShader的示例shader文件。

     接下来就是具体操作过程了,代码分为c#以及shader,c#代码主要负责接口实现,也就是获取源渲染画面,shader则将源画面当作_MainTex(主纹理)进行操作,如下:

      

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

public class CameraImageEffect : MonoBehaviour {

    private Material mMat;

    [SerializeField]public float _Weight = 1.0f;

    private void Awake()
    {
        mMat = new Material(Shader.Find("Hidden/ImageColorEffectShader"));
    }

    void Start () {
		
	}

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        mMat.SetTexture("_MainTex", source);
        mMat.SetFloat("_Weight", _Weight);
        Graphics.Blit(source, destination, mMat);
    }
}

    这个c#脚本绑定在mainCamera上,这样函数才能起作用。

    接着是一个简单的变换亮度的Shader,如下:

   

Shader "Hidden/ImageColorEffectShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_Weight("Weight",Range(0,2.0)) = 1.0
	}
	SubShader
	{
		//因为是屏幕特效,所以这些都关闭掉
		Cull Off ZWrite Off ZTest Always

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

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

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

			sampler2D _MainTex;
			float _Weight;

			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				//只进行最简单的颜色值操作
				col *= _Weight;
				return col;
			}
			ENDCG
		}
	}
}

     两份简单的代码描叙了屏幕后期特效操作流程,效果也单调,就改变整体亮度而已,如下:

  

  接下来做一个影视制作常用的绿布处理效果,如下:

  1.首先创建一个绿布背景场景。

      

  2.接下来编写c#和shader代码,c#代码控制场景源渲染图像,和要替换的背景图纹理,shader则根据源图像的片段颜色值进行重采样替换。

     

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

public class CamereGreenEffect : MonoBehaviour {

    public Texture2D mSubTex;
    private Material mMat;


    private void Awake()
    {
        mMat = new Material(Shader.Find("Hidden/ImageGreenEffectShader"));
        mMat.SetTexture("_SubTex", mSubTex);
    }

    void Start()
    {

    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        mMat.SetTexture("_MainTex", source);
        Graphics.Blit(source, destination, mMat);
    }

}


Shader "Hidden/ImageGreenEffectShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_SubTex("SubTex", 2D) = "white" {}
	}
	SubShader
	{
		// No culling or depth
		Cull Off ZWrite Off ZTest Always

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

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

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

			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}
			
			sampler2D _MainTex;
			sampler2D _SubTex;     /*因为屏幕的uv已经确定是左下角00,右上角11,所以不需要_ST*/

			//判断rgb分量是否相同
			bool CompareColor(fixed4 src, fixed4 compare)
			{
				if (src.x == compare.x && src.y == compare.y && src.z == compare.z)
					return true;
				return false;
			}

			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				//如果主纹理采样是绿色,则替换成subtex背景图的采样颜色值
				if (CompareColor(col, fixed4(0, 1, 0, 1)))
				{
					col = tex2D(_SubTex, i.uv);
				}
				return col;
			}
			ENDCG
		}
	}
}

    3.运行后最终效果就是,源采样图像中颜色值为green会被重采样的subTex的颜色值替换。

  

   4.因为我写的绝对等于green颜色值,所以存在一些“毛边”效应,只需要实现一个“约等于”判断函数即可。

   最后,屏幕特效的原理和应用大致如此,后面我们需要的时候会实现一些复杂的屏幕后期特效,但是原理万变不离其宗,我们了解原理后,很多效果都可以在日常学习工作中摸索出来。

   so,我们接下来继续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值