欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

程序员文章站 2022-05-25 08:49:55
...

Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

 

目录

Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

一、简介

二、色散

三、关键技术

四、注意事项

五、效果预览

六、实现步骤


 

一、简介

所谓屏幕后处理,简单来说就是渲染流水线的最后阶段,对由整个场景生成的一张图片进行处理,比如HDR,运动模糊等等效果,通过屏幕空间的后处理,可以整体改变整个游戏的风格或者效果。所以,要制作屏幕后处理,我们需要两样东西,一个是用于渲染后处理效果的shader,而另一个是我们需要调用这个渲染的脚本。
 

实现原理:

  • shader里片元着色器的输出颜色的rgb值是分别对rgb通道的_MainTex进行采样;
  • 并对采样坐标做不同的偏移,这里主要的uv.x 上偏移;
  • 如果加上时间参数,即可做出简单动画效果;

 

二、色散

色散是复色光分解为单色光而形成光谱的现象。色散可以利用棱镜或光栅等作用为色散系统的仪器来实现。如复色光进入棱镜后,由于它对各种频率的光具有不同折射率,各种色光的传播方向有程度的偏折,因而在离开棱镜时就各自分散,形成光谱。

Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

 

三、关键技术

1、在 Shader 中,把颜色进行rgb分开处理,这里 r 和 b 上做偏移;  

 2、OnRenderImage函数每帧渲染完全部内容后执行,我们在每一帧设置Material的各项参数,通过Material.SetXXX("name",value)可以向shader中传递各种参数;

3、关键代码

half2 uv_0 = half2(i.uv.x - scale,i.uv.y);
half2 uv_1 = half2(i.uv.x + scale, i.uv.y);

col.r = tex2D(_MainTex, uv_0).r;
col.g = tex2D(_MainTex, i.uv).g;
col.b = tex2D(_MainTex, uv_1).b;

四、注意事项

1、各种后处理效果可以叠加,这里的dest并不一定就是屏幕。不过后处理是很耗费性能的,一方面是pixel shader全屏幕overdraw,另一方面,一个rendertexture的内存占用很大,尤其是大分辨率手机上,多个后处理效果可能造成内存耗尽,程序崩溃。

2、注意判断屏幕特效是否支持可以用


五、效果预览

Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

六、实现步骤

1、新建Unity工程,导入模型,新建脚本,如下

Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

2、新建两个camera,Left_Camera 不挂载脚本不做颜色处理,Right_Camera 挂在脚本做颜色处理,两相机视口作为颜色效果调节对比,如下

Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

3、测试效果

Unity 屏幕特效 之 简单地调整颜色的 色散效果 的实现

4、Shader 脚本

Shader "Unlit/ColorDispersion"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
		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;
            float4 _MainTex_ST;
			float _Scale;
			float _Speed;
			
			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= fixed4(0,0,0,1);

                fixed scale = _Scale * sin(_Time.y * _Speed);
				scale = saturate(scale);

				half2 uv_0 = half2(i.uv.x - scale,i.uv.y);
				half2 uv_1 = half2(i.uv.x + scale,i.uv.y);

				col.r = tex2D(_MainTex,uv_0).r;
				col.g = tex2D(_MainTex,i.uv).g;
				col.b = tex2D(_MainTex,uv_1).b;
               
                return col;
            }
            ENDCG
        }
    }
}

5、C# 脚本

using UnityEngine;

//非运行时也触发效果
[ExecuteInEditMode]
//屏幕后处理特效一般都需要绑定在摄像机上
[RequireComponent(typeof(Camera))]
//提供一个后处理的基类,主要功能在于直接通过Inspector面板拖入shader,生成shader对应的材质
public class ScreenPostEffectBase : MonoBehaviour
{

    //Inspector面板上直接拖入
    public Shader shader = null;
    private Material _material = null;
    public Material _Material
    {
        get
        {
            if (_material == null)
                _material = GenerateMaterial(shader);
            return _material;
        }
    }

    //根据shader创建用于屏幕特效的材质
    protected Material GenerateMaterial(Shader shader)
    {
        // 系统是否支持
        if (!SystemInfo.supportsImageEffects)
        {            
            return null;
        }

        if (shader == null)
            return null;
        //需要判断shader是否支持
        if (shader.isSupported == false)
            return null;
        Material material = new Material(shader);
        material.hideFlags = HideFlags.DontSave;
        if (material)
            return material;
        return null;
    }

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

public class ColorDispersion : ScreenPostEffectBase
{
    [Range(0, 5)]
    public float scale = 1;
    public float speed = 5;


    void OnRenderImage(RenderTexture src, RenderTexture dest) {
        if (_Material)
        {
            _Material.SetFloat("_Scale",scale);
            _Material.SetFloat("_Speed",speed);
            Graphics.Blit(src,dest,_Material);
        }
        else {
            Graphics.Blit(src,dest);
        }
    }
}