Mecanim 发表于 2022-9-19 07:34

一般通过unity特效shader

是实习的第一个作业,贼菜2333
一个有基本功能的特效shader+制作一个爆炸效果
特效shader

当时还没怎么写过c#,也不懂序列化和生命周期,纠结了半天我刚刚填进去的东西怎么一运行就没了啊,然后发现材质会存.mat文件,就直接存材质里了(逃。
当时还没写过editor,随便网上找了个改吧改吧。
总之是按要求实现了,原理就不写了!网上满天飞。

mask
https://www.zhihu.com/video/1554840288279109632


warp
https://www.zhihu.com/video/1554840471729582080

pannar
https://www.zhihu.com/video/1554840540960665600
Shader "Effect/qwqCustomEffect"
{
    Properties
    {
      _MainTex ("Main Texture", 2D) = "white" {}
      _MainColor("Main Color", Color) = (1,1,1,1)
      _UseMainTexPanner("Use MainTex Panner", float) = 0
      _MainTex_PannerU("Main Texture panner u", float) = 0
      _MainTex_PannerV("Main Texture panner v", float) = 0

      _MaskTex("Mask Texture", 2D) = "white" {}
      _UseMaskTexPanner("Use MaskTex Panner", float) = 0
      _MaskTex_PannerU("Mask Texture panner u", float) = 0
      _MaskTex_PannerV("Mask Texture panner v", float) = 0      

      _DissolveTex("Dissolve Texture", 2D) = "wihte"{}
      _DissolveFactor("Dissolve Factor", Range(0,1)) = 0
      _DissolveWidth("Dissolve Width", Range(0,1)) = 0
      _UseCustomData("", float) = 0
      
      _WarpTex("Warping Texture", 2D) = "bump"{}
      _WarpFactor("Warping Factor", Range(0,1)) = 0
      _WarpDeltaTime("Warping Delta Time", range(0.05, 0.5)) =0

    }
    SubShader
    {
      Tags
      {
            "Queue" = "Transparent"
            "RenderPipeline" = "UniversalPipeline"
            "IgnoreProjector" = "True"
      }
      LOD 100

      Pass
      {
            Cull Off
                        Lighting Off
                        ZWrite On
            ZTest On
            Blend SrcAlpha OneMinusSrcAlpha

            HLSLPROGRAM
            #pragma vertex EffectVert
            #pragma fragment EffectFrag

            #pragma multi_compile_instancing
            
            #pragma shader_feature_local __ _USE_MASK
            #pragma shader_feature_local __ _USE_PANNER
            #pragma shader_feature_local __ _USE_DISSOLVE
            #pragma shader_feature_local __ _USE_WARPING
            #pragma shader_feature_local __ _BILLBOARD_ON

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            //#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Particles.hlsl"

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);
            #ifdef _USE_MASK
            TEXTURE2D(_MaskTex);
            SAMPLER(sampler_MaskTex);
            #endif
            #ifdef _USE_DISSOLVE
            TEXTURE2D(_DissolveTex);
            SAMPLER(sampler_DissolveTex);            
            #endif
            #ifdef _USE_WARPING
            TEXTURE2D(_WarpTex);
            SAMPLER(sampler_WarpTex);            
            #endif

            CBUFFER_START(UnityPerMaterial)
            half4 _MainTex_ST;
            half4 _MainColor;
            half _MainTex_PannerU;
            half _MainTex_PannerV;
            half _MaskTex_PannerU;
            half _MaskTex_PannerV;      
            half4 _MaskTex_ST;
            half4 _DissolveTex_ST;
            half _DissolveFactor;
            half _DissolveWidth;
            half _WarpFactor;
            half _WarpDeltaTime;
            half _UseCustomData;
            CBUFFER_END

            struct appdata
            {
                float4 vertex : POSITION;
                float4 color : COLOR;
                float4 uv : TEXCOORD0;
                float4 customData1 : TEXCOORD1; //if need Particle System CustomData
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 vertexCol : COLOR;
                float4 uv1 : TEXCOORD0; //MainTex uv
                float4 customData1 : TEXCOORD1;
                #ifdef _USE_MASK
                float2 uv2 : TEXCOORD2; //Mask uv
                #endif
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            #define _BILLBOARD_ON
            v2f EffectVert (appdata v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_TRANSFER_INSTANCE_ID(v, o);
            
                o.vertex = TransformObjectToHClip(v.vertex.xyz);
                o.vertexCol = v.color;
                //half2 uv;
                //GetParticleTexcoords(uv, v.uv.xy);
                o.uv1.xy = TRANSFORM_TEX(v.uv.xy, _MainTex);
                o.customData1 = v.customData1;
                #ifdef _USE_MASK
                o.uv2.xy = TRANSFORM_TEX(v.uv.xy, _MaskTex);
                #endif
                #ifdef _USE_PANNER
                o.uv1.xy += _Time.y * float2(_MainTex_PannerU, _MainTex_PannerV);
                  #ifdef _USE_MASK
                  o.uv2 += _Time.y * float2(_MaskTex_PannerU, _MaskTex_PannerV);
                  #endif
                #endif

                return o;
            }

            half4 EffectFrag (v2f i) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(i);
                #ifdef _USE_WARPING
                half4 noise = SAMPLE_TEXTURE2D(_WarpTex, sampler_WarpTex, i.uv1.xy + _Time.xy * _WarpDeltaTime);
                i.uv1.xy += noise.xy * _WarpFactor;
                #endif
                // sample the texture
                half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv1.xy) * _MainColor;
                col *= saturate(i.vertexCol);
               
                #ifdef _USE_MASK
                //col.rgb = SAMPLE_TEXTURE2D(_MaskTex, sampler_MaskTex,i.uv2);
                col.a = SAMPLE_TEXTURE2D(_MaskTex, sampler_MaskTex,i.uv2).r;
                #endif
               
                #ifdef _USE_DISSOLVE
                half dissolveTex =SAMPLE_TEXTURE2D(_DissolveTex, sampler_DissolveTex,i.uv1.xy);
                //_DissolveFactor = i.uv1.x;
                half dissolveL = _DissolveFactor;
                dissolveL = lerp(_DissolveFactor, i.customData1.x, _UseCustomData);
                dissolveL *= 1 + _DissolveWidth;
                half2 dissolveRange = half2(saturate((dissolveL - _DissolveWidth) ),
                                          saturate(dissolveL ));
                col.a *= smoothstep(dissolveRange.x, dissolveRange.y, dissolveTex);
                #endif
                //clip(col.a-0.01);
                return col;
            }
            ENDHLSL
      }
    }
    CustomEditor "EffectShaderGUI"
}
editor:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class EffectShaderGUI : ShaderGUI
{
    Material Mat;
    MaterialProperty _MainTex, _MainColor;
    bool usePanner;
    bool useMainTexPanner;
    MaterialProperty _UseMainTexPanner, _MainTex_PannerU,_MainTex_PannerV;

    bool useMask, useMaskPanner;
    MaterialProperty _MaskTex, _UseMaskTexPanner, _MaskTex_PannerU, _MaskTex_PannerV;

    bool useDissolve;
    MaterialProperty _DissolveTex, _DissolveFactor, _DissolveWidth;

    bool useWarping;
    MaterialProperty _WarpTex, _WarpFactor, _WarpDeltaTime;

    bool useCustomData;
    MaterialProperty _UseCustomData;

    public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
    {
      this.Mat = materialEditor.target as Material;

      GUILayout.Button("Common Effect Shader");
      //usePanner = useMainTexPanner || useMaskPanner;
      usePanner = Mat.IsKeywordEnabled("_USE_PANNER");

      //Main Texture
      EditorGUILayout.BeginVertical(EditorStyles.helpBox);
      MaterialProperty _MainTex = FindProperty("_MainTex", props);
      materialEditor.ShaderProperty(_MainTex, "Main Texture");
      MaterialProperty _MainColor = FindProperty("_MainColor", props);
      materialEditor.ShaderProperty(_MainColor, "Main Color");

      useMainTexPanner = Mat.GetInt("_UseMainTexPanner") > 0.5 ? true : false;
      useMainTexPanner = EditorGUILayout.Toggle("MainTex UV Panner", useMainTexPanner);
      if(useMainTexPanner)
      {
            usePanner = true;
            Mat.SetInt("_UseMainTexPanner", 1);
            
            _MainTex_PannerU = FindProperty("_MainTex_PannerU", props);
            _MainTex_PannerV = FindProperty("_MainTex_PannerV", props);
            materialEditor.ShaderProperty(_MainTex_PannerU, "Pannar u");
            materialEditor.ShaderProperty(_MainTex_PannerV, "Pannar v");
      }
      else
      {
            Mat.SetInt("_UseMainTexPanner", 0);
            Mat.SetFloat("_MainTex_PannerU", 0.0f);
            Mat.SetFloat("_MainTex_PannerV", 0.0f);
      }
      EditorGUILayout.EndVertical();

      //Mask
      EditorGUILayout.BeginVertical(EditorStyles.helpBox);
      useMask = Mat.IsKeywordEnabled("_USE_MASK");
      useMask = EditorGUILayout.Toggle("Mask", useMask);
      if(useMask)
      {
            Mat.EnableKeyword("_USE_MASK");
            _MaskTex = FindProperty("_MaskTex", props);
            materialEditor.ShaderProperty(_MaskTex, "Mask Texture");

            useMaskPanner = Mat.GetInt("_UseMaskTexPanner") > 0.5 ? true : false;
            useMaskPanner = EditorGUILayout.Toggle("MaskTex UV Panner", useMaskPanner);
            if(useMaskPanner)
            {
                usePanner = true;
                Mat.SetInt("_UseMaskTexPanner", 1);
               
                _MaskTex_PannerU = FindProperty("_MaskTex_PannerU", props);
                _MaskTex_PannerV = FindProperty("_MaskTex_PannerV", props);
                materialEditor.ShaderProperty(_MaskTex_PannerU, "Pannar u");
                materialEditor.ShaderProperty(_MaskTex_PannerV, "Pannar v");
            }
            else
            {
                Mat.SetInt("_UseMaskTexPanner", 0);
                Mat.SetFloat("_MaskTex_PannerU", 0.0f);
                Mat.SetFloat("_MaskTex_PannerV", 0.0f);
            }
      }
      else
      {
            Mat.DisableKeyword("_USE_MASK");
      }
      EditorGUILayout.EndVertical();

      //Dissolve
      EditorGUILayout.BeginVertical(EditorStyles.helpBox);
      useDissolve = Mat.IsKeywordEnabled("_USE_DISSOLVE");
      useDissolve = EditorGUILayout.Toggle("Dissolve", useDissolve);
      if(useDissolve)
      {
            Mat.EnableKeyword("_USE_DISSOLVE");
            _DissolveTex = FindProperty("_DissolveTex", props);
            materialEditor.ShaderProperty(_DissolveTex, "Dissolve Texture");

            //if need ParticleSystem Custom data
            useCustomData = Mat.GetInt("_UseCustomData") > 0.5 ? true : false;
            useCustomData = EditorGUILayout.Toggle("PS CustomData", useCustomData);
            if(useCustomData)
            {
                Mat.SetInt("_UseCustomData", 1);
            }
            else
            {
                Mat.SetInt("_UseCustomData", 0);
                _DissolveFactor = FindProperty("_DissolveFactor", props);
                materialEditor.ShaderProperty(_DissolveFactor, "Dissolve Range");
            }
            _DissolveWidth = FindProperty("_DissolveWidth", props);
            materialEditor.ShaderProperty(_DissolveWidth, "Dissolve Soft Edge");
         
      }
      else
      {
            Mat.DisableKeyword("_USE_DISSOLVE");
      }
      EditorGUILayout.EndVertical();
      
      //Warping
      EditorGUILayout.BeginVertical(EditorStyles.helpBox);
      useWarping = Mat.IsKeywordEnabled("_USE_WARPING");
      useWarping = EditorGUILayout.Toggle("Warping", useWarping);
      if(useWarping)
      {
            Mat.EnableKeyword("_USE_WARPING");
            _WarpTex = FindProperty("_WarpTex", props);
            materialEditor.ShaderProperty(_WarpTex, "Warping Texture");
            _WarpFactor = FindProperty("_WarpFactor", props);
            materialEditor.ShaderProperty(_WarpFactor, "Warping Factor");
            _WarpDeltaTime = FindProperty("_WarpDeltaTime", props);
            materialEditor.ShaderProperty(_WarpDeltaTime, "Speed");            
      }
      else
      {
            Mat.DisableKeyword("_USE_WARPING");
      }
      EditorGUILayout.EndVertical();

      if(usePanner)
      {
            Mat.EnableKeyword("_USE_PANNER");
      }
      else
      {
            Mat.DisableKeyword("_USE_PANNER");
      }

      EditorGUILayout.BeginVertical(EditorStyles.helpBox);
      materialEditor.RenderQueueField();
      EditorGUILayout.EndVertical();

    }
}
有个问题是不知道是我叠加不对还是什么bug,当时用unity的particle system时间轴控制颜色透明度,总觉得最后透明度乘的结果很奇怪,仿佛乘的不是1是255,但是后来又复现不出来这个问题了。。。算了润了。

爆炸效果

年轻的我以为随便做个效果应该很简单吧,拖到ddl前一天晚上才开做。
惨不忍睹的第一版,美术向的mentor看了给我塞了几个视频,好好康康别人咋做的。
左挑右改折腾到晚上三点终于做完了
我爹的评价:感觉不如...页游
美术也太难了!可恶


https://www.zhihu.com/video/1554838298438328320
页: [1]
查看完整版本: 一般通过unity特效shader