Solver that rigs an organic character mesh. It voxelizes the mesh, extracts a curve skeleton, detects body category and symmetry, optionally maps to a humanoid/quadruped/winged template, builds a skeleton, computes skinning weights, and returns a RigResult.
using AutoRig.Analyze;
using AutoRig.Rig;
using AutoRig.Solve.Organic;
using AutoRig.Voxel;
namespace AutoRig.Solve;
/// <summary>
/// Rigs a creature/character: voxelize, extract the curve skeleton, detect the body
/// category, snap humanoids to the citizen-compatible template (generic graph rig
/// otherwise), and skin with geodesic voxel weights. Hybrid meshes run through the
/// same volume (rigid attachments merge into it and bind to the nearest bones).
/// </summary>
public static class OrganicSolver
{
public static RigResult Rig( AnalysisResult analysis )
{
ArgumentNullException.ThrowIfNull( analysis );
var resolution = analysis.Mesh.TriangleCount < 50_000 ? 96 : 64;
var grid = VoxelGrid.Build( analysis.Mesh, resolution );
var graph = CurveSkeleton.Extract( grid );
var bounds = analysis.Mesh.ComputeBounds();
var (category, _, why) = CategoryDetector.Detect( graph, analysis.Symmetry, bounds );
RigSkeleton? skeleton = null;
var usedTemplate = false;
if ( analysis.Symmetry is { } symmetry )
{
skeleton = category switch
{
OrganicCategory.Humanoid => HumanoidTemplate.Build( graph, symmetry, bounds ),
OrganicCategory.Quadruped => QuadrupedTemplate.Build( graph, symmetry, bounds ),
OrganicCategory.Winged => WingedTemplate.Build( graph, symmetry, bounds ),
_ => null,
};
usedTemplate = skeleton is not null;
}
skeleton ??= GraphSkeletonBuilder.Build( graph );
var weights = OrganicSkinner.Skin( analysis.Mesh, grid, skeleton );
var result = new RigResult
{
Skeleton = skeleton,
Weights = weights,
SolverName = "organic",
Degraded = false,
Explanation = usedTemplate
? category == OrganicCategory.Humanoid
? $"Humanoid detected - citizen-compatible skeleton ({skeleton.Joints.Count} joints)."
: $"{category} detected - anatomical skeleton ({skeleton.Joints.Count} joints)."
: $"{category} body ({why}) - {skeleton.Joints.Count}-joint skeleton from the volume centerline.",
};
result.Skeleton.Validate();
result.Weights.Validate( analysis.Mesh, result.Skeleton );
return result;
}
}