Unity Shader - BRP - Soft Particle - 软粒子

文章目录

  • 环境
  • SoftParticleCommon.cg
  • Alpha blend
  • Additive blend
  • UniformSetSoftParticleThreshold.cs
  • CustomGraphicsSettings.cs
    • 查看 SetGlobalKW
  • SoftParticleToggle.cs
  • 遇到的坑 _InvFade 默认值修改未 10.0 来避坑


Talk is Cheap, Show me your CODE!

环境

Unity : 2018.2.11f1
Pipeline : BRP


SoftParticleCommon.cg

#ifndef __SOFT_PARTICLE_COMMON_H__
#define __SOFT_PARTICLE_COMMON_H__

// jave.lin 2021/02/28

#include "UnityCG.cginc"

#if defined(_SOFT_PARTICLE_ON)

#if defined(_SOFT_PARTICLE_DEPTH_MAP_DEF_ON)
sampler2D _CameraDepthTexture;
#endif

// https://github.com/TwoTailsGames/Unity-Built-in-Shaders/blob/master/DefaultResourcesExtra/Particle%20AddMultiply.shader
half _InvFade; // _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0

#define SOFT_PARTICLE_V2F(idx) float4 projPos : TEXCOORD##idx;

#define SOFT_PARTICLE_VERT(o) \
o.projPos = ComputeScreenPos(o.vertex); \
COMPUTE_EYEDEPTH(o.projPos.z);

#define COMPUTE_EYEDEPTH1(o, objVertex) o = -UnityObjectToViewPos( objVertex ).z

#define SOFT_PARTICLE_VERT1(o, vertex) \
o.projPos = ComputeScreenPos(vertex); \
COMPUTE_EYEDEPTH(o.projPos.z);

#define SOFT_PARTICLE_VERT2(o, vertex, objVertex) \
o.projPos = ComputeScreenPos(vertex); \
COMPUTE_EYEDEPTH1(o.projPos.z, objVertex);

#define SOFT_PARTICLE_FRAG_FADE(i, out_v) \
fixed offSP = step(10.0, _InvFade); \
out_v = saturate(_InvFade * (LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos))) - i.projPos.z)); \
out_v = lerp(out_v, 1.0, offSP);

#else

#define SOFT_PARTICLE_V2F(idx) 
#define SOFT_PARTICLE_VERT(o)
#define SOFT_PARTICLE_VERT1(o, vertex)
#define SOFT_PARTICLE_FRAG_FADE(i, out_v)  out_v = 1.0;

#endif

#endif

意思有两句 fixed offSP = step(10.0, _InvFade);out_v = lerp(out_v, 1.0, offSP); 是为了避免由些特效同学再制作 UI 特效的时候没效果 UI 特效的 BUG

这里我就不使用变体了,计算量不算大,直接 step, lerp 来伪分支即可


Alpha blend

soft particle fade 主要用于 alpha 通道即可

Shader "cgwell/Alpha Blended" 
{
	Properties 
	{
		_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
		_MainTex ("Particle Texture", 2D) = "white" {}
		[HideInInspector]_Center ("Center",Vector) = (0,0,0,1)
		[HideInInspector]_Scale ("Scale",Vector) = (1,1,1,1)
		[HideInInspector]_Normal ("Normal",Vector) = (0,0,1,0)
		_InvFade("Soft Particles Factor", Range(0.01,10.0)) = 10.0 //1.0
	}

	Category 
	{
		Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
		Blend SrcAlpha OneMinusSrcAlpha
		Cull Off Lighting Off ZWrite Off Fog { Mode Off}

		SubShader 
		{
			Pass 
			{
				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#pragma fragmentoption ARB_precision_hint_fastest

				#pragma multi_compile _ _SOFT_PARTICLE_ON
				//#define _SOFT_PARTICLE_ON
				#define _SOFT_PARTICLE_DEPTH_MAP_DEF_ON

				#include "UnityCG.cginc"
				#include "../../../Shaders/Includes/CG/SoftParticleCommon.cginc"

				sampler2D _MainTex;
				fixed4 _TintColor;
			
				struct appdata_t 
				{
					float4 vertex : POSITION;
					fixed4 color : COLOR;
					float2 texcoord : TEXCOORD0;
				};

				struct v2f 
				{
					float4 vertex : SV_POSITION;
					fixed4 color : COLOR;
					float2 texcoord : TEXCOORD0;
					SOFT_PARTICLE_V2F(1)
				};
			
				float4 _MainTex_ST;

				float4 _Center;
				float4 _Scale;
				float4 _Normal;

				uniform float4x4 _Camera2World;

				v2f vert (appdata_t v)
				{
					v2f o;
					 o.vertex = UnityObjectToClipPos(v.vertex);

					o.color = v.color;
					o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);

					SOFT_PARTICLE_VERT(o)

					return o;
				}
			
				fixed4 frag (v2f i) : SV_Target
				{
					float fade;
					SOFT_PARTICLE_FRAG_FADE(i, fade)
				    fixed4 col = saturate(2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord));
					col.a *= fade;
					return col;
				}
				ENDCG 
			}
		}
	}
}


Additive blend

主要是减少亮度,也就是 RGB 整体降低

Shader "cgwell/Dissolution_Add" {
    Properties {
        _TintColor ("Diffuse Color", Color) = (0.6985294,0.6985294,0.6985294,1)
        _MainTex ("Diffuse Texture", 2D) = "white" {}
        _N_mask ("N_mask", Float ) = 0.3
        _MaskTexture ("Mask Texture", 2D) = "white" {}
        _C_BYcolor ("C_BYcolor", Color) = (1,0,0,1)
        _N_BY_QD ("N_BY_QD", Float ) = 3
        _N_BY_KD ("N_BY_KD", Float ) = 0.01
        [HideInInspector]_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
		_InvFade("Soft Particles Factor", Range(0.01,3.0)) = 10.0 //1.0
	}
    SubShader {
        Tags {
            "IgnoreProjector"="True"
            "Queue"="Transparent"
            "RenderType"="Transparent"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            Blend One One
            ZWrite Off
            Cull Off
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //#define UNITY_PASS_FORWARDBASE
            #include "UnityCG.cginc"
			#include "../../../Shaders/Includes/CG/SoftParticleCommon.cginc"
			#pragma multi_compile _ _SOFT_PARTICLE_ON
			//#define _SOFT_PARTICLE_ON
			#define _SOFT_PARTICLE_DEPTH_MAP_DEF_ON
            #pragma target 3.0
            uniform sampler2D _MaskTexture; uniform float4 _MaskTexture_ST;
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform float4 _TintColor;
            uniform float _N_mask;
            uniform float _N_BY_KD;
            uniform float4 _C_BYcolor;
            uniform float _N_BY_QD;
            struct VertexInput {
                float4 vertex : POSITION;
                float2 texcoord0 : TEXCOORD0;
                float4 vertexColor : COLOR;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                float4 vertexColor : COLOR;
				SOFT_PARTICLE_V2F(1)
			};
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.uv0 = v.texcoord0;
                o.vertexColor = v.vertexColor;
                o.pos = UnityObjectToClipPos(v.vertex );
				SOFT_PARTICLE_VERT1(o, o.pos)
				return o;
            }
            float4 frag(VertexOutput i) : COLOR {
                float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
                float vertColMulMask = (i.vertexColor.a * _N_mask);
                float maskTexture_r = tex2D(_MaskTexture,TRANSFORM_TEX(i.uv0, _MaskTexture)).r;
                float isMaskRGreaterThanVertColMulMask = step(vertColMulMask,maskTexture_r);
                float isMaskRNotGreaterThanVertColMulMask = step(maskTexture_r,vertColMulMask);
                float vertColMulMaskIsGreaterThan_MaskRPlus_N_BY_KD = step((maskTexture_r+_N_BY_KD),vertColMulMask);
                float node_1274 = (isMaskRNotGreaterThanVertColMulMask-vertColMulMaskIsGreaterThan_MaskRPlus_N_BY_KD);
                float node_6450 = (isMaskRNotGreaterThanVertColMulMask+node_1274);
                float3 node_7666 = ((node_1274*_C_BYcolor.rgb)*_N_BY_QD);
                float3 emissive = (_TintColor.a*(((_TintColor.rgb*_MainTex_var.rgb)*node_6450)+node_7666));
                float3 finalColor = emissive + (_TintColor.a*node_7666);
                float node_6644 = (_TintColor.a*(_MainTex_var.a*node_6450));
                fixed4 col = saturate(fixed4(finalColor,node_6644));
				float fade;
				SOFT_PARTICLE_FRAG_FADE(i, fade)
				col *= fade;
				return col;
            }
            ENDCG
        }
    }
}


因为这些特效之前使用了比较多特效材质的 shader 都是每有这个 _InvFade("Soft Particles Factor", Range(0.01,3.0)) = 0.1 //1.0 属性的,并且优化之前我忘记将默认值线调整到一个看着比较好统一值

然后 _InvFade 都默认是 1.0 了,效果不是很好,如果需要对几千个特效的材质统一处理默认值未 0.1,那么这么多个材质,手动去调整肯定要死人,所以就写个工具批量处理一下即可

UniformSetSoftParticleThreshold.cs

// jave.lin : 2022/03/01

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEditor;
using UnityEngine;

public class UniformSetSoftParticleThreshold : EditorWindow
{
    private static int _InvFade = Shader.PropertyToID("_InvFade");

    [MenuItem("Tools/统一调整所有SoftParticleThreshold...")]
    public static void _Show()
    {
        var win = EditorWindow.GetWindow<UniformSetSoftParticleThreshold>();
        win.Show();
    }

    private float uniformValue = 0.1f;

    private bool adjusting = false;
    private int doingIDX = -1;
    private int len = -1;
    private bool error = false;

    private int handlePerFrame = 5;

    private List<string> assetPaths;

    private Stopwatch sw;

    private void OnEnable()
    {
        if (assetPaths == null)
        {
            assetPaths = new List<string>();
        }
    }

    private void OnGUI()
    {
        uniformValue = EditorGUILayout.FloatField("Uniform SoftParticle Threshold", uniformValue);

        const int min = 1, max = 20;
        handlePerFrame = EditorGUILayout.IntSlider("Hanlde Per Frame", handlePerFrame, min, max);

        var srcEnabled = GUI.enabled;

        if (adjusting)
        {
            GUI.enabled = false;
        }

        if (GUILayout.Button("Adjust"))
        {
            var filterPaths = new string[]
            {
                "Assets/LuaFramework/Effect",
                "Assets/LuaFramework/EffectNew"
            };

            if (assetPaths == null) assetPaths = new List<string>();
            else assetPaths.Clear();

            foreach (var filterPath in filterPaths)
            {
                var guids = AssetDatabase.FindAssets("t:Material", new string[] { filterPath });

                foreach (var guid in guids)
                {
                    var assetPath = AssetDatabase.GUIDToAssetPath(guid);
                    assetPaths.Add(assetPath);
                }
            }

            doingIDX = 0;
            len = assetPaths.Count;
            adjusting = true;

            sw = new Stopwatch();
            sw.Start();

            UnityEngine.Debug.Log("Uniform SoftParticle Threshold Start!");
        }

        GUI.enabled = srcEnabled;
    }

    private void Update()
    {
        if (adjusting && assetPaths != null && assetPaths.Count > 0)
        {
            if (doingIDX == -1 && len == -1)
            {
                adjusting = false;
                return;
            }

            if (doingIDX >= len)
            {
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();

                adjusting = false;
                sw.Stop();

                UnityEngine.Debug.Log(
                    string.Format("Uniform SoftParticle Threshold Complete! handle:{0}, len:{1}, et:{2}",
                    doingIDX, len, sw.Elapsed
                    ));
                return;
            }

            var cancel = EditorUtility.DisplayCancelableProgressBar(
                "Uniform SoftParticle Threshold",
                string.Format("{0}/{1}", (doingIDX + 1), len),
                (float)(doingIDX + 1) / len);

            if (cancel)
            {
                adjusting = false;
                sw.Stop();

                UnityEngine.Debug.Log(
                    string.Format("Uniform SoftParticle Threshold Cancel! handle:{0}, len:{1}, et:{2}",
                    doingIDX, len, sw.Elapsed
                    ));
                return;
            }

            var n = handlePerFrame;
            while (n-- > 0)
            {
                if (doingIDX >= len)
                    return;

                var assetPath = assetPaths[doingIDX++];
                try
                {
                    var mat = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
                    if (mat.HasProperty(_InvFade))
                    {
                        mat.SetFloat(_InvFade, uniformValue);
                    }
                }
                catch (System.Exception er)
                {
                    error = true;
                    adjusting = false;
                    sw.Stop();
                    UnityEngine.Debug.Log(
                        string.Format("Uniform SoftParticle Threshold error, idx : {0}, len : {1}\nassetPath : {2}\nerror : \n{3}",
                        doingIDX, len, assetPath, er
                        ));
                }
            }
        }
    }
}


CustomGraphicsSettings.cs

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

// jave.lin : 画质级别
public enum QualityLevel
{
    Low = 1,
    Middle = 2,
    High = 3,
    Ultra = 4,
}

public class CustomGraphicsSettings
{
    public static void InitGraphicSetting()
    {
        SceneManager.activeSceneChanged -= Instance.OnActiveSceneChanged;
        SceneManager.activeSceneChanged += Instance.OnActiveSceneChanged;
        // 场景变更的回调,先调 activeSceneChanged, 再调 sceneLoaded; 比较反直觉。
        // SceneManager.sceneLoaded -= Instance.OnSceneLoaded;
        // SceneManager.sceneLoaded += Instance.OnSceneLoaded;
        SceneManager.sceneUnloaded -= Instance.OnSceneUnloaded;
        SceneManager.sceneUnloaded += Instance.OnSceneUnloaded;

        Instance.srcShadows = QualitySettings.shadows;
        Instance.srcAntiAliasing = QualitySettings.antiAliasing;

        var powerSaveMode = PlayerPrefs.GetInt(kPowerSaveModeKey, 0) == 1;
        PowerSaveMode = powerSaveMode;
        var graphicsQualityLevel = Instance.GetGraphicsQualityLevel();
        GraphicsQualityLevel = graphicsQualityLevel;
        Instance.DeviceAdapterQualityLevel = GraphicsQualityLevel;
    }

    public static bool PowerSaveMode
    {
        get
        {
            return Application.targetFrameRate < 40;
        }

        set
        {
            var cv = PlayerPrefs.GetInt(kPowerSaveModeKey, -1);
            var nv = value ? 1 : 0;
            if (cv != nv)
            {
                PlayerPrefs.SetInt(kPowerSaveModeKey, nv);
            }

            var fps = value ? 30 : 60;
            Application.targetFrameRate = fps;
        }
    }
    public static QualityLevel GraphicsQualityLevel
    {
        get 
        {
            return Instance.GetGraphicsQualityLevel();
        }

        set
        {
            if ((int)value != PlayerPrefs.GetInt(kGraphicsQualityLevelKey, -1))
            {
                PlayerPrefs.SetInt(kGraphicsQualityLevelKey, (int)value);
                Instance.SetGraphicsQualityLevel(value);
                if (null != onGraphicsQualityLevelChanged)
                {
                    onGraphicsQualityLevelChanged.Invoke(value);
                }
            }
        }
    }

    private static CustomGraphicsSettings Instance
    {
        get
        {
            if (null == instance)
            {
                instance = new CustomGraphicsSettings();
            }
            return instance;
        }
    }

    public static Action<QualityLevel> onGraphicsQualityLevelChanged;
    private static CustomGraphicsSettings instance = null;

    public QualityLevel DeviceAdapterQualityLevel
    {
        get; private set;
    }
    public Dictionary<string, CustomLightMapData[]> LightMapRecord
    {
        get
        {
            return lightMapRecord;
        }

        set
        {
            lightMapRecord = value;
        }
    }

    private int srcAntiAliasing;
    private ShadowQuality srcShadows;
    private const string kPowerSaveModeKey = "graphics.setting.power.save.mode";
    private const string kGraphicsQualityLevelKey = "graphics.setting.quality.level";

    private QualityLevel AnalysicDeviceLevel()
    {
        if (SystemInfo.processorFrequency >= 2500 &&
            SystemInfo.processorCount >= 8 &&
            SystemInfo.systemMemorySize >= (6 * 1024) &&
            SystemInfo.graphicsMemorySize >= (2 * 1024) &&
            SystemInfo.graphicsShaderLevel >= 30 &&
            SystemInfo.graphicsMultiThreaded &&
            SystemInfo.supportsShadows &&
            SystemInfo.supportsInstancing &&
            SystemInfo.supports32bitsIndexBuffer
            )
        {
            return QualityLevel.Ultra;
        }
        else if (SystemInfo.processorFrequency >= 2000 &&
            SystemInfo.processorCount >= 4 &&
            SystemInfo.systemMemorySize >= (4 * 1024) &&
            SystemInfo.graphicsMemorySize >= (1 * 1024) &&
            SystemInfo.graphicsShaderLevel >= 20
            )
        {
            return QualityLevel.High;
        }
        else if (SystemInfo.processorFrequency >= 1500 &&
            SystemInfo.processorCount >= 2 &&
            SystemInfo.systemMemorySize >= (2 * 1024) &&
            SystemInfo.graphicsMemorySize >= (512) &&
            SystemInfo.graphicsShaderLevel >= 10
            )
        {
            return QualityLevel.Middle;
        }
        else
        {
            return QualityLevel.Low;
        }
    }

    private QualityLevel GetGraphicsQualityLevel()
    {
        var val = PlayerPrefs.GetInt(kGraphicsQualityLevelKey, -1);
        if (val == -1)
        {
            return AnalysicDeviceLevel();
        }
        else
        {
            return (QualityLevel)val;
        }
    }

    /// 
    /// 设置图像等级
    /// 
    /// [1, 4],等级越高,图形效果越好
    private void SetGraphicsQualityLevel(QualityLevel level)
    {
        SetGraphicsTier(level);
        SetResolutionAndShaderLOD(level);
        SetAntiAliasing(level);
        SetLigthMapUsage(level);
        SetShadow(level);
        SetGlobalKW(level);
    }
    
    private void SetLigthMapUsage(QualityLevel level)
    {
        if (level >= QualityLevel.High)
        {
            var datas = CreateCurLightMapsData(SceneManager.GetActiveScene().name);
            var len = datas != null ? datas.Length : 0;
            var newLightMapDatas = new LightmapData[len];
            for (int i = 0; i < len; i++)
            {
                newLightMapDatas[i] = datas[i].CreateLightMapData();
            }
            LightmapSettings.lightmaps = newLightMapDatas;
        }
        else
        {
            LightmapSettings.lightmaps = new LightmapData[] { };
        }
    }

    private void SetAntiAliasing(QualityLevel level)
    {
        if (level >= QualityLevel.High)
        {
            QualitySettings.antiAliasing = srcAntiAliasing;
        }
        else
        {
            QualitySettings.antiAliasing = 0;
        }
    }

    private void SetGraphicsTier(QualityLevel level)
    {
        switch(level)
        {
            case QualityLevel.Low:
            case QualityLevel.Middle:
                Graphics.activeTier = GraphicsTier.Tier1;
                break;
            case QualityLevel.High:
                Graphics.activeTier = GraphicsTier.Tier2;
                break;
            case QualityLevel.Ultra:
                Graphics.activeTier = GraphicsTier.Tier3;
                break;
        }
    }

    private void SetResolutionAndShaderLOD(QualityLevel level)
    {
        switch (level)
        {
            case QualityLevel.Low:
                QualitySettings.resolutionScalingFixedDPIFactor = 0.75f;
                Shader.globalMaximumLOD = 200;
                QualitySettings.masterTextureLimit = DeviceAdapterQualityLevel < QualityLevel.High ? 3 : 2;
                break;
            case QualityLevel.Middle:
                QualitySettings.resolutionScalingFixedDPIFactor = 0.85f;
                Shader.globalMaximumLOD = 400;
                QualitySettings.masterTextureLimit = DeviceAdapterQualityLevel < QualityLevel.High ? 2 : 1;
                break;
            case QualityLevel.High:
                QualitySettings.resolutionScalingFixedDPIFactor = 0.85f;
                Shader.globalMaximumLOD = 600;
                QualitySettings.masterTextureLimit = 0;
                break;
            case QualityLevel.Ultra:
                QualitySettings.resolutionScalingFixedDPIFactor = 1.00f;
                Shader.globalMaximumLOD = 800;
                QualitySettings.masterTextureLimit = 0;
                break;
        }
    }

    private void SetShadow(QualityLevel level)
    {
        switch (level)
        {
            case QualityLevel.Low:
                QualitySettings.shadows = ShadowQuality.Disable;
                break;
            case QualityLevel.Middle:
                QualitySettings.shadows = ShadowQuality.Disable;
                break;
            case QualityLevel.High:
                QualitySettings.shadows = srcShadows;
                QualitySettings.shadowResolution = ShadowResolution.Low;
                QualitySettings.shadowDistance = 70;
                break;
            case QualityLevel.Ultra:
                QualitySettings.shadows = srcShadows;
                QualitySettings.shadowResolution = ShadowResolution.High;
                QualitySettings.shadowDistance = 100;
                break;
        }
    }

    private void SetGlobalKW(QualityLevel level)
    {
        switch (level)
        {
            case QualityLevel.Low:
            case QualityLevel.Middle:
                Shader.DisableKeyword("_SOFT_PARTICLE_ON");
                break;
            case QualityLevel.High:
            case QualityLevel.Ultra:
                Shader.EnableKeyword("_SOFT_PARTICLE_ON");
                break;
        }
    }

    private Dictionary<string, CustomLightMapData[]> lightMapRecord = new Dictionary<string, CustomLightMapData[]>();
    private void OnActiveSceneChanged(Scene from, Scene to)
    {
        CreateCurLightMapsData(to.name);

        var level = GetGraphicsQualityLevel();
        SetGraphicsQualityLevel(level);
    }

    private CustomLightMapData[] CreateCurLightMapsData(string sceneName)
    {
        CustomLightMapData[] ret;
        var srcLightmaps = LightmapSettings.lightmaps;
        var srcLightmapsLen = srcLightmaps != null ? srcLightmaps.Length : 0;

        // create map data
        var recreate = false;
        if (!lightMapRecord.TryGetValue(sceneName, out ret))
        {
            if (srcLightmapsLen > 0)
            {
                recreate = true;
            }
        }
        else
        {
            recreate = ret.Length < srcLightmapsLen;
        }

        if (recreate)
        {
            ret = new CustomLightMapData[srcLightmapsLen];
            for (int i = 0; i < srcLightmapsLen; i++)
            {
                ret[i] = new CustomLightMapData();
            }
            lightMapRecord[sceneName] = ret;
        }

        // fill map data
        if (ret != null)
        {
            if (srcLightmapsLen > 0)
            {
                for (int i = 0; i < srcLightmapsLen; i++)
                {
                    ret[i].CopyFrom(srcLightmaps[i]);
                }
            }
        }

        return ret;
    }

    private void OnSceneUnloaded(Scene scene)
    {
        lightMapRecord.Remove(scene.name);
    }
}

查看 SetGlobalKW

    private void SetGlobalKW(QualityLevel level)
    {
        switch (level)
        {
            case QualityLevel.Low:
            case QualityLevel.Middle:
                Shader.DisableKeyword("_SOFT_PARTICLE_ON");
                break;
            case QualityLevel.High:
            case QualityLevel.Ultra:
                Shader.EnableKeyword("_SOFT_PARTICLE_ON");
                break;
        }
    }

SoftParticleToggle.cs

那么,特效同学在他们的特效开发场景中,看不到软粒子效果
那是因为 shader 变体每有开启,所以需要给他们一个组件来开启或关闭的功能,方便查看软粒子效果

// jave.lin : 2022/03/01

using UnityEngine;

[ExecuteInEditMode]
public class SoftParticleToggle : MonoBehaviour
{
    [Header("是否开启软粒子")]
    public bool softParticleEnabled = true;
    private bool lastSoftParticleEnabled = false;

    private Camera _camera;

    private void Start()
    {
        #if UNITY_EDITOR
        _camera = GetComponent<Camera>();
        _camera.depthTextureMode |= DepthTextureMode.Depth;
        #endif
    }
    private void Update()
    {
        #if UNITY_EDITOR
        if (lastSoftParticleEnabled != softParticleEnabled)
        {
            lastSoftParticleEnabled = softParticleEnabled;
            if (lastSoftParticleEnabled)
            {
                Shader.EnableKeyword("_SOFT_PARTICLE_ON");
            }
            else
            {
                Shader.DisableKeyword("_SOFT_PARTICLE_ON");
            }
            EnabledSceneViewCamsDepth(lastSoftParticleEnabled);
        }
        #endif
    }

    private void EnabledSceneViewCamsDepth(bool enabledDepth)
    {
        for (var i = 0; i < UnityEditor.SceneView.sceneViews.Count; i++)
        {
            var scene = UnityEditor.SceneView.sceneViews[i] as UnityEditor.SceneView;
            if (scene == null) continue;
            EnabledCamDepth(scene.camera, enabledDepth);
        }
    }

    private void EnabledCamDepth(Camera camera, bool enabledDepth)
    {
        if (enabledDepth)
            camera.depthTextureMode |= DepthTextureMode.Depth;
        else
            camera.depthTextureMode &= ~DepthTextureMode.Depth;
        Debug.Log("Camera.gameObject.name" + camera.name + ", depth : " + enabledDepth);
    }
}


遇到的坑 _InvFade 默认值修改未 10.0 来避坑

因为各个开启,_InvFade = 0.1 的话,会影响所有特效片段里不透明深度写入的深度图比较近

导致贴 地表水的一些地裂,等 特效的面片看不到效果了

所以后面又将 _InvFade 的默认值修改未 10.0 了


有了 BRP 的思路,再 URP 下实现也是很 easy 的


每天 最便宜的圆珠笔 一练

C 的排线已经乱套。。。 -_-~

Unity Shader - BRP - Soft Particle - 软粒子_第1张图片

乱画排线,排出一个锤子
Unity Shader - BRP - Soft Particle - 软粒子_第2张图片

Unity Shader - BRP - Soft Particle - 软粒子_第3张图片

你可能感兴趣的:(unity,unity-shader,unity,SoftParticle,软粒子)