您当前的位置: 首页 >  ar

Jave.Lin

暂无认证

  • 5浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity Shader - BRP - Soft Particle - 软粒子

Jave.Lin 发布时间:2022-03-03 09:26:42 ,浏览量:5

文章目录
  • 环境
  • 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();
        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 assetPaths;

    private Stopwatch sw;

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

    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();
            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(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 = 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 = 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             
关注
打赏
1664331872
查看更多评论
0.1521s