Saturday, November 30, 2013

Models

I activated my 30 day Unity Pro trial license a few days ago so we're frantically trying to finish this forest sprite demo. While Lou is coding like mad, I am going to share some of our models with you. We are using Maya 2013 to build and rig (where necessary) our assets. We are using Photoshop and Mari to texture our character and Unity to shade our assets. In Unity we have actually created our own "uber shader" which almost all of our assets are currently using. For now, the modeling.

Here's our set from our main camera with all of our assets referenced into a scene and dressed according to our artwork. The green bits are maya joints for some vegetation that will have some wind animation in Unity.


Here is the same set from a different camera to show our hackery. The beauty of working in context is that we can shape all of our dressing to our camera.

The log is detailed where it needs to be and sparse everywhere else

This is one of the flowers that also has a skeleton bound to it.


This is our forest sprite character. We are using our cache exporter and importer to bring our animation into Unity. 

Wednesday, November 20, 2013

Moss Shader

We wanted some soft "texture" in our scene to make it more inviting and organic, so in envisioning the scene we decided we ought to add some cushy moss to the fallen log.

To reiterate - we're using Unity on a mac - so we don't have access to DirectX 11's tessellation support to grow isoline fur or anything like that.  The tried and true method in games prior to that technology has been to implement a shell/fin method - but we wanted to take that idea a step further.

A simple 3 pass shell extrusion shader.

In order to have decent-quality fur using the method mentioned above, you need a significant number of shells, each serving as a cross section of the fur volume (which in Unity would each require a separate draw call per sub shader, since we'd prefer to do all the extrusion using the vertex program).  This can bring down performance, requires a lot of redundant code, and a long compilation cycle.

I want to keep the draw call count low per model, so instead I chose to integrate the effects of multiple cross-section layers in only one layer.  This essentially turns into a ray casting problem.

Rather than spend a bunch of shader instructions writing the ray casting itself, I hijacked another popular shading concept called parallax mapping.

Essentially, naive parallax mapping allows for a texture to seem "deeper" inset into the surface being shaded, as a function of a height map.  If you replace the height map value with a constant, you can set the entire texture a certain "depth" into the material.  Do this enough times with linear varying depths, and integrate things such as opacity, surface normal, root-tip color, etc in a loop, and you get a holographic ray-marched-esque shader of the fur volume.

In pseudocode:
for each iteration
{
shift uv by ParallaxOffset(0, depth*iteration/numIters, viewDirection);
look up cross section tex2d(tex, shiftedUV);
integrate tinted texture over length with root&tip color;
integrate alpha over length with root&tip opacity;
integrate normal from tex2D(NormalMap, shiftedUV);
}
normalize(Normal);

With 30 iterations and 1 draw call you can achieve the look of 30 shells.

One shortcoming of naive parallax mapping is that you don't have true silhouette edges.  This could be solved by implementing relief mapping.  Instead I opted to AlphaTest anything lower than a certain fixed value, allowing for blades of moss and grass to be clipped.

Clumping was also achieved by additionally offsetting the uv value at the tip by some smoothly varying vectors, encoded in a normal map generated from tiling FBM.  Same goes for keep alive/wind.

Gross directionality changes and density are attenuated via vertex colors = (tangentShift, bitangentShift, 0, density).


Resulting hologram moss.

Friday, November 1, 2013

Colored Shadows in Unity

Sometimes you just want to colored shadows.  It may not be physically correct, but perhaps you're making a stylistic choice.  Unfortunately our options are limited.   Unity's Ambient Light is a global concept, so if you want to add colored shadows on a per-material basis for fine grain control, you probably need to implement it in your shader.

In order for our forest to feel more organic, I made some adjustments to all of our custom shaders - a very simple addendum within our lighting models.

Let's start with standard lambert irradiance.

c.rgb = s.Albedo * saturate(NdotL) * atten;

There are two things happening here, we're diminishing the color of the material by the diffuse component (saturate(NdotL)), as well as the combined factor of the surface's distance to the light source and whatever cast shadows are occurring (atten).  Both of these are 0->1 values.  This is what that looks like:


With all that black we lose a lot of contextual information.

Let's add some terms to our lighting to make it more interesting.

c.rgb = (s.Albedo * saturate(NdotL) + s.Albedo * _ShadowColor.rgb * (1-saturate(NdotL))) * atten
+ s.Albedo * _ShadowColor.rgb * (1-atten);


Since both the diffuse and attenuation/shadow components map 0->1 as "in shadow"->"in light", we can remap them, multiply against a per-material _ShadowColor, and add the result back into the mix.  Now colors that used to be crushed to (0,0,0) are (_ShadowColor.r,_ShadowColor.g,_ShadowColor.b), and our whites are preserved:


Per-material colored shadows for optimal control.