Thursday, September 26, 2013

Unity Dust Particle Shader

You can now buy our particle shader on the Unity asset store for $5!

NOTE: If you're seeing WHITE SQUARES, please try adding this line: 
AlphaTest Greater .01
under the line: 
Tags {"RenderType"="Transparent" "Queue" = "Transparent" "IgnoreProjector" = "True"}
See below for more info. I'll release an update to the shader soon with this in there by default. Sorry for the confusion!

We're using Lou's painting as inspiration for our first test shot. I started developing a shader for Unity's particle system to create the close up floaties. The tricky part here was that I had no way of accessing particle ids in the shader, which meant that I couldn't randomize the particles in the shader. I wanted to randomize opacity, color and flashes. I originally tried creating a perlin noise texture look up in screen space based on the particle's screen space position to get a random value for that particle. That works for our purposes since our camera is static. I didn't get very good results with this and instead varied the opacity in the particle system by manually setting Alpha to be 0 or 255 in Color over Lifetime. The varying opacity was used to drive a super bright emission and the color naturally looked random because of the different opacities.  

o.Emission = lerp(0,_Emission, smoothstep(_FlashSpeed,1,o.Alpha));

 My dust motes are made up of two particle systems: Large blurry dust and micro dust.

Large Blurry Dust
For the coloration, I wanted to create a "photographic" look. I looked a lot at images like these I found on google:

Even though the overall mote looks circular, it is actually a cutout of an imperfect circle texture I painted. This just adds a subtle randomness to all of them as they slowly spawn and rotate (I think anyway).

if(_DoShape)
    o.Alpha = o.Alpha*tex2D(_Shape,IN.uv_Noise.xy).r;
//otherwise make a circle
else{
    if(dist>=.5)
o.Alpha = 0;
}

I wrote a function to create a bright yellow ring near the edge of the particle that fades toward the center. As it fades, the color turns bluish.

float dist = distance(IN.uv_Noise.xy, float2(.5,.5));
if(dist<(.5-_Blur)){
    o.Alpha = o.Alpha*max(1.0*pow(dist/(.5-_Blur),2),(1-_Transparency));
    //add a shadow color as the particle fades
    o.Albedo = lerp(_ShadowColor.rgb, o.Albedo,o.Alpha);

}  

Finally, I have a noise on top that creates some pink speckles for a low resolution pixelated look.

o.Albedo = lerp(o.Albedo,_Speckles.rgb,tex2D(_Noise,(IN.uv_Noise.xy*.1+_Time*.01)).r);

As as bonus, I created a custom lighting model for these dust motes which simulates light scattering through them.

half4 LightingParticle(SurfaceOutputCustom s, half3 lightDir, half3 viewDir, half atten) { 
    half4 c;  
    c.rgb = s.Albedo;
    c.a =lerp(0,s.Alpha, 1-saturate(dot(normalize(viewDir), lightDir)));
    return c;
}

NOTE the lighting model does not work with multiple lights and can result in the particles looking blown out, or white. Since the particles are alpha mapped billboards, they will look like white squares. There are a couple ways to fix this. One is to add "alpha" to the pragma surface line. This basically overrides the lighting model (for whatever reason):

#pragma surface surf Particle alpha

If you want to preserve the ability to have a light source create a scattering effect, add the following line:
AlphaTest Greater .01
under the line: 
Tags {"RenderType"="Transparent" "Queue" = "Transparent" "IgnoreProjector" = "True"}
I believe the first light that was created in the scene is the only light that can create the scattering effect.

Micro Dust
This one was much simpler. Basically white and the cutout is an irregular polygon texture.

And here is my result:
If nothing loads, watch with Vimeo or try installing Unity Player .

Dabble #1 Realtime Forest Sprite


We work in the animation industry and we know how much it sucks to wait for renders to come back. So we're embarking on a little experiment. Inspired by Square-Enix's "Agni's Philosophy" and Unity's "Butterfly Effect", we want to see if we can create a near film quality shot/test/short in "real-time" in our free time. For this project, we are using Maya to create assets and set dress to a camera and Unity for shading, lighting, and rendering.

 Our test idea is centered around a tiny forest sprite running across a fallen log. This sprite actually came from a game idea we had but shelved because of our lack of DirectX11 (We're using Macs). Here are some initial artworks for the sprite. We are actually pretty far along on this project already (we've only spent 2 weekends so far), but we'll update the blog with pipeline scripts and pretty shaders we had to develop.