Mighty Morphin'

Saturday, February 21, 2015 at 9:45 PM

Adorkable Games in devlog, fantasticjack, fantasticjack

Adorkable Games in devlog, fantasticjack, fantasticjack

Since Fantastic Jack takes place in the intersection between reality and fantasy, we've been focusing on developing a style for visually blending between the two. A few weeks ago I explained how we plan to blend between different sky backgrounds. It turns out that our sky backgrounds are particularly conducive for this sort of thing, since they're so amorphous. Simply crossfading between two painted skies accomplishes most of what we need, although we will eventually add movement, like the clouds drifting or the sun and moon rising and setting.

However, our game also has vehicles, like the bicycle that becomes a snowmobile on the icy tundra, as you may remember from our initial announcement. While similar in terms of their structure--both have handlebars and seats, as well as two points of contact with the ground--these particular vehicle variations have distinctly different silhouettes. Crossfading would not be sufficient, so I decided to try morphing!

Morphing between two images is a combination of crossfading while distorting the shapes of both images. The objective is to match up similar features in both images so that they end up overlapping even if they were originally in different places.

The first step is to manually add control points on top of both images, where each point on one image corresponds to one point on the other image. Then all we would need to do is run the automatic morphing algorithm! Unfortunately, however, we didn't have a morphing algorithm already in our toolbox, so for us the second step was writing it.

The algorithm needs to generate two displacement fields, one for each image. When an image is fully faded in, it doesn't need to use the displacement, but the more it fades out, the stronger the displacement needs to be. So, after it's fully faded out, the initial image would take roughly the shape of the other image. This displacement field should actually be generated for the fully-faded-out condition. In other words, given a target point on the second image, how far away are the source pixels that we sample from the first image? We also need to smoothly blend the displacement in between the control points. This smooth blending is the hard part.

To generate a smooth displacement field, we start by iterating over every pixel. To mix the influences of the control points that are nearest to this pixel, we need to compute a kind of weighted average. So for each pixel, we iterate over every pair of control points, and for each pair of control points, we subtract the target point from the source point to obtain this pair's displacement offset. Next, to figure out the weight of this pair's influence, we compute the distance from this pixel to the **target** point. I picked the formula 1/distance^2 to convert this distance to a weight value, and then I add this to a sum of the weight values for all control points, and I also sum all of the displacement offsets multiplied by their weight values. Finally, I divide the offset sum by the weight sum to get the blended displacement offset for this pixel. In pseudocode, the algorithm looks like this:

```
```

```
Vector2 pixelPos = ( pixelX, pixelY )
```

Vector2 displacementSum = ( 0, 0 )

float weightSum = 0

for each pair (Vector2 sourcePoint, Vector2 targetPoint) from controlPoints:

Vector2 pointDisplacement = sourcePoint - targetPoint

float distance = length( targetPoint - pixelPos )

float weight = 1 / ( distance * distance )

weightSum += weight

displacementSum += pointDisplacement * weight

Vector2 finalDisplacement = displacementSum / weightSum;

```
```

If we display the displacement fields generated by this algorithm using red to indicate x-axis offsets and green to indicate y-axis offsets, we end up with this abstract art:

On the other hand, if we skip the crossfading and just apply the displacement to the source images, we get this DalĂ-esque surrealism:

Combining the displacement and the crossfade together, we get this cute little animation:

There's definitely a lot of work left to do to clean this up, but I'm pretty happy with my first attempt at morphing, and this technique will surely be useful to us.

--John

Article originally appeared on Adorkable Games (http://www.adorkablegames.com/).

See website for complete article licensing information.