Search Unity

[Share Knowledge] How to make 3d animate particle effect

Discussion in 'Shaders' started by NathanJSmith, Oct 5, 2018.

  1. NathanJSmith

    NathanJSmith

    Joined:
    May 11, 2018
    Posts:
    57
    I. Introduction
    I've successfully created animate particle effect, so I decided to share this for those who need it.
    Special Thanks to Hironori Sugino for sharing his incredible Animation-Texture-Baker, and to Unity for creating Custom Vertex Stream.

    II. Method
    The method is: animate the 3d mesh with shader, the shader will read the animate information from an image.
    This shader will work with Custom Vertex Stream of Particle Effect.
    To really understand how to make it work, you need to learn a little about Shader:
    https://docs.unity3d.com/Manual/PartSysVertexStreams.html
    https://docs.unity3d.com/Manual/ShadersOverview.html
    https://docs.unity3d.com/Manual/SL-ShaderPrograms.html
    https://unity3d.com/learn/tutorials/topics/graphics/gentle-introduction-shaders
    https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
    https://docs.unity3d.com/Manual/SL-BuiltinFunctions.html
    https://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html
    https://docs.unity3d.com/Manual/SL-ShaderSemantics.html
    https://docs.unity3d.com/Manual/SL-ShaderPrograms.html

    I'll assume you understand how shader, material & particle effect work.

    III. Let's get to work
    Step 1: Download and play around with Animation-Texture-Baker: https://github.com/sugi-cho/Animation-Texture-Baker

    Step 2: Make a copy of the file TextureAnimPlayer.shader . Then rename it into SimplePfx.shader (or anything you like, in this article, I gonna call it SimplePfx), then open the file SimplePfx.shader, we really get to work now.

    Step 3: Working with SimplePfx
    Replace all the content of SimplePfx.shader with the code below:
    Code (CSharp):
    1.  
    2. Shader "GTA/SimplePfx" {
    3.    Properties
    4.    {
    5.        _MainTex ("Texture", 2D) = "white" {}
    6.        _PosTex("position texture", 2D) = "black"{}
    7.    }
    8.    SubShader
    9.    {
    10.        Tags { "RenderType"="Opaque" }
    11.        //LOD 100 Cull Off
    12.  
    13.        Pass
    14.        {
    15.            CGPROGRAM
    16.            #pragma vertex vert
    17.            #pragma fragment frag
    18.  
    19.            #include "UnityCG.cginc"
    20.            #pragma multi_compile_instancing
    21.            #define ts _PosTex_TexelSize
    22.  
    23.            struct appdata_t
    24.            {
    25.                float4 vertex : POSITION;
    26.                float4 texcoord : TEXCOORD0;
    27.                float4 texcoord1 : TEXCOORD1;
    28.            };
    29.  
    30.            sampler2D _MainTex, _PosTex;
    31.            float4 _PosTex_TexelSize;
    32.      
    33.            float3x3 XRotationMatrix(float sina, float cosa)
    34.            {
    35.                return float3x3(
    36.                    1,   0,       0,
    37.                    0,   cosa,   -sina,
    38.                    0,   sina,   cosa);
    39.            }
    40.      
    41.            float3x3 YRotationMatrix(float sina, float cosa)
    42.            {
    43.                return float3x3(
    44.                    cosa,    0,   -sina,
    45.                    0,        1,   0,
    46.                    sina,    0,   cosa);
    47.            }
    48.      
    49.            float3x3 ZRotationMatrix(float sina, float cosa)
    50.            {
    51.                return float3x3(
    52.                    cosa,    -sina,   0,
    53.                    sina,    cosa,   0,
    54.                    0,        0,       1);
    55.            }
    56.      
    57.            appdata_t vert (appdata_t v)
    58.            {
    59.                float x = (v.texcoord.z + 0.5) * ts.x;//VertexID & Size of bake anim texture
    60.                float y;
    61.  
    62.                y = fmod(_Time.y, 1.0);//Loop animation
    63.  
    64.                float4 pos = tex2Dlod(_PosTex, float4(x, y, 0, 0));
    65.                pos += v.vertex;
    66.          
    67.                float rotAngle = v.texcoord1.x * 1000;
    68.                //Convert to radian
    69.                rotAngle *= 0.01745329251994329576923690768489;//rotAngle * UNITY_PI / 180.0
    70.                //Calculate sin cos
    71.                float sina, cosa;
    72.                 sincos(rotAngle, sina, cosa);
    73.          
    74.                float randRot = (v.texcoord.w + v.texcoord1.x);
    75.                float3 pivot = v.texcoord1.yzw;
    76.          
    77.                //Move to root
    78.                pos.xyz -= pivot;
    79.          
    80.                //Rotate
    81.                pos.xyz = mul(YRotationMatrix(sina, cosa), pos.xyz);
    82.          
    83.                if(randRot > 1)
    84.                    pos.xyz = mul(XRotationMatrix(sina, cosa), pos.xyz);
    85.                else
    86.                    pos.xyz = mul(ZRotationMatrix(sina, cosa), pos.xyz);
    87.          
    88.                //Move it back
    89.                pos.xyz += pivot;
    90.  
    91.                appdata_t o;
    92.                o.vertex = UnityObjectToClipPos(pos);
    93.                o.texcoord = v.texcoord;
    94.                return o;
    95.            }
    96.      
    97.            half4 frag (appdata_t i) : SV_Target
    98.            {
    99.                return tex2D(_MainTex, i.texcoord.xy);
    100.            }
    101.            ENDCG
    102.        }
    103.    }
    104. }
    105.  
    Note for the shader
    Animate the character: to make it work with Particle System, I use Custom Vertex VertexID.
    Randomly rotate character: to understand the rotate part, read my other post.

    Step 4: Create a material for the shader


    Step 5: Create a Particle System and setup the Render of Particle System:
    Render Mode: Mesh
    Mesh: The mesh of yours
    Material: The material from step 4
    Render Alignment: World
    Custom Vertex Stream: Position, UV, VertexID, StableRandom.xy, Center


    Step 6: And the results are...




    Enjoy the 3d animate particle effect :D
     
    Last edited: Mar 23, 2020
  2. Rand_D

    Rand_D

    Joined:
    Oct 24, 2017
    Posts:
    44
    Just a head up, in Unity 2019.4, the center has been switched to TEXCOORD0.w|xy so the pivot in the shader code should be:
    Code (CSharp):
    1. float3 pivot = float3(v.texcoord.w, v.texcoord1.x, v.texcoord1.y);
     
  3. dknauss1

    dknauss1

    Joined:
    Feb 9, 2022
    Posts:
    2
    Any updates to this kind of thing? It's 2022 now, and this is still the best option I have to create a particle animation and have it export to a format that will work when embedded in html? It blows my mind. I mean, what in the world do they do for actual games, if not make it possible to say... flow some xenon gas through a tube? I don't get life anymore.
     
    DungDajHjep likes this.