Friday, October 25, 2013

Procedural Wind Effects in Unity

Rather than animating and cacheing a bunch of flower bending by hand, we wanted to create some wind procedurally. This wind is simply for "keep alive," or, to add some subtle movement so our scene does not look completely static and CG. In order to do this, the flowers were rigged, and three scripts were written: WindSim, WindObject, and AssignIDs.

WindSim 

The WindSim script is attached to any flower or object that has a rig and wants to be simmed. The object "wants" to be simmed if it is specifically tagged in the inspector. This allowed us the ability to turn off simulation easily rather than removing the script entirely from the object. WindSim does the actual moving of the joints and takes in a direction from WindObject. WindSim has attributes such as strength and animation offset to vary the wind motion from object to object. Here is the noise function we came up with:

(Mathf.Pow(Mathf.Tan(Mathf.Sin(Time.time+AnimOffset*id))/2.0f,4f)-.1f)*10F*Mathf.PerlinNoise(Time.time/2F,Time.time/2F);

Inigo Quilez's Graph Toy or the Grapher tool for Macs are really helpful tools to come up with interesting noise functions. This is the function visualized with Graph Toy:


WindObject

WindObject is attached to an empty gameObject and serves as a global way of controlling the direction of the wind as well as other parameters. The direction is just based on the gameObject’s directional vector. We have a simple Gizmo line drawing in the direction of the wind which is visible in the scene view. Like WindSim, WindObject also has strength, flexibility, and animation offset attributes that are passed to WindSim initially by default. If any of these attributes are set in WindSim, then they override WindObject’s settings.

Here's a screenshot of our WindObject selected. The yellow line tells us which direction the wind is blowing.

Object IDs 

We created AssignIDs as an editor script to add some randomization for each simmable object, . It looks for all simmable objects in the scene and incrementally assigns an id to each of the objects.

Here's an example of our wind in action.


If nothing loads, try installing Unity Player
The result is a globally controllable wind sim with the ability to tweak the look of each simmed object if necessary.

Thursday, October 10, 2013

Cache, Money

One requirement of our realtime effort is that we be able to achieve film-quality animation within Unity.  The current release doesn't support blend shapes, and even if it did, we'd want to leave ourselves some room to use other deformer solutions, as well as allow the animation to come from any arbitrary 3rd party package one could imagine.  The industry's standard answer to a problem like this is to point cache the scene data.

At this time, Unity also does not support caches.  So!  We have to make our own, or buy something someone else has made.  We're frugal, so we made our own.

The concept is simple - store non frame-varying data once (triangles, uvs), and frame-varying data once per frame (vert positions, normals), in some text file, and construct a parser in Unity to build out the resulting mesh, predicated upon a frame in the range you wish to animate.

One problem though...

Unity uses a different coordinate system than most other 3d packages.  As an example, we're using Maya for our asset creation - and it happens to use a Right Handed Coord-Sys, whereas Unity uses a Left Handed Coord-Sys.

In practice all our positional and directional vectors (i.e. vertex positions and normals) have to be flipped (*-1) in the x-axis (or "right" vector).  But that's not enough!  If you were to only scale, all your normals would be inverted, so you must take care to also reverse the winding-order of your triangles upon export.



The winding-order simply defines what is considered the "front-face" or "back-face" of a polygon, and its really just what it sounds like - the order in which the vertices are listed in the polygon's array.  By reversing the winding-order, you effectively flip the face normal, and now all is right in the world.

What's fantastic about these two simple observations is that (as far as I can tell) this is exactly what's happening within Unity's Maya Scene Importer.  Now anything statically imported from Maya through Unity's traditional pipeline will match perfectly with anything dynamically cached!