Unity ShaderLab特效教程:带模糊效果的 2D 阴影着色器教程(带代码详解)

本文介绍了一种在Unity中为UGUI和Sprite生成动态阴影的Shader技术,通过两个着色程序块实现正常显示与阴影效果,支持颜色调节和模糊设置。

如果代码中有什么不清楚请查看以下基础知识

Shader基础知识
unity3d 中 七种坐标知识详解

带模糊效果的 2D 阴影着色器教程(带代码详解)

一、效果预览

该 Shader 实现2D 物体 + 模糊阴影的双层渲染效果:一层渲染带 Box 模糊的偏移阴影,一层渲染物体本身(可叠加贴图与颜色),支持自定义阴影颜色、偏移量和模糊强度,适合 2D 游戏角色、UI 元素的阴影美化。
上笑狗图:
在这里插入图片描述

二、代码结构与核心部分说明

1. 属性面板(Properties)

Properties
{
   _MainTex ("贴图", 2D) = "black" {}  // 物体主贴图(默认黑色)
   _Color ("颜色", Color) = (0.3, 0.59, 0.11,1)  // 物体本身叠加色
   _ShadowColor ("阴影颜色", Color) = (0.3, 0.59, 0.11,1)  // 阴影颜色(含透明度)
   _ShadowOffset ("阴影偏移", Vector) = (0.3, 0.59,0,0)  // 阴影偏移(x/y控制左右上下,z无效)
   _BlurSize("模糊尺寸", vector) = (256,256,0,0)  // 模糊采样尺寸(对应贴图分辨率,x=宽,y=高)
   _BlurOffset("模糊偏移", Range(1, 10)) = 1  // 模糊强度(值越大模糊越明显)
}
  • 核心作用:暴露参数,在 Unity 编辑器实时调节物体颜色、阴影位置与模糊效果。

2. SubShader 基础设置

SubShader
{
   LOD 200  // 细节层级(200适配中等性能)
   Tags
   {
       "Queue" = "Transparent"  // 透明队列(确保阴影/物体在不透明物体后渲染)
       "IgnoreProjector" = "True"  // 不受投影器影响(2D专用)
       "RenderType" = "Transparent"  // 透明类型(适配后处理)
   }
  • 关键作用:配置 2D 透明渲染规则,避免阴影与物体遮挡异常。

3. Pass 1:阴影渲染(带模糊)

(1)Pass 基础配置
Pass
{
   Cull Off  // 关闭背面裁剪(2D物体无正反面)
   Lighting Off  // 关闭光照(阴影无需光照计算)
   ZWrite Off  // 关闭深度写入(避免阴影遮挡物体)
   Fog { Mode Off }  // 关闭雾效
   Blend SrcAlpha OneMinusSrcAlpha  // 透明混合(阴影半透效果)
   CGPROGRAM 
       #pragma vertex vert
       #pragma fragment frag       
       #include "UnityCG.cginc"
       // 声明属性变量
       sampler2D _MainTex;
       fixed4 _ShadowColor;
       fixed4 _ShadowOffset;
       float4 _BlurSize;
       fixed _BlurOffset;
(2)数据结构定义
struct a2v
{
   float4 vertex : POSITION;  // 模型空间顶点坐标
   float2 texcoord : TEXCOORD0;  // 贴图UV
   fixed4 color : COLOR;  // 顶点颜色(预留)
};
struct v2f
{
   float4 vertex : SV_POSITION;  // 裁剪空间顶点坐标
   half2 texcoord : TEXCOORD0;  // 传递UV
   fixed4 color : COLOR;  // 传递顶点颜色
};
(3)Box 模糊工具函数(filter)
float4 filter(float3x3 filter, sampler2D tex, float2 coord, float2 texSize)
{
   float4 outCol = float4(0,0,0,0);
   // 遍历3x3矩阵(采样当前像素周围8个像素+自身)
   for (int i = 0; i < 3; i++)
   {
       for (int j = 0; j < 3; j++)
       {
           // 计算偏移后的采样坐标(_BlurOffset控制偏移幅度)
           float2 newCoord = float2(coord.x + (i-1)*_BlurOffset, coord.y + (j-1)*_BlurOffset);
           float2 newUV = float2(newCoord.x / texSize.x, newCoord.y / texSize.y);  // 转UV坐标
           outCol += tex2D(tex, newUV) * filter[i][j];  // 采样颜色×滤波权重,累加
       }
   }
   return outCol;
}
  • 核心原理:3x3 Box 滤波(权重均为 1/9),实现均匀模糊效果。
(4)阴影顶点着色器(vert)
v2f vert (a2v v)
{
   v2f o;
   o.vertex = UnityObjectToClipPos(v.vertex);  // 模型→裁剪空间
   o.vertex.x += _ShadowOffset.x;  // 阴影X轴偏移
   o.vertex.y += _ShadowOffset.y;  // 阴影Y轴偏移
   o.texcoord = v.texcoord;
   o.color = v.color;
   return o;
}
  • 关键操作:给顶点坐标加偏移,实现阴影与物体分离。
(5)阴影片元着色器(frag)
fixed4 frag (v2f v) : COLOR
{
   // 定义3x3 Box滤波矩阵(权重平均,实现模糊)
   float3x3 boxFilter =
   {
       1.0f/9, 1.0f/9, 1.0f/9,
       1.0f/9, 1.0f/9, 1.0f/9,
       1.0f/9, 1.0f/9, 1.0f/9,
   };
   // 计算贴图实际采样坐标(UV×模糊尺寸)
   float2 coord = float2(v.texcoord.x * _BlurSize.x, v.texcoord.y * _BlurSize.y);
   fixed4 f = filter(boxFilter, _MainTex, coord, _BlurSize);  // 模糊采样
   fixed4 color = f;
   color.rgb = _ShadowColor.rgb;  // 替换为阴影颜色
   color.a = color.a * _ShadowColor.a;  // 控制阴影透明度
   return color;
}

4. Pass 2:物体本身渲染

Pass
{
   // 同阴影Pass的基础配置(Cull Off、Lighting Off等,略)
   CGPROGRAM 
       #pragma vertex vert
       #pragma fragment frag       
       #include "UnityCG.cginc"
       sampler2D _MainTex;
       fixed4 _Color;
       // 数据结构同Pass1(a2v、v2f,略)
       // 物体顶点着色器(无偏移,直接传递坐标)
       v2f vert (a2v v)
       {
           v2f o;
           o.vertex = UnityObjectToClipPos(v.vertex);  // 模型→裁剪空间
           o.texcoord = v.texcoord;
           o.color = v.color;
           return o;
       }
       // 物体片元着色器
       fixed4 frag (v2f v) : COLOR
       {
           fixed4 color = tex2D(_MainTex, v.texcoord);  // 采样主贴图
           color.rgb = color.rgb + _Color.rgb;  // 叠加物体颜色
           color.a = color.a * _Color.a;  // 控制物体透明度
           return color;
       }
   ENDCG
}
  • 核心逻辑:无模糊、无偏移,直接渲染物体本身,与阴影 Pass 叠加形成最终效果。

三、使用步骤(3 步完成)

  1. 创建 Shader 与材质:Unity 中右键→Create→Shader→Unlit Shader,替换代码并命名 “Custom / 阴影着色器”;创建 Material,将 Shader 设为该自定义 Shader。

  2. 参数调节:拖入贴图到_MainTex;调_Color改物体颜色;_ShadowColor设阴影色;_ShadowOffset控制阴影位置;_BlurOffset调模糊强度;_BlurSize设为贴图分辨率(如 256,256)。

  3. 应用物体:将材质赋给 2D Quad 或 Sprite,运行即可看到 “物体 + 模糊阴影” 效果。

完整代码

Shader "Custom/阴影着色器"
{
    Properties
    {
        //图片设置
        _MainTex ("贴图", 2D) = "black" {}
        _Color ("颜色", Color) = (0.3, 0.59, 0.11,1)
        //阴影设置
        _ShadowColor ("阴影颜色", Color) = (0.3, 0.59, 0.11,1)
        _ShadowOffset ("阴影偏移", Vector) = (0.3, 0.59,0,0)
        //模糊
        _BlurSize("模糊尺寸", vector) = (256,256,0,0)
        //模糊偏移
        _BlurOffset("模糊偏移", Range(1, 10)) = 1
    }
    
    SubShader
    {
        LOD 200
        Tags
        {
            //透明队列
            "Queue" = "Transparent"
            //不被任何投影或贴图影响。一般应用在sprite和GUI
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
        }
         //阴影
        Pass
        {
            //2d关闭
            Cull Off
            Lighting Off
            ZWrite Off
            Fog { Mode Off }
            // Offset -1, -1
            //正常透明度混合
            Blend SrcAlpha OneMinusSrcAlpha
            //ColorMaterial AmbientAndDiffuse | Emission 颜色材质 环境漫反射光照 及放射光
            // ColorMaterial AmbientAndDiffuse

            CGPROGRAM
                //顶点与片元着色器
                #pragma vertex vert
                #pragma fragment frag        
                //unity宏    
                #include "UnityCG.cginc"
                //阴影相关
                sampler2D _MainTex;
                fixed4 _ShadowColor;
                fixed4 _ShadowOffset;
                fixed4 _Color;
                //模糊
                float4 _BlurSize;
                fixed _BlurOffset;

                struct a2v
                {
                    //顶点位置
                    float4 vertex : POSITION;
                    //贴图
                    float2 texcoord : TEXCOORD0;
                    //颜色
                    fixed4 color : COLOR;
                };
        
                struct v2f
                {
                    //像素位置
                    float4 vertex : SV_POSITION;
                    //贴图
                    half2 texcoord : TEXCOORD0;
                    //颜色
                    fixed4 color : COLOR;
                };
                //对忒图滤波
                float4 filter(float3x3 filter, sampler2D tex, float2 coord, float2 texSize)
                {
                    float4 outCol = float4(0,0,0,0);
                    for (int i = 0; i < 3; i++)
                    {
                        for (int j = 0; j < 3; j++)
                        {
                            //计算采样点,得到当前像素附近的像素的坐标
                            float2 newCoord = float2(coord.x + (i-1)*_BlurOffset, coord.y + (j-1)*_BlurOffset);
                            float2 newUV = float2(newCoord.x / texSize.x, newCoord.y / texSize.y);
                            //采样并乘以滤波器权重,然后累加
                            outCol += tex2D(tex, newUV) * filter[i][j];
                        }
                    }
                    return outCol;
                }
                //顶点着色器
                v2f vert (a2v v)
                {
                    v2f o;
                    //将顶点从模型空间转换为裁剪空间,因为2d就是平面映射。
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    //偏移
                    o.vertex.x += _ShadowOffset.x;
                    o.vertex.y += _ShadowOffset.y;
                    o.vertex.z += _ShadowOffset.z;
                    o.texcoord = v.texcoord;
                    o.color = v.color;
                    return o;
                }
                // 片元着色器
                fixed4 frag (v2f v) : COLOR
                {
                    
                    //模糊
                    //定义滤波核
                    float3x3 boxFilter = 
                    {
                        1.0f/9, 1.0f/9, 1.0f/9, 
                        1.0f/9, 1.0f/9, 1.0f/9, 
                        1.0f/9, 1.0f/9, 1.0f/9, 
                    };
                    
                    float2 coord = float2(v.texcoord.x * _BlurSize.x, v.texcoord.y * _BlurSize.y);
                    fixed4 f = filter(boxFilter, _MainTex, coord, _BlurSize);

                    


                    //像素颜色
                    // fixed4 color = tex2D(_MainTex, v.texcoord) ;
                    fixed4 color = f;
                    //像素颜色 点乘 灰度因子
                    color.rgb = _ShadowColor.rgb;
                    //透明度
                    color.a = color.a * _ShadowColor.a;

                    return color;
                }
            ENDCG
        }
        //正常着色
        Pass
        {
            //2d关闭
            Cull Off
            Lighting Off
            ZWrite Off
            Fog { Mode Off }
            // Offset -1, -1
            //正常透明度混合
            Blend SrcAlpha OneMinusSrcAlpha
            //ColorMaterial AmbientAndDiffuse | Emission 颜色材质 环境漫反射光照 及放射光
            // ColorMaterial AmbientAndDiffuse

            CGPROGRAM
                //顶点与片元着色器
                #pragma vertex vert
                #pragma fragment frag        
                //unity宏    
                #include "UnityCG.cginc"

                sampler2D _MainTex;
                fixed4 _Color;

                struct a2v
                {
                    //顶点位置
                    float4 vertex : POSITION;
                    //贴图
                    float2 texcoord : TEXCOORD0;
                    //颜色
                    fixed4 color : COLOR;
                };
        
                struct v2f
                {
                    //像素位置
                    float4 vertex : SV_POSITION;
                    //贴图
                    half2 texcoord : TEXCOORD0;
                    //颜色
                    fixed4 color : COLOR;
                };
                //顶点着色器
                v2f vert (a2v v)
                {
                    v2f o;
                    //将顶点从模型空间转换为裁剪空间,因为2d就是平面映射。
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.texcoord = v.texcoord;
                    o.color = v.color;
                    return o;
                }
                // 片元着色器
                fixed4 frag (v2f v) : COLOR
                {
                    //像素颜色
                    fixed4 color = tex2D(_MainTex, v.texcoord) ;
                    //像素颜色 点乘 灰度因子
                    color.rgb = color.rgb + _Color.rgb;
                    //透明度
                    color.a =  color.a * _Color.a;
                    return color;
                }
            ENDCG
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千年奇葩

从来没受过打赏,这玩意好吃吗?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值