您当前的位置: 首页 >  unity

Jave.Lin

暂无认证

  • 3浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity Shader PostProcessing - 12 - 外发光

Jave.Lin 发布时间:2021-03-01 20:13:30 ,浏览量:3

文章目录
  • 思路
  • Shader Code - GlowZAlwaysPP.shader
  • CSharp Code - GlowPP.cs
  • CSharp Code - GlowManager.cs
  • 使用方式
  • 查看效果
  • Project
  • References

其实以前老早就想制作这个效果了,但是没有太多的空闲时间

那这次反正项目组需要这个效果,就顺手将 Demo 记录到 Blog

2021/03/03 刚刚好今天早上晨会分享了这个 外发光 的思路

我讲的比较简单的理解化的方式

该效果还是比较简单的,都是非常基础的东西,大神、大佬可以跳过。

思路

使用后效处理:

  • 先将需要外发光的对象都 draw 到一张 RT(RenderTexture,这里因为颜色统一的,所以 RT 只要 Format为 R8 即可),假设 RT 名为:Mask_RT
  • 再将 Mask_RT Blit 一下,处理高斯模糊,将 Mask_RT 高斯模糊后的内容存入到另一张 RT: Blur_RT
    • 高斯模糊可以参考我之前的一篇:Unity Shader PostProcessing - 6 - GaussianBlur 高斯模糊+CommandBuffer使用做一些其他的特效
  • 再将 Value_RT = Blur_RT - Mask_RT,就是最终外发光的像素部分了
  • 再用一个 FinalCol = _Color * Value_RT 就是最终颜色了

下面列出完整的 CSharp + ShaderLab 的代码

Shader Code - GlowZAlwaysPP.shader
// jave.lin 2021/02/25
// references : https://blog.csdn.net/linjf520/article/details/104940213
Shader "Game/PP/GlowZAlwaysPP"
{
    CGINCLUDE
#include "UnityCG.cginc"

        // pure col
        float4 vert_pure_col(float4 vertex : POSITION) : SV_POSITION
    {
        return UnityObjectToClipPos(vertex);
    }
        fixed4 frag_pure_col() : SV_Target
    {
        return 1;
    }

        // expand
    sampler2D _ExpandOrginTex;
    float4 _ExpandOrginTex_TexelSize;
    float _GlowSize;
    struct a2v_expand
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };
    struct v2f_expand
    {
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
        float4 uv01 : TEXCOORD1;
        float4 uv23 : TEXCOORD2;
    };
    v2f_expand vert_expand(a2v_expand v) {
        v2f_expand o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        float2 ts = _ExpandOrginTex_TexelSize.xy;
        float2 offset1 = float2(1, 0);
        float2 offset2 = float2(0, 1);
        o.uv01.xy = v.uv + offset1 * ts * _GlowSize; // 左
        o.uv01.zw = v.uv + offset1 * -ts * _GlowSize; // 右
        o.uv23.xy = v.uv + offset2 * ts * _GlowSize; // 上
        o.uv23.zw = v.uv + offset2 * -ts * _GlowSize; // 下
        return o;
    }
    fixed4 frag_expand(v2f_expand i) : SV_Target
    {
        fixed sum = tex2D(_ExpandOrginTex, i.uv).r;
        if (sum == 0)
            sum = tex2D(_ExpandOrginTex, i.uv01.xy).r; // 左
        if (sum == 0)
            sum += tex2D(_ExpandOrginTex, i.uv01.zw).r; // 右
        if (sum == 0)
            sum += tex2D(_ExpandOrginTex, i.uv23.xy).r; // 上
        if (sum == 0)
            sum += tex2D(_ExpandOrginTex, i.uv23.zw).r; // 下

        //if (sum == 0)
        //    sum = tex2D(_ExpandOrginTex, float2(i.uv01.xy.x, i.uv23.xy.y)).r; // 左 | 上
        //if (sum == 0)
        //    sum += tex2D(_ExpandOrginTex, float2(i.uv01.zw.x, i.uv23.xy.y)).r; // 右 | 上
        //if (sum == 0)
        //    sum = tex2D(_ExpandOrginTex, float2(i.uv01.xy.x, i.uv23.zw.y)).r; // 左 | 下
        //if (sum == 0)
        //    sum += tex2D(_ExpandOrginTex, float2(i.uv01.zw.x, i.uv23.zw.y)).r; // 右 | 下

        return sum != 0 ? 1 : 0;
    }

        /// blur /
        struct a2v_blur
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };
    struct v2f_blur
    {
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
        float4 uv01 : TEXCOORD1;
        float4 uv23 : TEXCOORD2;
    };
    sampler2D _BlurOrginTex;
    float4 _BlurOrginTex_TexelSize;
    float _BlurSize;
    v2f_blur vert_blur_h(a2v_blur v) {
        v2f_blur o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        float2 ts = _BlurOrginTex_TexelSize.xy;
        float2 offset1 = float2(1, 0);
        float2 offset2 = float2(2, 0);
        o.uv01.xy = v.uv + offset1 * ts * _BlurSize; // 左1
        o.uv01.zw = v.uv + offset1 * -ts * _BlurSize; // 右1
        o.uv23.xy = v.uv + offset2 * ts * _BlurSize; // 左2
        o.uv23.zw = v.uv + offset2 * -ts * _BlurSize; // 右2
        return o;
    }
    v2f_blur vert_blur_v(a2v_blur v) {
        v2f_blur o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        float2 ts = _BlurOrginTex_TexelSize.xy;
        float2 offset1 = float2(0, 1);
        float2 offset2 = float2(0, 2);
        o.uv01.xy = v.uv + offset1 * ts * _BlurSize; // 上1
        o.uv01.zw = v.uv + offset1 * -ts * _BlurSize; // 下1
        o.uv23.xy = v.uv + offset2 * ts * _BlurSize; // 上2
        o.uv23.zw = v.uv + offset2 * -ts * _BlurSize; // 下2
        return o;
    }
    fixed4 frag_blur(v2f_blur i) : SV_Target{
        fixed4 sum = tex2D(_BlurOrginTex, i.uv) * 0.4026;
        sum += tex2D(_BlurOrginTex, i.uv01.xy) * 0.2442; // 左1 | 上1
        sum += tex2D(_BlurOrginTex, i.uv01.zw) * 0.2442; // 右1 | 下1
        sum += tex2D(_BlurOrginTex, i.uv23.xy) * 0.0545; // 左2 | 上2
        sum += tex2D(_BlurOrginTex, i.uv23.zw) * 0.0545; // 右2 | 下2
        return sum;
    }

        /// final /
    sampler2D _MaskTex;
    sampler2D _BlurTex;
    sampler2D _SrcTex;
    fixed4 _GlowColor;
    struct a2v_final
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };
    struct v2f_final
    {
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
    };
    v2f_final vert_final(a2v_final v) {
        v2f_final o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        return o;
    }
    fixed4 frag_final(v2f_final i) : SV_Target{
        fixed blur_col = tex2D(_BlurTex, i.uv).r;
        fixed mask_col = tex2D(_MaskTex, i.uv).r;
        fixed value = saturate(blur_col - mask_col);
        return saturate(tex2D(_SrcTex, i.uv) + value * _GlowColor);
    }
        ENDCG
        SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
            Pass // pure col 0
        {

            ColorMask R
            CGPROGRAM
            #pragma vertex vert_pure_col
            #pragma fragment frag_pure_col
            ENDCG
        }
            Pass // expand 1
        {
            ColorMask R
            CGPROGRAM
            #pragma vertex vert_expand
            #pragma fragment frag_expand
            ENDCG
        }
            Pass // blur h 2
        {
            ColorMask R
            CGPROGRAM
            #pragma vertex vert_blur_h
            #pragma fragment frag_blur
            ENDCG
        }
            Pass // blur v 3
        {
            ColorMask R
            CGPROGRAM
            #pragma vertex vert_blur_v
            #pragma fragment frag_blur
            ENDCG
        }
            Pass // final 4
        {
            CGPROGRAM
            #pragma vertex vert_final
            #pragma fragment frag_final
            ENDCG
        }
    }
}

CSharp Code - GlowPP.cs
// jave.lin 2021/02/25
// 绘制外发光后效
// 临时效果,时间关系,未优化
using UnityEngine;
using UnityEngine.Rendering;

public class GlowPP : PostEffectBasic
{
    private static int _GlowSize_hash = Shader.PropertyToID("_GlowSize");
    private static int _BlurSize_hash = Shader.PropertyToID("_BlurSize");
    private static int _GlowColor_hash = Shader.PropertyToID("_GlowColor");
    private static int _ExpandOrginTex_hash = Shader.PropertyToID("_ExpandOrginTex");
    private static int _BlurTex_hash = Shader.PropertyToID("_BlurTex");
    private static int _BlurOrginTex_hash = Shader.PropertyToID("_BlurOrginTex");
    private static int _MaskTex_hash = Shader.PropertyToID("_MaskTex");
    private static int _SrcTex_hash = Shader.PropertyToID("_SrcTex");

    private static int _ZLessTex_hash = Shader.PropertyToID("_ZLessTex");
    private static int _ZGreaterTex_hash = Shader.PropertyToID("_ZGreaterTex");
    private static int _ExpandTex_hash = Shader.PropertyToID("_ExpandTex");

    [Header("ZGreater绘制材质")]
    public Material z_greater_draw_mat;
    [Header("ZAlways绘制材质")]
    public Material z_always_draw_mat;

    [Header("DownSample 降采等级")]
    public int down_sample_level = 4;

    [Range(1, 4)]
    [Header("高斯模糊的次数")]
    public int iterations = 4;

    [Header("模糊边界大小:每次模糊采样纹素距离的缩放因数")]
    [Range(0.2f, 3.0f)]
    public float blur_size = 0.2f;

    [Header("外发光边缘大小")]
    [Range(0.0f, 2.0f)]
    public float glow_size = 2;

    [Header("外发光颜色")]
    public Color glow_color = Color.red;

    [Header("是否只显示 z greater 部分(暂时无效的参数)")]
    public bool only_show_greater_glow = false;

    private CommandBuffer cmdBuffer;
    private Camera cam;

    protected override void Start()
    {
        base.Start();
        cmdBuffer = new CommandBuffer();
        cmdBuffer.name = "GlowPPCmdBuffer";
        cam = GetComponent();
    }

    private void OnDestroy()
    {
        if (cmdBuffer != null)
        {
            cmdBuffer.Clear();
            cmdBuffer.Dispose();
            cmdBuffer = null;
        }
        cam = null;
    }

    protected override void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (!IsSupported || GlowManager.instance.Count == 0)
        {
            Graphics.Blit(src, dest);
            return;
        }

        if (z_always_draw_mat == null)
        {
            Debug.LogError("GlowPP.z_always_draw_mat == null");
            Graphics.Blit(src, dest);
            return;
        }

        // clamp down_sample_level
        if (down_sample_level  0 ? listPool.Pop() : new List();
        go.GetComponentsInChildren(false, list);

        GlowElement e = glowElementPool.Count > 0 ? glowElementPool.Pop() : null;

        if (ignoreLayer != 0)
        {
            var count = list.Count;
            for (int i = 0; i             
关注
打赏
1664331872
查看更多评论
0.0827s