## Sunday, October 14, 2012

### Distortion-Free Flip Operator for Lattices

There's nothing quite like a feature written to a scratch a particular itch... especially one for one of your own itches when actually working on stuff (vs thinking through how someone might work on stuff ;)

I've just committed such a feature for lattice editing. It's an improved tool for mirroring lattices, without the problems of the traditional mirror operator

Inspiration

While working on Tweedle, I found that it's currently difficult to mirror lattices without side-effects. Namely, if you use Ctrl-M to mirror a lattice, it's going to invert the lattice's deform-space while it goes about flipping the verts to give you the intended cage shape. This causes "Bad Things" (TM) to happen:

As can be seen, meshes can end up disappearing, because their normals are inverted by the inverted lattice deform, leading to these being treated as backfaces.

But even if you don't get such artifacts, trying to transform objects deformed by the lattice will be difficult. That's because the objects will now be in "crazyspace". It can be really tricky and counter-intuitive to do (e.g. rotate in opposite direction by asymmetric amounts to get desired result)

Lattice Flip Operator
To solve this problem, I coded up a smarter flip tool for lattices which understands that the order of lattice vertices matters. That is, you can't just swap coordinates or mirror them across invisible mirror lines while leaving those vertices in the same order in the lattice's control point voxel-grid. That will merely invert everything, which to outward appearances is fine, but when deforming leads to all hell being let loose.

The way this operator works is it computes the midpoint (mirror line) for all coordinates on one of its component "axes" (NOTE: lattices call their "XYZ" axes "UVW". As far as I can tell, these are equivalent an aligned with each other.) We then go through swapping pairs of vertices (outside-in, ith from each side along the flipping axis):

 The swapping process (steps u=1,2) and mirror on odd (u = "3(ms)"). This is shown for one "w" layer of the lattice - it repeats in much the same way for the other w layers of the lattice

However, in addition to simply swapping the points, once we've got the points where we need them to be, we need to "mirror" these values across the midpoint we calculated earlier. This step is essential for ensuring that we don't simply reimplement the mirror operator: without it, we still get a mismatch of coordinates. Let's see an example:

As we can see, after swapping, there is a mismatch (shown with arrows from u indices pointing towards the coordinate with the sign that they should go to) where small u-indexed verts have big/positive coordinates, whereas large u-indexed verts have small/negative coordinates. This causes our inversion problems. To fix, we "mirror" these points once they're where they are so that they have the right "sign" and/or are on the right side.

Comparison Between Flip and Mirror
Let's have a look at the difference between using our flipping technique and traditional mirroring, to confirm that I'm not just making all these problems up:

Firstly, here is the mesh deformed after applying U-Flip (see image at top of post for original mesh/lattice configuration):

Nothing much to see here really. Lighting looks nice/flat/standard.

Now, let's see the mesh deformed after applying X-Mirror:

We clearly have some artifacts here, and some rather peculiar shading. However, if you were just looking at the lattice cage, you wouldn't know that anything was wrong.

Usage Notes
So, how do I use this?
There are two ways to invoke this:
1) Ctrl-F in Lattice Edit Mode

What can I use it for?
1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored.
2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig.
3) Be creative!

Things to be aware of:
- It currently ignores select status of lattice verts. Since we're dealing with pairs of vertices, if we implemented selection-masking, then you'd probably have to select both to get this to work. Plus, it doesn't seem too useful to do so. Please squawk if that's not the case ;)

Oh, and here's a little the test file for the above.