mono/MonoGame — pull request #3331 by mgarstenauer (2014-12-29 16:33:31+00:00)
Title: Fix MeshHelper.TransformScene()

In the current implementation `MeshHelper.TransformScene` only transforms mesh data. Local transforms, animations, are ignored.

This commit adds the following fixes:

- All nodes in the scene need to be transformed using a "similarity transform". (For example, imagine a model with two separate mesh nodes: A character holding a gun. The model was exported with z-up (3dsmax), but XNA requires y-up. A -90° around the x-axis needs to be applied. If `TransformScene` only rotates the meshes then gun would no longer be attached to the character. `TransformScene` needs to rotate the meshes and correct the local transforms.)
- Animations need to be transformed as well. (Same principle.)
- Normals need to be transformed with the transpose of the inverse. This is relevant when non-uniform scaling is applied. (`Vector3.TransformNormal` doesn't automatically invert/transpose the transform. `TransformNormal` only means that the translation is ignored.)
- When the transform is mirroring the mesh, the winding order needs to be swapped.

I also simplified lines like these

channel.Items.CopyTo(geomBuffer, 0);
Vector3.TransformNormal(geomBuffer, ref xform, geomBuffer);
channel.Items.Clear();
foreach (var item in geomBuffer)
channel.Items.Add(item);

to

for (int i = 0; i < vector3Channel.Count; i++)
vector3Channel[i] = Vector3.TransformNormal(vector3Channel[i], inverseTranspose);

The second version is easier to maintain. (I assume the original author tried to optimize the operation. But I doubt that the original code is any faster. It requires more heap memory allocations/copies. When `channel.Items.Add(item)` is called each individual Vector3 needs to be boxed/unboxed!)