stonstad 发表于 2021-12-17 17:26

Unity——Shader学习13——From庄懂(特效篇):AC、AB ...

第十三课(特效篇)

<hr/>本课任务:


[*]特效大纲
[*]AC(AlphaCutout)
[*]AB(AlphaBlend)
[*]AD(Addtive)
[*]混合模式
[*]美术自定义混合面板
<hr/>一、特效大纲

1.特效·透

[*]AlphaCutOut(AC)
[*]AlphaBlend(AB)
[*]Additive(AD)
[*]其他混合效果



2.特效·动

[*]参数动画:面板上的参数做动画,(标量、位置、颜色、向量...)
[*]UV动画:
UV流动:一般拿UV的Offset做流动动画
UV扰动:UV做扰动+映射
序列帧动画:拿UV走序列,如1张图是3x3的九宫格,拿UV去走每一格
[*]顶点动画
顶点位置动画:下面视频中的食物动画就是用顶点位置动画实现的,不是骨骼实现的
顶点颜色动画:通常和粒子相关,粒子颜色、显示、消失等


https://www.zhihu.com/video/1433564662336389120
序列帧动画:


https://www.zhihu.com/video/1433564838043324416
序列帧动画案例:案例来源:v_xchen_v

3.特效·映射

[*]极坐标:可以制作圆形的法阵,做一些极坐标的动画
[*]屏幕坐标UV:(之前讲过)拿屏幕坐标UV采样贴图,配合UV扰动可以做出下面透明扭曲的效果
[*]透明扭曲


https://www.zhihu.com/video/1433565046320885760
<hr/>二、透明剪切·AlphaCutout(AC)(或者AlphaTest)

介绍:只有完全透明和不完全透明2种情况,无中间半透明情况,其本质是舍弃了某些片元
用途:

[*]常用于复杂轮廓,边缘明确的物体表现,如:镂空金属,裙摆边缘,特定风格的头发,树叶等。(像丝袜的网孔,写实的头发,其边缘就表达不能确了)
[*]卡通渲染表现,一般配上抗锯齿后处理+Bloom(辉光)
优点:

[*]无排序问题
缺点:

[*]边缘效果太实
[*]移动端性能较差
[*]有很强的锯齿



AC:右;AB:左

Shader代码


1.Properties声明:
_MainTex: 要带透明度的贴图
_Cutoff: 透明剪切阈值
2.SubShader Tags
Tags {
         "Queue" = "AlphaTest"               //渲染队列2450
         "IgnoreProjector" = "True"          //shader不会受到投影器(Projectors)的影响
         "ForceNoShadowCasting" = "True"   //关闭阴影投射
         "RenderType" = "TransparentCutout"//把Shader归入到提前定义的组(这里是TransparentCutout组)
                                              //以指明该Shader使用了透明度测试
                                              //RenderType标签通常被用于着色器替换功能3.用clip函数对采样纹理进行透明度剪切
clip(var_MainTex.a - _Cutoff);//如果clip里面的值小于0,则剔除该片元这里我在Pass里面 使用了渲染设置 Cull Off ,关闭背面剔除
具体代码:
Shader "AP1/L13/AlphaCutout" {
        Properties{
      _MainTex ("RGB:颜色 ; A:透贴" , 2D) = "white"{}
      _Cutoff("Cutoff" , Range(0.0 , 1.0)) = 0.5
        }
        SubShader{
                Tags {
                        "Queue" = "AlphaTest"               //渲染队列2450
            "IgnoreProjector" = "True"          //shader不会受到投影器(Projectors)的影响
            "ForceNoShadowCasting" = "True"   //关闭阴影投射
            "RenderType" = "TransparentCutout"//把Shader归入到提前定义的组(这里是TransparentCutout组)
                                                 //以指明该Shader使用了透明度测试
                                                 //RenderType标签通常被用于着色器替换功能
                }
                Pass {
                        Name "FORWARD"
                        Tags {
                                "LightMode" = "ForwardBase"
                        }

            Cull Off      //关闭背面剔除
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        #include "UnityCG.cginc"
                        #pragma multi_compile_fwdbase_fullshadows
                        #pragma target 3.0

            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform fixed      _Cutoff;

                        struct VertexInput {
                                float4 vertex : POSITION;
                float2 uv0    : TEXCOORD0;
                        };
                        struct VertexOutput {
                                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                        };
                        VertexOutput vert(VertexInput v) {
                                VertexOutput o = (VertexOutput)0;
                  o.pos = UnityObjectToClipPos(v.vertex);
                  o.uv0 = v.uv0 * _MainTex_ST.xy + _MainTex_ST.zw;
                                return o;
                        }

                        fixed4 frag(VertexOutput i) : SV_TARGET {

                fixed4 var_MainTex = tex2D(_MainTex , i.uv0);
                clip(var_MainTex.a - _Cutoff);                //如果clip里面的值小于0,则剔除该片元
                               
                                return fixed4(var_MainTex.rgb ,1.0);       
                        }
                                ENDCG
                }
        }
                FallBack "Diffuse"                                               
}<hr/>三、透明混合·AlphaBlend(AB)

介绍:有半透明效果,将源颜色(该片元颜色)和目标颜色(颜色缓冲区颜色)进行混合
用途:

[*]用于复杂轮廓,无明确边缘的物体表现
[*]半透明物体的表现
[*]一般的特效表现,打底用
优点:

[*]移动端性能较好
[*]边缘效果好,有过渡
缺点:

[*]有排序问题,需要关闭深度写入



AC:右;AB:左

Shader代码


Queue : 控制渲染队列,使Unity能够先渲染不透明物体,再渲染带透明度的物体
Blend : 混合方式,源颜色和目标颜色的混合算法的一部分
(这里是 Blend One OneMinusSrcAlpha,是因为所用贴图的rgb已经预乘过了alpha通道了,如果没有预乘过则应写成 Blend SrcAlpha OneMinusSrcAlpha)(具体解释看十五课)
注意:AB涉及到了透明度混合,因此想要渲染双面显示,不能直接简单地写 Cull Off ,应该用2个Pass来分别渲染前后面

具体代码:
Shader "AP1/L13/AlphaBlend" {
        Properties{
      _MainTex ("RGB:颜色 ; A:透贴" , 2D) = "white"{}
        }
        SubShader{
                Tags {
                        "Queue" = "Transparent"            //渲染队列3000
            "RenderType" = "Transparent"         //把Shader归入到提前定义的组(这里是Transparent组)
                                                 //以指明该Shader使用了透明度测试
                                                 //RenderType标签通常被用于着色器替换功能
            "IgnoreProjector" = "True"         //shader不会受到投影器(Projectors)的影响
            "ForceNoShadowCasting" = "True"      //关闭阴影投射

                }
                Pass {
                        Name "FORWARD"
                        Tags {
                                "LightMode" = "ForwardBase"
                        }
                        ZWrite Off                                                        //关闭深度写入
            Blend One OneMinusSrcAlpha          //修改混合方式


                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        #include "UnityCG.cginc"
                        #pragma multi_compile_fwdbase_fullshadows
                        #pragma target 3.0

            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;

                        struct VertexInput {
                                float4 vertex : POSITION;
                float2 uv0    : TEXCOORD0;
                        };
                        struct VertexOutput {
                                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                        };
                        VertexOutput vert(VertexInput v) {
                                VertexOutput o = (VertexOutput)0;
                  o.pos = UnityObjectToClipPos(v.vertex);
                  o.uv0 = v.uv0 * _MainTex_ST.xy + _MainTex_ST.zw;
                                return o;
                        }

                        fixed4 frag(VertexOutput i) : SV_TARGET {

                fixed4 var_MainTex = tex2D(_MainTex , i.uv0);                               
                                return fixed4(var_MainTex);                //最终输出
                        }
                                ENDCG
                }
        }
                FallBack "Diffuse"                                               
}<hr/>四、透明度叠加·Additive(AD)

用途:

[*]常用于发光体,辉光
[*]一般用于特效提亮
问题:

[*]有排序问题,需要关闭深度写入
[*]叠加多层后 容易爆性能(OverDraw),一个像素会算多次叠加
[*]辉光效果,通常可以用后处理Bloom替代


Shader代码:


只是在AB的基础上修改混合模式为 Blend One One 即可,达到提亮的效果
(注意:这里前面的One 是用了预乘后的贴图,如果没有预乘,则要在Shader里面预乘)
为什么最后输出alpha通道可以设置为1.0:因为AD的混合因子为 One One ,与透明度无关,因此最终输出的RGB不会受到alpha值的影响,你将其设置为0.0也不会有任何改变
具体代码:
Shader "AP1/L13/Addtive" {
        Properties{
      _MainTex ("RGB:颜色 ; A:透贴" , 2D) = "white"{}
        }
        SubShader{
                Tags {
                        "Queue" = "Transparent"            //渲染队列3000
            "RenderType" = "Transparent"         //把Shader归入到提前定义的组(这里是Transparent组)
                                                 //以指明该Shader使用了透明度测试
                                                 //RenderType标签通常被用于着色器替换功能
            "IgnoreProjector" = "True"         //shader不会受到投影器(Projectors)的影响
            "ForceNoShadowCasting" = "True"      //关闭阴影投射

                }
                Pass {
                        Name "FORWARD"
                        Tags {
                                "LightMode" = "ForwardBase"
                        }
                        ZWrite Off                           //关闭深度写入
            Blend One One          //修改混合方式

                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        #include "UnityCG.cginc"
                        #pragma multi_compile_fwdbase_fullshadows
                        #pragma target 3.0

            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;

                        struct VertexInput {
                                float4 vertex : POSITION;
                float2 uv0    : TEXCOORD0;
                        };
                        struct VertexOutput {
                                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                        };
                        VertexOutput vert(VertexInput v) {
                                VertexOutput o = (VertexOutput)0;
                  o.pos = UnityObjectToClipPos(v.vertex);
                  o.uv0 = v.uv0 * _MainTex_ST.xy + _MainTex_ST.zw;
                                return o;
                        }

                        fixed4 frag(VertexOutput i) : SV_TARGET {

                fixed4 var_MainTex = tex2D(_MainTex , i.uv0);                               
                                return fixed4(var_MainTex.rgb , 1.0);                //最终输出,因为Blend One One 最终输出RGB与透明度无关,所以alpha可以设置为常数
                        }
                                ENDCG
                }
        }
                FallBack "Diffuse"                                               
}


AC、AB、AD对比

五、混合模式

各种混合模式,就是一个个函数,参数是混合因子和运算符,变量是源颜色和目标颜色
(拿PS类比:PS的上图层——源颜色,下图层——目标颜色)
关于混合计算方式可以参考我的另一篇文章:TecrayC:《UnityShader入门精要》学习笔记——第八章——透明效果中的混合命令






<hr/>六、美术自定义混合面板




左边:一般给美术调试效果; 右边:进行相应封装(需要C#)

代码实现:


   //[枚举Enum(枚举类型)]
_BlendSrc("混合源乘子" , int) = 0         //_BlendSrc , int型Enum是枚举的意思,后面小括号内是枚举类型
BlendOp                       //可自定义混合算符
Blend         //可自定义混合模式在定义变量时BlendOp(混合算符)和Blend(混合模式) 的参数填写 面板参数
具体代码:
Shader "AP1/L13/BlendMode" {
        Properties{
      _MainTex ("RGB:颜色 ; A:透贴" , 2D) = "white"{}

         //[枚举Enum(枚举类型)]
      _BlendSrc("混合源乘子" , int) = 0          //_BlendSrc , int型
      
      _BlendDst("混合目标乘子" , int) = 0      //_BlendDst
      
      _BlendOp("混合算符" , int) = 0             //_BlendOp
        }
        SubShader{
                Tags {
                        "Queue" = "Transparent"            //渲染队列3000
            "RenderType" = "Transparent"         //把Shader归入到提前定义的组(这里是Transparent组)
                                                 //以指明该Shader使用了透明度测试
                                                 //RenderType标签通常被用于着色器替换功能
            "IgnoreProjector" = "True"         //shader不会受到投影器(Projectors)的影响
            "ForceNoShadowCasting" = "True"      //关闭阴影投射

                }
                Pass {
                        Name "FORWARD"
                        Tags {
                                "LightMode" = "ForwardBase"
                        }
                        ZWrite Off                                                        //关闭深度写入
            BlendOp                       //可自定义混合算符
            Blend         //可自定义混合模式


                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        #include "UnityCG.cginc"
                        #pragma multi_compile_fwdbase_fullshadows
                        #pragma target 3.0

            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;

                        struct VertexInput {
                                float4 vertex : POSITION;
                float2 uv0    : TEXCOORD0;
                        };
                        struct VertexOutput {
                                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                        };
                        VertexOutput vert(VertexInput v) {
                                VertexOutput o = (VertexOutput)0;
                  o.pos = UnityObjectToClipPos(v.vertex);
                  o.uv0 = v.uv0 * _MainTex_ST.xy + _MainTex_ST.zw;
                                return o;
                        }

                        fixed4 frag(VertexOutput i) : SV_TARGET {

                fixed4 var_MainTex = tex2D(_MainTex , i.uv0);                               
                                return fixed4(var_MainTex);             
                        }
                                ENDCG
                }
        }
                FallBack "Diffuse"                                               
}

https://www.zhihu.com/video/1433565970187497472
<hr/>第十三课总结:


[*]特效有透明,动画,映射等
[*]AC(AlphaCutout)是直接去掉透明度超过某一阈值的片元
[*]AB(AlphaBlend)和AD(Addtive)都是应用了透明度混合,用到了混合模式
[*]混合模式有很多种,其本质上是一种关于源颜色、目标颜色、源混合因子、目标混合因子的算法,可以自己设定面板参数进行枚举调节

参考资料:
页: [1]
查看完整版本: Unity——Shader学习13——From庄懂(特效篇):AC、AB ...