Code/AutoRig/Dl/MagicArticulate/MagicArticulateInput.cs

Utility that prepares a point-cloud input for the MagicArticulate pipeline. It samples a RigMesh into an 8192-point surface cloud with normals, scales points to a ±0.9995 range, computes bounding extents and returns a Prepared record containing points, normals and denormalization transforms.

File Access
using AutoRig.Dl.UniRig;
using AutoRig.Mesh;

namespace AutoRig.Dl.MagicArticulate;

using Vector3 = System.Numerics.Vector3;

/// <summary>
/// MagicArticulate's input pipeline (demo.py Dataset): an 8192-point surface
/// cloud with normals, normalized so the max |coordinate| is 0.9995
/// (normalize_to_unit_cube), plus the residual bounds transform the reference
/// uses to denormalize predicted joints. The reference optionally rebuilds the
/// surface with marching cubes first — we sample the raw mesh (documented
/// deviation; the corpus gate validates the outcome).
/// </summary>
public static class MagicArticulateInput
{
    public const int NumSamples = 8192;
    public const float ScaleFactor = 0.9995f;

    public sealed class Prepared
    {
        public required Vector3[] Points;    // in ±0.9995
        public required Vector3[] Normals;

        /// <summary>Undo: world = (p * PcScale + PcCenter) / Scale + Center.</summary>
        public required Vector3 Center;      // normalize_to_unit_cube trans
        public required float Scale;         // normalize_to_unit_cube scale (multiplicative)
        public required Vector3 PcCenter;    // residual bounds of the normalized cloud
        public required float PcScale;
    }

    public static Prepared Prepare( RigMesh mesh )
    {
        ArgumentNullException.ThrowIfNull( mesh );

        // Pure surface sampling (vertexSamples 0) in [-1,1], then × 0.9995 —
        // identical to normalize_to_unit_cube's max-|coord| convention.
        var (points, normals, center, halfExtent) =
            UniRigInput.SampleCloud( mesh, NumSamples, vertexSamples: 0 );
        for ( var i = 0; i < points.Length; i++ )
            points[i] *= ScaleFactor;

        var min = points[0];
        var max = points[0];
        foreach ( var p in points )
        {
            min = Vector3.Min( min, p );
            max = Vector3.Max( max, p );
        }
        var extent = max - min;

        return new Prepared
        {
            Points = points,
            Normals = normals,
            Center = center,
            Scale = ScaleFactor / halfExtent,
            PcCenter = (min + max) * 0.5f,
            PcScale = MathF.Max( extent.X, MathF.Max( extent.Y, extent.Z ) ) + 1e-5f,
        };
    }
}