Sunday, May 28, 2017

unity - How can I create a radial animation that hollows out a shape from the inside?


I want to create the radial/circular animation seen in the explosions in this .gif of Flat Heroes.


I made an image using Illustrator of a radial ring (as below), but I'm not sure if this is the right approach. How can this be done?


Also, I would like to know how this could be extended to make similar animations for other shapes like squares and triangles.



Ring created in Illustrator



Answer



For a circular cutout we can do this with a little radius math and no textures at all. But since you mention wanting to extend to squares and triangles, I'll show a more general approach.


Animated particle system with star-shaped particles that wipe away from the inside.


First we create a texture in the shape we want, with a gradient falloff toward the interior. This gradient should follow the shape of the perimeter - we'll use it to control the shape of the inner cutout. For a circle, this can be a simple radial gradient.


Star-shaped gradient, white at the perimeter of the star and dark grey at the center.


Next we write a shader that reads this texture, as well as a threshold parameter, and displays only parts of the gradient that are brighter than the threshold as opaque, and everything darker as translucent, like so:


Shader "Unlit/RadialParticle"
{
Properties

{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
// Treat this material as transparent
Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True" }
LOD 100

// Set up alpha blending

ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"


struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
// Vertex color field
// (used by the particle system to tint)
fixed4 color : COLOR0;
};


struct v2f
{
float2 uv : TEXCOORD0;
// Pass through color information to fragment
fixed4 color : COLOR0;
float4 vertex : SV_POSITION;
};

sampler2D _MainTex;
float4 _MainTex_ST;


v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
// Pass our color parameter through to the fragment
o.color = v.color;
return o;
}


fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);

// Hide any part of the image that's darker than
// the _Cutout parameter
col.a = saturate((col.r - i.color.a) * 10.0f);

// Replace the visible color of the image

// with the particle color
col.rgb = i.color.rgb;

return col;
}
ENDCG
}
}
}


Attach your shader to a material and configure it with your gradient texture and you're off to the races. :)


Here I've configured the shader to work in a particle system, reading the threshold from the vertex colour's alpha channel. That let me use the particle system's "Color Over Lifetime" curves to create the animation above quickly.


If you need to do this with just a single quad, you could instead expose _Cutout material parameter, and vary that material property via script.


Shader "Unlit/RadialSprite"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = 1, 1, 1, 1
_Cutout ("Cutout", Range(0, 1)) = 0.5

}
SubShader
{
// Treat this material as transparent
Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True" }
LOD 100

// Set up alpha blending
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha


Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct appdata

{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};


sampler2D _MainTex;
float4 _MainTex_ST;
// Add shader variables for our material properties.
fixed4 _Color;
float _Cutout;

v2f vert (appdata v)
{
v2f o;

o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}

fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);

// Hide any part of the image that's darker than

// the current alpha value of the particle color
col.a = saturate((col.r -_Cutout) * 10.0f);

// Replace the visible color of the image
// with the material color
col.rgb = _Color.rgb;

return col;
}
ENDCG

}
}
}

In my examples all the displayed colour is coming from the particle system / material parameters, but you could just as easily have colour detail in your texture, and store the cutout gradient in the alpha channel.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...