UnityShader24:最简单的屏幕后处理例子

 

一、需要提前了解的

其实关于屏幕后处理(Screen Post-processing Effects)相关的知识,前面已经提过了不少:

这些是 OpenGL 渲染部分:

搞懂了上面这些后,就可以进入 Unity3D 了:

了解了这些内容之后,这一章的内容就非常好理解

 

二、屏幕后处理 C# 部分逻辑

  • 屏幕后处理的时机:完成整个场景、得到屏幕图像后
  • 屏幕后处理的目的:对整个游戏画面添加各种艺术效果和屏幕特技

对于上面的时机和目的,单纯的一个或多个 Shader 就可能难以去实现完整的屏幕后处理逻辑,还需要脚本的帮助

先解决第一个问题:抓取屏幕,这就依赖于 OnRenderImage 函数和 Graphics.Bilt 函数

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
//当在物体上添加该脚本时,Camera组件也会被自动被添加上去(如果没有的话)
[RequireComponent(typeof(Camera))]
public class PostEffectsBase: MonoBehaviour
{
	protected void Start()
	{
		//如果显卡支持图像后期处理效果
		if (!SystemInfo.supportsImageEffects)
		{
			//设置当前组件为关闭状态
			enabled = false;
		}
	}

	protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
	{
		//判断当前着色器是否可在当前显卡设备上使用,如果对应的着色器的所有Fallback都不可支持或者传入的着色器就不存在,返回null
		if (shader == null || !shader.isSupported)
			return null;

		if (material && material.shader == shader)
			return material;
		else
		{
			material = new Material(shader);
			//设置当前材质不会被保存在场景中
			material.hideFlags = HideFlags.HideAndDontSave;
			if (material)
				return material;
			else
				return null;
		}
	}
}

上面这个是基类,主要用于检查条件和资源是否支持我们进行图像后处理,以及组合 Shader 和 Meterial

  • SystemInfo.supportsImageEffects:如果显卡支持图像后期处理效果,返回 true
  • [RequireComponent(typeof(cName))]:添加依赖项:当你设置一个用了 RequireComponent 的脚本为组件,与此同时组件 cName 也会被自动被添加上去(如果没有的话)且不可被移除
  • shader.isSupported:当前着色器是否可在当前显卡设备上使用,如果对应的着色器的所有 Fallback 都不可支持,返回 false
  • object.hideFlags:设置的值应为 Unity 内置的枚举 HideFlags,用于控制对象的销毁、保存和在检查器中的可见性
using UnityEngine;
using System.Collections;

public class PostEffectExample: PostEffectsBase
{
	public Shader shader;
	private Material _material;
	public Material material
	{
		get
		{
			_material = CheckShaderAndCreateMaterial(shader, _material);
			return _material;
		}
	}

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

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

这是屏幕后处理的核心脚本:通过 OnRenderTexture 拿到当前屏幕 RT,之后再通过 Blit 将它作为绑定了指定 Shader Meterial 的主纹理,进行一次或多次渲染,得到的最终结果会显示到屏幕上

 

三、亮度、对比度与饱和度

这一章一样,亮度、对比度与饱和度的计算当然是在着色器中:

Shader "Jaihk662/PPEExample1"
{
    Properties
    {
        _MainTex("Base(RGB)", 2D) = "white" {}
		_Brightness("Brightness", Float) = 1            //亮度
		_Saturation("Saturation", Float) = 1            //饱和度
		_Contrast("Contrast", Float) = 1                //对比度
    }

    CGINCLUDE       //和之前常用的CGPROGRAM不同,在CGINCLUDE和ENDCG范围内插入的shader代码会被插入到所有Pass中
    #include "UnityCG.cginc"

    sampler2D _MainTex;  
    half _Brightness;
    half _Saturation;
    half _Contrast;
    struct vert2frag 
    {
        float4 pos: SV_POSITION;
		float2 uv: TEXCOORD0;
    };

    vert2frag vert(appdata_img v)
    {
		vert2frag o;
		o.pos = UnityObjectToClipPos(v.vertex);
		o.uv = v.texcoord;
		return o;
	}
	half4 frag(vert2frag i): SV_Target
    {
		fixed4 renderTex = tex2D(_MainTex, i.uv);
        //计算亮度
		fixed3 finalColor = renderTex.rgb * _Brightness;
				
        //计算饱和度
        fixed luminance = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;       //图像转黑白的专业算法
        fixed3 luminanceColor = fixed3(luminance, luminance, luminance);
        finalColor = lerp(luminanceColor, finalColor, _Saturation);

        //计算对比度
        fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
		finalColor = lerp(avgColor, finalColor, _Contrast);
				
		return fixed4(finalColor, renderTex.a);  
	}
    ENDCG

    Subshader
    {
        Pass
        {
            ZTest Always Cull Off ZWrite Off
            Fog { Mode off }        //设置雾模式:关闭

            CGPROGRAM
            //使用低精度(FP16)以提升fragment着色器的运行速度,减少时间
            #pragma fragmentoption ARB_precision_hint_fastest
            #pragma vertex vert
			#pragma fragment frag
            ENDCG
        }
    }
}

然后只需要将这个 Shader 给到对应的后处理脚本就 OK,这个 Shader 就是 Bilt 操作时 Meterial 对应的 Shader

上面的参数对应的亮度为 2.74,饱和度为 0.83,对比度为 0.2,效果和原图如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值