美文网首页
Unity内置Shader解读8——Particles/Addi

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

作者: ShawnWeasley | 来源:发表于2021-05-11 13:53 被阅读0次

    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效果)。

    相关文章

      网友评论

          本文标题:Unity内置Shader解读8——Particles/Addi

          本文链接:https://www.haomeiwen.com/subject/hpairltx.html