Momentum

repository·main·Indexed 18 days ago

https://github.com/facebookresearch/momentum

A library providing foundational algorithms for human kinematic motion and numerical optimization solvers to apply human motion in various applications. It includes both Python (pymomentum) and C++ (momentum-cpp) interfaces, featuring utilities for processing optical motion capture marker data and exporting animation from .fbx, .glb, or .gltf files into OBJ mesh sequences.

Tokens
27.4K
Snippets
99
Records
133
Agent score
63%

What's inside pymomentum

  1. Optical Marker based Body Tracking Overview

    main

    The marker_tracker library provides core functions for solving body motions from optical marker inputs. It is compatible with all PC operating systems.

    Key components include:

    • process_markers_app: Solves for body motion given an input marker sequence, supporting both uncalibrated and calibrated workflows.
    • refine_motion: A post-processing tool that runs smoothing to fill in missing data from the input.

    Important Coordinate and Unit Conventions:

    • Units: The ecosystem operates in centimeters (cm). If using C3D files, the system handles conversion based on file metadata. If using the API with custom data, you must manually convert data to cm.
    • Coordinate System: Uses a Y-up coordinate system (note that this differs from the industry-standard Z-up).
  2. What is the pymomentum rasterizer?

    main

    The pymomentum rasterizer is a high-performance, CPU-based software rasterizer designed for batch rendering (e.g., generating MP4 movies) in cluster environments. Unlike GPU-based rendering, it avoids the high cost and energy consumption of cloud GPUs and is designed to be bottlenecked by I/O rather than compute.

    Key features include:

    • Cross-platform: Uses drjit SIMD wrappers for Intel and ARM support.
    • Threadsafe: Releases the Python GIL, allowing for easy multithreaded rendering of multiple frames or images.
    • Zero Dependencies: Runs entirely on the CPU with no OpenGL or GPU requirements.
    • Functional Interface: No global state, providing better error reporting and sensible defaults (e.g., automatic default lighting).
    • Advanced Rendering: Supports per-pixel lighting/shading, texture mapping, ground plane shadows, and per-pixel triangle/vertex IDs.
    • Arbitrary Camera Models: Supports any camera model that implements the interface defined in momentum/renderer/camera.h.
    • Primitives: Supports both 3D primitives and 2D primitives (lines, circles) with depth buffer support.
  3. Choosing between `[]` and `.at()` for array access

    main

    When accessing array elements, choose the method based on the performance and safety requirements of the specific code area:

    • Use [] operator: For low-level, performance-critical, or internal Momentum code. It does not perform bounds checking, offering better performance.
    • Use .at() method: For code exposed to users. It performs bounds checking to prevent out-of-range errors, providing a safer interface for external developers.
  4. Understand the export_objs output format

    main

    The output format depends on whether the input file contains animation data:

    Animation Sequences

    If animation is present, files are named sequentially with zero-padding:

    • 00000.obj, 00001.obj, 00002.obj, etc.

    Static Mesh (No Animation)

    If no animation data is found, a single OBJ file is exported using the input filename:

    • <input_filename>.obj (e.g., character.obj for character.glb)

    OBJ File Contents

    Each file contains:

    • Vertex positions (v lines)
    • Triangle faces (f lines, 1-indexed)

    Note: This exporter does not include texture coordinates, normals, or materials.

  5. Prefer `std::span` for function arguments

    main

    When designing functions that accept contiguous memory, prefer using std::span<T> instead of typed containers like std::vector<T>.

    Why: Using std::vector<T> forces the caller to create a new std::vector instance even if the data is already in a compatible layout. std::span<T> allows the caller to pass existing memory without unnecessary data copies or object construction, improving performance.

  6. Differences in parameter handling between GLB and FBX files

    main

    When using the export_objs logic, the way parameters are applied to the CharacterState differs based on the input file format due to how motion is stored:

    GLB/GLTF Files

    • Loader: loadCharacterWithMotion()
    • Data: Returns motion as a MatrixXf containing model parameters and a separate identity parameter (JointParameters).
    • Parameter Mapping:
      • params.offsets = id (identity parameter)
      • params.pose = motion.col(iFrame) (model parameters)

    FBX Files

    • Loader: loadFbxCharacterWithMotion()
    • Data: Returns motion as a std::vector<MatrixXf> containing joint parameters. Only the first motion is exported.
    • Parameter Mapping:
      • params.pose.v.setZero(0)
      • params.offsets = motion.col(iFrame) (joint parameters)
  7. How the PyPI publishing system works

    main

    The PyPI publishing system for pymomentum-cpu and pymomentum-gpu uses a template-based approach to manage platform and Python version-specific dependencies.

    • Template: pyproject-pypi.toml.j2 (a Jinja2 template containing PyTorch version placeholders).
    • Generator: scripts/generate_pyproject.py (renders the template with specific version constraints).
    • Generated files: pyproject-pypi-cpu.toml and pyproject-pypi-gpu.toml. These are temporary files and must be included in .gitignore.
    • CI workflow: .github/workflows/publish_to_pypi.yml (handles the actual building and publishing of wheels).
  8. Error handling patterns in Momentum

    main

    Momentum uses exceptions as the primary mechanism for handling unrecoverable errors. This ensures errors are detectable and prevents silent failures in low-level code.

    Best Practices:

    • Application Layer: Wrap calls in try-catch blocks to prevent server crashes while capturing error information. This is particularly important for Python users interacting with the library.
    • Flow Control: Do not use exceptions for expected flow control (e.g., do not throw an exception if an "L2 norm is too high").

    Alternative Error Types:

    • std::optional: Used for inputs that may be missing temporarily (e.g., lost tracking) where the specific reason for absence is not critical.
    • folly::Expected: Preferred over std::optional when you need to specify an error type alongside the value, which is useful for APIs where error codes need to be serialized.
  9. PyMomentum version and dependency management

    main

    PyMomentum uses global pinning via conda-forge to ensure compatibility with the ecosystem. This means PyMomentum is automatically built against all pinned PyTorch and CUDA combinations.

    Example Build Matrix: If conda-forge supports PyTorch 2.8 with CUDA 12.9 and 12.6, the feedstock generates:

    • pymomentum-0.2.0-cuda129_py312_* (PyTorch 2.8 + CUDA 12.9 + Python 3.12)
    • pymomentum-0.2.0-cuda126_py312_* (PyTorch 2.8 + CUDA 12.6 + Python 3.12)
    • pymomentum-0.2.0-cpu_py312_* (PyTorch 2.8 CPU + Python 3.12)

    To add support for older dependencies, developers must update recipe/conda_build_config.yaml and submit a PR to the momentum-feedstock repository.

  10. Use depth offset for clearer rendering

    main

    When rendering keypoints or skeletons on top of a mesh, they might be hidden by the mesh's depth. To fix this, use the depth_offset parameter.

    Passing a negative depth_offset (e.g., -15) 'bumps' the object forward in depth, allowing it to be visible through the mesh surface without being completely hidden by it.

    # Render skeleton with a depth offset to see it 'through' the mesh
    pym_renderer.rasterize_skeleton(
        character, skel_state, camera, z_buffer, 
        rgb_buffer=rgb_buffer, 
        style=pym_renderer.SkeletonStyle.Pipes, 
        sphere_radius=1.0, 
        cylinder_radius=0.5, 
        depth_offset=-15, 
        image_offset=np.asarray([300, 0])
    )
  11. How PyMomentum conda packages are released

    main

    PyMomentum follows an automated release process via conda-forge:

    1. Git Tag: Maintainers push a v* tag (e.g., v0.2.0) to the main repository.
    2. Automated PR: The conda-forge bot detects the tag and creates a PR in the momentum-feedstock repository.
    3. Build & Test: CI builds packages for all platforms (Linux, macOS, Windows) and runs tests.
    4. Merge & Publish: Once approved, the PR is merged and packages become available on conda-forge within hours.

    Users can install the resulting packages via conda install -c conda-forge pymomentum.

  12. Understand the NumPy and PyTorch tensor usage in PyMomentum

    main

    PyMomentum uses a mixed approach involving both NumPy arrays and PyTorch tensors. This distinction is based on the following internal convention:

    • PyTorch tensor: Used for differentiable operations.
    • NumPy array: Used for non-differentiable operations.

    Because the codebase is currently transitioning between architectural approaches, you may encounter both types. The project is moving towards stripping PyTorch from certain modules (like pymomentum.geometry) to reduce dependencies and simplify interfaces.

    Current Recommendation: Until the architecture stabilizes, you should perform manual conversions between NumPy arrays and PyTorch tensors as needed for your specific workflow.