Unity内置Shader解读8——Particles/Additive

1.Shader在什么情况下使用

Particles/Additive(粒子/叠加)到了粒子系列了,之所以先写前面几篇是因为本shader中都用到了,篇幅有限,因此分了几篇来写。本文注释中有关INSTANCE_ID和软粒子的深度计算方法都没有搞明白,不懂的部分只能后面再深入研究了不能阻挡学习的脚步。

2.Shader的价值(用的多不多),Shader的难度

Additive应该是用的非常多的,难度非常大,毕竟有些细节我还没搞明白。

3.代码详细注释

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

Shader "Legacy Shaders/Particles/Additive" {
    Properties {
        _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)//明调颜色
        _MainTex ("Particle Texture", 2D) = "white" {}//贴图
        _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0//软粒子因子
    }

    Category {
        Tags { 
            "Queue"="Transparent" //申明渲染队列为透明(3000)
            "IgnoreProjector"="True"//忽略所有阴影
            "RenderType"="Transparent" //声明为透明物体
            "PreviewType"="Plane" //指示材质检视面板预览应如何显示材质。默认情况下,材质显示为球体,但也可以将 PreviewType 设置为“Plane”(将显示为 2D)或“Skybox”(将显示为天空盒)
        }
        // Blend SrcAlpha One//透明混合模式
        // ColorMask指定渲染结果的输出通道,而不是通常的 RGBA 四个通道都被写入
        // ColorMask RGB,RBA等,意思是输出颜色中RGB,RBA通道会被写入
        // ColorMask R,意思是输出颜色中只有R通道会被写入
        // ColorMask 0,意思是不会输出任何颜色
        // 默认值为RGBA,即四个通道都写入
        ColorMask RGB

        // //双面显示,关闭裁剪
        // Cull Off 
        // //关闭灯光影响
        // Lighting Off 
        // //关闭深度写入
        // ZWrite Off

        SubShader {
            Pass {

                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma target 2.0
                //使用您定义的一组关键字来编译多个实例。查看已编译的着色器,multi_compile_particles添加了SOFTPARTICLES_ON和SOFTPARTICLES_OFF,因此,这只是Unity自己的粒子关键字风格,包含该关键字。此外,您可以在质量设置中切换关键字。
                //简单说所有multi_compile开头的都是声明宏定义
                //之后就可以用#if xxxx #endif了
                //或者使用官方定义的宏定义如下,可以自动生成一些宏定义
                // #pragma multi_compile_particles表示允许使用官方的软阴影粒子SOFTPARTICLES_ON/SOFTPARTICLES_OFF的宏定义开关
                #pragma multi_compile_particles
                //雾效宏定义,不了解可以看雾效篇
                #pragma multi_compile_fog

                #include "UnityCG.cginc"

                sampler2D _MainTex;
                fixed4 _TintColor;

                struct appdata_t {
                    float4 vertex : POSITION;
                    fixed4 color : COLOR;
                    float2 texcoord : TEXCOORD0;
                    //在“顶点着色器输入/输出”结构中定义一个语义为SV_InstanceID的元素。一些要更改的属性,则可以根据ID进行更改,而无需为MaterialPropertyBlock设置其他属性。
                    //在UnityInstancing.cginc文件中可找到UNITY_VERTEX_INPUT_INSTANCE_ID的定义
                    //#define UNITY_VERTEX_INPUT_INSTANCE_ID uint instanceID : SV_InstanceID;
                    //通常用在GPU Instancing和VR中
                    //在VR中他们将实例ID和眼睛索引传递给片段着色器。这使您可以访问片段着色器中的实例化属性,以及进行可能需要的每眼唯一工作。例如,如果您使用任何视图矩阵或投影矩阵或片段着色器中的相机位置,则这些都需要眼图索引以提供正确的值,否则,您将始终访问左眼。
                    //这部分网上资料太少-。-搜不到,暂时不理解,就先这样吧
                    UNITY_VERTEX_INPUT_INSTANCE_ID
                };

                struct v2f {
                    float4 vertex : SV_POSITION;
                    fixed4 color : COLOR;
                    float2 texcoord : TEXCOORD0;
                    雾效,不了解可以看雾效篇
                    UNITY_FOG_COORDS(1)
                    //如果启用软粒子
                    #ifdef SOFTPARTICLES_ON
                        float4 projPos : TEXCOORD2;
                    #endif
                    UNITY_VERTEX_OUTPUT_STEREO
                };

                float4 _MainTex_ST;

                v2f vert (appdata_t v)
                {
                    v2f o;
                    //同UNITY_VERTEX_INPUT_INSTANCE_ID
                    //需要写在vert shader的最前面
                    UNITY_SETUP_INSTANCE_ID(v);
                    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                    //取裁剪空间顶点位置
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    //如果软粒子系统打开,需要#pragma multi_compile_particles
                    //开关在质量设置里
                    #ifdef SOFTPARTICLES_ON
                        //ComputeScreenPos传入裁剪空间顶点坐标变换到齐次坐标系下的坐标
                        //齐次坐标就是将笛卡尔坐标转成矩阵,便于变换操作
                        o.projPos = ComputeScreenPos (o.vertex);
                        //计算顶点摄像机空间的深度:距离裁剪平面的距离,线性变化;
                        //在顶点着色器中取出深度信息储存到projPos,在片段着色器中使用
                        COMPUTE_EYEDEPTH(o.projPos.z);
                    #endif
                    //获取mesh顶点色
                    //一般情况下顶点色都是没有使用的默认为白色
                    o.color = v.color;
                    //将模型顶点的uv和Tiling、Offset两个变量进行运算,计算出实际显示用的顶点uv
                    //如果不需要Tiling、Offset可以移除
                    o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
                    //雾效,不了解可以看雾效篇
                    UNITY_TRANSFER_FOG(o,o.vertex);
                    return o;
                }

                UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
                float _InvFade;

                fixed4 frag (v2f i) : SV_Target
                {

                    #ifdef SOFTPARTICLES_ON
                        //获得当前片元显示的深度
                        //LinearEyeDepth 负责把深度纹理的采样结果转换到视角空间下的深度值
                        float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
                        //顶点计算出来的深度
                        float partZ = i.projPos.z;
                        //saturate将值限制到0-1
                        //使用混合度_InvFade乘以两个深度的差
                        //有关这两个深度查到的信息不多,暂时也搞不明白,先搁这后面明白了再更
                        float fade = saturate (_InvFade * (sceneZ-partZ));
                        //混合度影响一下透明度
                        i.color.a *= fade;
                    #endif

                    //最终颜色混合
                    // alpha should not have double-brightness applied to it, but we can't fix that legacy behavior without breaking everyone's effects, so instead clamp the output to get sensible HDR behavior (case 967476)alpha不应该应用双倍的亮度,但是我们不能在不破坏每个人的效果的情况下修复遗留行为,所以取而代之的是钳制输出以获得合理的HDR行为(案例967476)
                    fixed4 col = 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord);
                    //限制透明度区间
                    col.a = saturate(col.a); 

                    //雾效混合,不了解可以看雾效篇
                    UNITY_APPLY_FOG_COLOR(i.fogCoord, col, fixed4(0,0,0,0)); // fog towards black due to our blend mode由于我们的混合模式雾向黑色
                    return col;
                }
                ENDCG
            }
        }
    }
}

4.Shader编写思路,用到的知识点

粒子其实主要就是显示原本的颜色并且提亮,本Shader涵盖了很多如适配性代码,其中软粒子主要是指粒子图像边缘混合时柔化,具体可以自行百度,其他的知识点参考本系列前面几篇。
Legacy Shaders下的Particles系列基本与本文98%相似,各个不同仅修改了混合方式,至于透明混合方式写法都比较简单,本文不再讨论,读者自行研究(本系列的主要目的是梳理官方shader了解各种语法用法知识点,而非实现具体逻辑及shader效果)。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值