这次要使用到顶点和片段着色器。同样是制作屏幕后处理效果。

下面是一开始的效果,只是一个循环播放的粒子系统。

我们首先要对源图像的亮部区域进行提亮,然后进行模糊添加光芒。然后进行混合,最后进行一次合成

我们需要创建一些临时纹理来存储渲染过程的中间阶段,之后先通过第一个pass将原图像提亮,下面是关键代码, Graphics.Blit(source, brightnessTex, material, 1)这个函数的就是通过material的第二个pass对图像进行处理,

 void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        RenderTexture brightnessTex = RenderTexture.GetTemporary(source.width / divide, source.height / divide, source.depth, source.format);
        RenderTexture blurredTex1 = RenderTexture.GetTemporary(brightnessTex.descriptor);
        RenderTexture blurredTex2 = RenderTexture.GetTemporary(brightnessTex.descriptor);
        RenderTexture compositeTex = RenderTexture.GetTemporary(brightnessTex.descriptor);

        material.SetVector(brightnessSettingsID, new Vector3(threshold, intensity, attenuation));

        // 进行渲染操作

        Graphics.Blit(source, brightnessTex, material, 1);
        Graphics.Blit(brightnessTex, destination, material, 0);
        //Graphics.Blit(source, destination, material, 0);

        // 释放临时RenderTextures
        RenderTexture.ReleaseTemporary(brightnessTex);
        RenderTexture.ReleaseTemporary(blurredTex1);
        RenderTexture.ReleaseTemporary(blurredTex2);
        RenderTexture.ReleaseTemporary(compositeTex);
    }

下面是shader代码

            fixed4 frag(v2f_img input) : SV_Target
            {
               float4 color = tex2D(_MainTex,input.uv ) ;
                
               return max(color - BRIGHTNESS_THRESHOLD,0)* INTENSITY;

            }

 然后下一步就是为星星添加光芒条纹。

要以特定角度模糊上一步的图像,然后迭代多次

创建一个新的pass,_MainTex_TexelSize.xy就是图像宽度的倒数。计算颜色之后每次对uv进行偏移并对颜色进行衰减

 Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            int _Iteration;
            float2 _Offset;
            struct v2f_starglow {
                float4 pos : SV_POSITION;   // 变换后的屏幕空间坐标
                half2 uv : TEXCOORD0;       // 纹理坐标
                half power : TEXCOORD1;     
                half2 offset : TEXCOORD2;   // 偏移量
            };

            v2f_starglow vert(appdata_img v) 
            {
                v2f_starglow o;
    
                // 计算顶点位置
                o.pos = UnityObjectToClipPos(v.vertex);

                // 传递纹理坐标
                o.uv = v.texcoord;

                o.power = pow(4.0, _Iteration - 1.0);

                // 计算偏移量
                o.offset = _MainTex_TexelSize.xy * _Offset * o.power;

                return o;
             }


            float4 frag(v2f_starglow input) : SV_Target 
            {
                half4 color = half4(0, 0, 0, 0); // 初始化颜色为黑色
                half2 uv = input.uv;
    
                // 遍历4个样本
                for (int j = 0; j < 4; j++) {
                    // 采样纹理并应用衰减
                    color += saturate(tex2D(_MainTex, uv) * pow(ATTENUATION, input.power * j));
                    // 更新纹理坐标
                    uv += input.offset;
                }
    
                return color;
            }


            ENDCG
        }

C#代码:

 float angle = 360f / numOfStreaks;

        for (int x = 1; x <= numOfStreaks; x++)
        {
            // 计算每个条纹的偏移量
            Vector2 offset = (Quaternion.AngleAxis(angle * x + angleOfStreak, Vector3.forward) * Vector2.down).normalized;

            // 设置材质的偏移量和迭代次数
            material.SetVector(offsetID, offset);
            material.SetInt(iterationID, 1);

            // 使用材质进行图像处理
            Graphics.Blit(brightnessTex, blurredTex1, material, 2);

            for (int i = 2; i <= iteration; i++)
            {
                // 设置当前迭代次数
                material.SetInt(iterationID, i);

                // 进行图像处理,将 blurredTex1 处理并输出到 blurredTex2
                Graphics.Blit(blurredTex1, blurredTex2, material, 2);

                // 交换纹理,准备下一次迭代
                RenderTexture temp = blurredTex1;
                blurredTex1 = blurredTex2;
                blurredTex2 = temp;
            }

        }

然后要进行一次混合

 //  STEP:3
                Pass
        {
            // 设置混合模式
            Blend OneMinusDstColor One

            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            #include "UnityCG.cginc"

            // 定义片元着色器
            fixed4 frag(v2f_img input) : SV_Target
            {
                // 从 _MainTex 采样颜色并返回
                return tex2D(_MainTex, input.uv);
            }

            ENDCG
        }

最后将源图像与上一步中得到的图像进行叠加

最终效果:

完整代码:

starglow.shader

Shader "ImageEffect/StarGlow"
{
    Properties
    {
        [HideInInspector]
        _MainTex("Texture", 2D) = "white" {}
        _BrightnessSettings("(Threshold, Intensity, Attenuation, -)", Vector) = (0.8, 1.0, 0.95, 0.0)
    }
    SubShader
    {
        CGINCLUDE

        #include "UnityCG.cginc"

        sampler2D _MainTex;
        float4    _MainTex_ST;
        float4    _MainTex_TexelSize;
        float4    _BrightnessSettings;

        #define BRIGHTNESS_THRESHOLD _BrightnessSettings.x
        #define INTENSITY            _BrightnessSettings.y
        #define ATTENUATION          _BrightnessSettings.z

        ENDCG

        // STEP:0
        // Debug.

        Pass
        {
            CGPROGRAM

            #pragma vertex vert_img
            #pragma fragment frag

            fixed4 frag(v2f_img input) : SV_Target
            {
                return tex2D(_MainTex, input.uv);
            }

            ENDCG
        }
        // STEP:1
           Pass
        {
            CGPROGRAM

            #pragma vertex vert_img
            #pragma fragment frag

            fixed4 frag(v2f_img input) : SV_Target
            {
               float4 color = tex2D(_MainTex,input.uv ) ;
                
               return max(color - BRIGHTNESS_THRESHOLD,0)* INTENSITY;

            }

            ENDCG
        }

          // STEP:2
           Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            int _Iteration;
            float2 _Offset;
            struct v2f_starglow {
                float4 pos : SV_POSITION;   // 变换后的屏幕空间坐标
                half2 uv : TEXCOORD0;       // 纹理坐标
                half power : TEXCOORD1;     
                half2 offset : TEXCOORD2;   // 偏移量
            };

            v2f_starglow vert(appdata_img v) 
            {
                v2f_starglow o;
    
                // 计算顶点位置
                o.pos = UnityObjectToClipPos(v.vertex);

                // 传递纹理坐标
                o.uv = v.texcoord;

                o.power = pow(4.0, _Iteration - 1.0);

                // 计算偏移量
                o.offset = _MainTex_TexelSize.xy * _Offset * o.power;

                return o;
             }


            float4 frag(v2f_starglow input) : SV_Target 
            {
                half4 color = half4(0, 0, 0, 0); // 初始化颜色为黑色
                half2 uv = input.uv;
    
                // 遍历4个样本
                for (int j = 0; j < 4; j++) {
                    // 采样纹理并应用衰减
                    color += saturate(tex2D(_MainTex, uv) * pow(ATTENUATION, input.power * j));
                    // 更新纹理坐标
                    uv += input.offset;
                }
    
                return color;
            }


            ENDCG
        }
       //  STEP:3
                Pass
        {
            // 设置混合模式
            Blend OneMinusDstColor One

            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            #include "UnityCG.cginc"

            // 定义片元着色器
            fixed4 frag(v2f_img input) : SV_Target
            {
                // 从 _MainTex 采样颜色并返回
                return tex2D(_MainTex, input.uv);
            }

            ENDCG
        }

        // Step 4 Pass
        Pass
        {
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            sampler2D _CompositeTex;
            float4 _CompositeColor;

            fixed4 frag(v2f_img input) : SV_Target
            {
                // 从 _MainTex 采样颜色
                float4 mainColor = tex2D(_MainTex, input.uv);

                // 从 _CompositeTex 采样颜色
                float4 compositeColor = tex2D(_CompositeTex, input.uv);

                // 计算 compositeColor 的灰度,并乘以 _CompositeColor
                compositeColor.rgb = (compositeColor.r + compositeColor.g + compositeColor.b) * 0.3333 * _CompositeColor.rgb;

                // 将 mainColor 和 compositeColor 叠加,并限制在 [0,1] 范围
                return saturate(mainColor + compositeColor);
            }

            ENDCG
        }


    }
}

starglow.cs

using System.Collections.Generic;
using UnityEngine;

public class StarGlow : MonoBehaviour
{
    #region Field

    [Range(0, 1)]
    public float threshold = 1;

    [Range(0, 10)]
    public float intensity = 1;

    [Range(1, 20)]
    public int divide = 3;

    [Range(1, 5)]
    public int iteration = 5;

    [Range(0, 1)]
    public float attenuation = 1;

    [Range(0, 360)]
    public float angleOfStreak = 0;

    [Range(1, 16)]
    public int numOfStreaks = 4;

    public Material material;

    public Color color = Color.white;

    private int compositeTexID   = 0;
    private int compositeColorID = 0;
    private int brightnessSettingsID   = 0;
    private int iterationID      = 0;
    private int offsetID         = 0;

    #endregion Field

    #region Method

    void Start()
    {
        compositeTexID   = Shader.PropertyToID("_CompositeTex");
        compositeColorID = Shader.PropertyToID("_CompositeColor");
        brightnessSettingsID   = Shader.PropertyToID("_BrightnessSettings");
        iterationID      = Shader.PropertyToID("_Iteration");
        offsetID         = Shader.PropertyToID("_Offset");
    }

    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        RenderTexture brightnessTex = RenderTexture.GetTemporary(source.width / divide, source.height / divide, source.depth, source.format);
        RenderTexture blurredTex1 = RenderTexture.GetTemporary(brightnessTex.descriptor);
        RenderTexture blurredTex2 = RenderTexture.GetTemporary(brightnessTex.descriptor);
        RenderTexture compositeTex = RenderTexture.GetTemporary(brightnessTex.descriptor);

        material.SetVector(brightnessSettingsID, new Vector3(threshold, intensity, attenuation));

        // 进行渲染操作

        Graphics.Blit(source, brightnessTex, material, 1);

        float angle = 360f / numOfStreaks;

        for (int x = 1; x <= numOfStreaks; x++)
        {
            // 计算每个条纹的偏移量
            Vector2 offset = (Quaternion.AngleAxis(angle * x + angleOfStreak, Vector3.forward) * Vector2.down).normalized;

            // 设置材质的偏移量和迭代次数
            material.SetVector(offsetID, offset);
            material.SetInt(iterationID, 1);

            // 使用材质进行图像处理
            Graphics.Blit(brightnessTex, blurredTex1, material, 2);

            for (int i = 2; i <= iteration; i++)
            {
                // 设置当前迭代次数
                material.SetInt(iterationID, i);

                // 进行图像处理,将 blurredTex1 处理并输出到 blurredTex2
                Graphics.Blit(blurredTex1, blurredTex2, material, 2);

                // 交换纹理,准备下一次迭代
                RenderTexture temp = blurredTex1;
                blurredTex1 = blurredTex2;
                blurredTex2 = temp;
            }
            Graphics.Blit(blurredTex1, compositeTex, material, 3);

        }


        material.SetColor(compositeColorID, color);
        material.SetTexture(compositeTexID,compositeTex);
        Graphics.Blit(source, destination,material,4);
        //Graphics.Blit(source, destination, material, 0);

        // 释放临时RenderTextures
        RenderTexture.ReleaseTemporary(brightnessTex);
        RenderTexture.ReleaseTemporary(blurredTex1);
        RenderTexture.ReleaseTemporary(blurredTex2);
        RenderTexture.ReleaseTemporary(compositeTex);
    }

    #endregion Method
}

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部