Showing preview only (1,726K chars total). Download the full file or copy to clipboard to get everything.
Repository: nv-tlabs/kimodo
Branch: main
Commit: 54257dd8ff18
Files: 320
Total size: 1.6 MB
Directory structure:
gitextract__xaaoo6k/
├── .gitignore
├── .pre-commit-config.yaml
├── ATTRIBUTIONS.MD
├── CHANGELOG.md
├── CONTRIBUTING.MD
├── Dockerfile
├── LICENSE
├── MANIFEST.in
├── MotionCorrection/
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── MANIFEST.in
│ ├── README.md
│ ├── python/
│ │ └── motion_correction/
│ │ ├── __init__.py
│ │ └── motion_postprocess.py
│ ├── run_test.py
│ ├── setup.py
│ └── src/
│ └── cpp/
│ ├── AnimProcessing/
│ │ ├── InverseKinematics.cpp
│ │ ├── InverseKinematics.h
│ │ ├── TrajectoryCorrector.cpp
│ │ ├── TrajectoryCorrector.h
│ │ ├── Utility.cpp
│ │ └── Utility.h
│ ├── BindingsPython.cpp
│ ├── Compiler.h
│ ├── Debug.h
│ ├── Math/
│ │ ├── Constants.h
│ │ ├── Matrix.cpp
│ │ ├── Matrix.h
│ │ ├── Matrix.inl
│ │ ├── Quaternion.cpp
│ │ ├── Quaternion.h
│ │ ├── Quaternion.inl
│ │ ├── SIMD.h
│ │ ├── Scalar.h
│ │ ├── Transform.cpp
│ │ ├── Transform.h
│ │ ├── Transform.inl
│ │ ├── Types.cpp
│ │ ├── Types.h
│ │ ├── Vector.cpp
│ │ ├── Vector.h
│ │ └── Vector.inl
│ └── Platform.h
├── README.md
├── benchmark/
│ ├── create_benchmark.py
│ ├── embed_folder.py
│ ├── evaluate_folder.py
│ ├── generate_eval.py
│ └── parse_folder.py
├── docker-compose.yaml
├── docker_requirements.in
├── docker_requirements.txt
├── docs/
│ ├── .gitattributes
│ ├── Makefile
│ ├── README.md
│ ├── make.bat
│ ├── requirements.txt
│ └── source/
│ ├── _static/
│ │ └── custom.css
│ ├── _templates/
│ │ └── apidoc/
│ │ ├── module.rst.jinja
│ │ └── package.rst.jinja
│ ├── api_reference/
│ │ ├── _generated/
│ │ │ ├── kimodo.demo.rst
│ │ │ ├── kimodo.exports.rst
│ │ │ ├── kimodo.metrics.rst
│ │ │ ├── kimodo.model.llm2vec.models.rst
│ │ │ ├── kimodo.model.llm2vec.rst
│ │ │ ├── kimodo.model.rst
│ │ │ ├── kimodo.motion_rep.reps.rst
│ │ │ ├── kimodo.motion_rep.rst
│ │ │ ├── kimodo.rst
│ │ │ ├── kimodo.scripts.rst
│ │ │ ├── kimodo.skeleton.rst
│ │ │ ├── kimodo.viz.rst
│ │ │ └── modules.rst
│ │ ├── constraints.rst
│ │ ├── exports.rst
│ │ ├── index.rst
│ │ ├── model.rst
│ │ ├── motion_rep.rst
│ │ ├── post-processing.rst
│ │ ├── utilities.rst
│ │ └── viz.rst
│ ├── benchmark/
│ │ ├── introduction.md
│ │ ├── metrics.md
│ │ ├── pipeline.md
│ │ └── results.md
│ ├── conf.py
│ ├── getting_started/
│ │ ├── installation.md
│ │ ├── installation_docker.md
│ │ ├── installation_smpl.md
│ │ ├── installation_virtual_env.md
│ │ └── quick_start.md
│ ├── index.md
│ ├── interactive_demo/
│ │ ├── constraints.md
│ │ ├── examples.md
│ │ ├── export_results.md
│ │ ├── generation.md
│ │ ├── index.md
│ │ ├── launching.md
│ │ ├── model_selection.md
│ │ └── ui_overview.md
│ ├── key_concepts/
│ │ ├── constraints.md
│ │ ├── limitations.md
│ │ ├── model.md
│ │ ├── motion_representation.md
│ │ └── skeleton.md
│ ├── project_info.md
│ ├── project_structure.md
│ └── user_guide/
│ ├── cli.md
│ ├── configuration.md
│ ├── constraints.md
│ ├── motion_convert.md
│ ├── output_formats.md
│ └── seed_dataset.md
├── kimodo/
│ ├── __init__.py
│ ├── assets/
│ │ ├── demo/
│ │ │ └── examples/
│ │ │ ├── kimodo-g1-rp/
│ │ │ │ ├── 01_single_text_prompt/
│ │ │ │ │ ├── meta.json
│ │ │ │ │ └── motion.npz
│ │ │ │ ├── 02_multi_text_ee_constraint/
│ │ │ │ │ ├── constraints.json
│ │ │ │ │ ├── meta.json
│ │ │ │ │ └── motion.npz
│ │ │ │ ├── 03_full_body_keyframes/
│ │ │ │ │ ├── constraints.json
│ │ │ │ │ ├── meta.json
│ │ │ │ │ └── motion.npz
│ │ │ │ ├── 04_ee_constraint/
│ │ │ │ │ ├── constraints.json
│ │ │ │ │ ├── meta.json
│ │ │ │ │ └── motion.npz
│ │ │ │ ├── 05_root_path/
│ │ │ │ │ ├── constraints.json
│ │ │ │ │ ├── meta.json
│ │ │ │ │ └── motion.npz
│ │ │ │ ├── 06_root_waypoints/
│ │ │ │ │ ├── constraints.json
│ │ │ │ │ ├── meta.json
│ │ │ │ │ └── motion.npz
│ │ │ │ ├── 07_text_terrain/
│ │ │ │ │ ├── meta.json
│ │ │ │ │ └── motion.npz
│ │ │ │ └── 08_text_object/
│ │ │ │ ├── meta.json
│ │ │ │ └── motion.npz
│ │ │ └── kimodo-soma-rp/
│ │ │ ├── 01_single_text_prompt/
│ │ │ │ ├── meta.json
│ │ │ │ └── motion.npz
│ │ │ ├── 02_multi_text_prompt/
│ │ │ │ ├── meta.json
│ │ │ │ └── motion.npz
│ │ │ ├── 03_full_body_keyframes/
│ │ │ │ ├── constraints.json
│ │ │ │ ├── meta.json
│ │ │ │ └── motion.npz
│ │ │ ├── 04_ee_constraint/
│ │ │ │ ├── constraints.json
│ │ │ │ ├── meta.json
│ │ │ │ └── motion.npz
│ │ │ ├── 05_root_path/
│ │ │ │ ├── constraints.json
│ │ │ │ ├── meta.json
│ │ │ │ └── motion.npz
│ │ │ ├── 06_root_waypoints/
│ │ │ │ ├── constraints.json
│ │ │ │ ├── meta.json
│ │ │ │ └── motion.npz
│ │ │ ├── 07_mixed_constraints/
│ │ │ │ ├── constraints.json
│ │ │ │ ├── meta.json
│ │ │ │ └── motion.npz
│ │ │ └── 08_stylized_text/
│ │ │ ├── meta.json
│ │ │ └── motion.npz
│ │ └── skeletons/
│ │ ├── g1skel34/
│ │ │ ├── joints.p
│ │ │ ├── meshes/
│ │ │ │ └── g1/
│ │ │ │ ├── head_link.STL
│ │ │ │ ├── left_ankle_pitch_link.STL
│ │ │ │ ├── left_ankle_roll_link.STL
│ │ │ │ ├── left_elbow_link.STL
│ │ │ │ ├── left_hand_index_0_link.STL
│ │ │ │ ├── left_hand_index_1_link.STL
│ │ │ │ ├── left_hand_middle_0_link.STL
│ │ │ │ ├── left_hand_middle_1_link.STL
│ │ │ │ ├── left_hand_palm_link.STL
│ │ │ │ ├── left_hand_thumb_0_link.STL
│ │ │ │ ├── left_hand_thumb_1_link.STL
│ │ │ │ ├── left_hand_thumb_2_link.STL
│ │ │ │ ├── left_hip_pitch_link.STL
│ │ │ │ ├── left_hip_roll_link.STL
│ │ │ │ ├── left_hip_yaw_link.STL
│ │ │ │ ├── left_knee_link.STL
│ │ │ │ ├── left_rubber_hand.STL
│ │ │ │ ├── left_shoulder_pitch_link.STL
│ │ │ │ ├── left_shoulder_roll_link.STL
│ │ │ │ ├── left_shoulder_yaw_link.STL
│ │ │ │ ├── left_wrist_pitch_link.STL
│ │ │ │ ├── left_wrist_roll_link.STL
│ │ │ │ ├── left_wrist_roll_rubber_hand.STL
│ │ │ │ ├── left_wrist_yaw_link.STL
│ │ │ │ ├── logo_link.STL
│ │ │ │ ├── pelvis.STL
│ │ │ │ ├── pelvis_contour_link.STL
│ │ │ │ ├── right_ankle_pitch_link.STL
│ │ │ │ ├── right_ankle_roll_link.STL
│ │ │ │ ├── right_elbow_link.STL
│ │ │ │ ├── right_hand_index_0_link.STL
│ │ │ │ ├── right_hand_index_1_link.STL
│ │ │ │ ├── right_hand_middle_0_link.STL
│ │ │ │ ├── right_hand_middle_1_link.STL
│ │ │ │ ├── right_hand_palm_link.STL
│ │ │ │ ├── right_hand_thumb_0_link.STL
│ │ │ │ ├── right_hand_thumb_1_link.STL
│ │ │ │ ├── right_hand_thumb_2_link.STL
│ │ │ │ ├── right_hip_pitch_link.STL
│ │ │ │ ├── right_hip_roll_link.STL
│ │ │ │ ├── right_hip_yaw_link.STL
│ │ │ │ ├── right_knee_link.STL
│ │ │ │ ├── right_rubber_hand.STL
│ │ │ │ ├── right_shoulder_pitch_link.STL
│ │ │ │ ├── right_shoulder_roll_link.STL
│ │ │ │ ├── right_shoulder_yaw_link.STL
│ │ │ │ ├── right_wrist_pitch_link.STL
│ │ │ │ ├── right_wrist_roll_link.STL
│ │ │ │ ├── right_wrist_roll_rubber_hand.STL
│ │ │ │ ├── right_wrist_yaw_link.STL
│ │ │ │ ├── torso_constraint_L_link.STL
│ │ │ │ ├── torso_constraint_L_rod_link.STL
│ │ │ │ ├── torso_constraint_R_link.STL
│ │ │ │ ├── torso_constraint_R_rod_link.STL
│ │ │ │ ├── torso_link.STL
│ │ │ │ ├── torso_link_23dof_rev_1_0.STL
│ │ │ │ ├── torso_link_rev_1_0.STL
│ │ │ │ ├── waist_constraint_L.STL
│ │ │ │ ├── waist_constraint_R.STL
│ │ │ │ ├── waist_roll_link.STL
│ │ │ │ ├── waist_roll_link_rev_1_0.STL
│ │ │ │ ├── waist_support_link.STL
│ │ │ │ ├── waist_yaw_link.STL
│ │ │ │ └── waist_yaw_link_rev_1_0.STL
│ │ │ ├── rest_pose_local_rot.p
│ │ │ └── xml/
│ │ │ └── g1.xml
│ │ ├── smplx22/
│ │ │ ├── beta.npy
│ │ │ ├── joints.p
│ │ │ └── mean_hands.npy
│ │ ├── somaskel30/
│ │ │ ├── joints.p
│ │ │ └── soma_base_fit_mhr_params.npz
│ │ └── somaskel77/
│ │ ├── bvh_joints.p
│ │ ├── joints.p
│ │ ├── relaxed_hands_rest_pose.npy
│ │ ├── skin_standard.npz
│ │ ├── somaskel77_standard_tpose.bvh
│ │ └── standard_t_pose_global_offsets_rots.p
│ ├── assets.py
│ ├── constraints.py
│ ├── demo/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── app.py
│ │ ├── config.py
│ │ ├── embedding_cache.py
│ │ ├── generation.py
│ │ ├── queue_manager.py
│ │ ├── state.py
│ │ └── ui.py
│ ├── exports/
│ │ ├── __init__.py
│ │ ├── bvh.py
│ │ ├── motion_convert_lib.py
│ │ ├── motion_formats.py
│ │ ├── motion_io.py
│ │ ├── mujoco.py
│ │ └── smplx.py
│ ├── geometry.py
│ ├── meta.py
│ ├── metrics/
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── constraints.py
│ │ ├── foot_skate.py
│ │ └── tmr.py
│ ├── model/
│ │ ├── __init__.py
│ │ ├── backbone.py
│ │ ├── cfg.py
│ │ ├── common.py
│ │ ├── diffusion.py
│ │ ├── kimodo_model.py
│ │ ├── llm2vec/
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── llm2vec.py
│ │ │ ├── llm2vec_wrapper.py
│ │ │ └── models/
│ │ │ ├── __init__.py
│ │ │ ├── attn_mask_utils.py
│ │ │ ├── bidirectional_llama.py
│ │ │ └── utils.py
│ │ ├── load_model.py
│ │ ├── loading.py
│ │ ├── registry.py
│ │ ├── text_encoder_api.py
│ │ ├── tmr.py
│ │ └── twostage_denoiser.py
│ ├── motion_rep/
│ │ ├── __init__.py
│ │ ├── conditioning.py
│ │ ├── feature_utils.py
│ │ ├── feet.py
│ │ ├── reps/
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── kimodo_motionrep.py
│ │ │ └── tmr_motionrep.py
│ │ ├── smooth_root.py
│ │ └── stats.py
│ ├── postprocess.py
│ ├── sanitize.py
│ ├── scripts/
│ │ ├── __init__.py
│ │ ├── docker-entrypoint.sh
│ │ ├── generate.py
│ │ ├── gradio_theme.py
│ │ ├── lock_requirements.py
│ │ ├── motion_convert.py
│ │ ├── mujoco_load.py
│ │ └── run_text_encoder_server.py
│ ├── skeleton/
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── bvh.py
│ │ ├── definitions.py
│ │ ├── kinematics.py
│ │ ├── registry.py
│ │ └── transforms.py
│ ├── tools.py
│ └── viz/
│ ├── __init__.py
│ ├── constraint_ui.py
│ ├── coords.py
│ ├── g1_rig.py
│ ├── gui.py
│ ├── playback.py
│ ├── scene.py
│ ├── smplx_skin.py
│ ├── soma_layer_skin.py
│ ├── soma_skin.py
│ └── viser_utils.py
├── pyproject.toml
└── setup.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# debugging files
debug/
SMPLX_NEUTRAL.npz
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
datasets
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# vscode
.vscode
*.code-workspace
/pyrightconfig.json
wandb/
# others
out
tmr_out
.ruff_cache
outputs
/debug
/batch*.sh
checkpoints/**/test/*
nohup.out
*.swp
*.swo
*.txt~*
*.un~
*~
train_done
.aider*
onelogger.err
# deploy files
/helm-library
================================================
FILE: .pre-commit-config.yaml
================================================
repos:
# code formatting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.4
hooks:
- id: ruff
name: sort imports with ruff
args: [--select, I, --fix]
- id: ruff-format
name: format with ruff
# docstring formatting
- repo: https://github.com/PyCQA/docformatter
rev: v1.7.7
hooks:
- id: docformatter
args:
[
--in-place,
--wrap-summaries=100,
--wrap-descriptions=100,
--style=sphinx,
]
# yaml formatting
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.0-alpha.6
hooks:
- id: prettier
types: [yaml]
exclude: |
(?x)^(
environment\.yaml$ |
\.gitlab-ci\.yml$ |
\.k8s/.*\.(ya?ml)$
)
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
hooks:
- id: trailing-whitespace # Trims trailing whitespace.
- id: end-of-file-fixer # Makes sure files end in a newline and only a newline.
- id: check-yaml # Attempts to load all yaml files to verify syntax.
exclude: |
(?x)^(
\.gitlab-ci\.yml$ |
\.k8s/.*\.(ya?ml)$
)
exclude: "checkpoints/.*"
================================================
FILE: ATTRIBUTIONS.MD
================================================
LLM2Vec MIT License https://github.com/McGill-NLP/llm2vec Copyright (c) 2024 McGill NLP
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Unitree mujoco BSD 3-Clause License https://github.com/unitreerobotics/unitree_mujoco/blob/main/LICENSE
Copyright (c) 2016-2024 HangZhou YuShu TECHNOLOGY CO.,LTD. ("Unitree Robotics")
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [2026-05-03]
### Fixed
- `benchmark/parse_folder.py` now averages each metric only over the testcases that actually report it. Previously, sparse constraint metrics (`constraint_root2d_acc`, `constraint_root2d_err`, `constraint_root2d_err_p95`, `constraint_fullbody_keyframe`, `constraint_end_effector`) were divided by the total motion count of the (split, category), including testcases of other constraint kinds that did not report the metric. This silently scaled values by `motions_with_metric / total_motions` (e.g. `constraint_root2d_acc` displayed as ~0.57 when the true value was ~0.93). Both the printed table and `summary_rows.json` are affected, including the combined constraints row that merges `constraints_withtext` and `constraints_notext`. Text-following metrics, foot-skate/contact metrics, and TMR metrics are unchanged.
- Updated Kimodo benchmark results in the documentation with this fix applied.
## [2026-04-24]
### Added
- Support for `TEXT_ENCODER_DEVICE` environment variable to force LLM2Vec to use the CPU instead of GPU. Setting `TEXT_ENCODER_DEVICE=cpu` reduces VRAM usage to <3 GB with a fairly small speed hit.
- `--save_example_dir` argument to `kimodo_gen` to save outputs to an example directory that can be directly loaded into `kimodo_demo`
### Fixed
- Bug in post-processing that was incorrectly making the smoothed root the target for the root in full-body constraints
- Modified how transitions are handled in multi-prompt generation to improve smoothness
### Removed
- `share_transition` and `percentage_transition_override` options from python API for multi-prompt generation
## [2026-04-13]
### Added
- Option `--bvh_standard_tpose` to use standard T-pose for BVH file saved from `generate.py`
- Option to use standard T-pose for BVH file saved or downloaded from demo
- Option to input/output BVH files that use standard T-pose with `motion_convert.py`
- Added BVH file containing the standard Kimodo T-pose to `kimodo/assets/skeletons/somaskel77/somaskel77_standard_tpose.bvh`
- Updated documentation with these new options
## [2026-04-10]
### Added
- [Kimodo-SOMA-RP-v1.1](https://huggingface.co/nvidia/Kimodo-SOMA-RP-v1.1) and [Kimodo-SOMA-SEED-v1.1](https://huggingface.co/nvidia/Kimodo-SOMA-SEED-v1.1) models and added support in the codebase. If not specified, the latest version of the models will be used automatically with the demo and CLI.
- [Kimodo Motion Generation Benchmark](https://huggingface.co/datasets/nvidia/Kimodo-Motion-Gen-Benchmark) for standardized evaluation of motion generation models training on the BONES-SEED dataset.
- Scripts to construct the full benchmark, generate motions for test cases, and compute evaluation metrics.
- Documentation explaining the benchmark and how to use the evaluation pipeline.
- [TMR-SOMA-RP-v1](https://huggingface.co/nvidia/TMR-SOMA-RP-v1) motion-text embedding model to be used for evaluation metrics.
- Added option to load LLM2Vec text encoder in fp32 precision.
### Fixed
- Always use batch size 1 with LLM2Vec to avoid unexpected behavior of different embeddings based on batch size.
- Load LLM2Vec directly onto the GPU, if available.
- Updated documentation on constraints with more details.
## [2026-04-01]
### Fixed
- Fix unnecessary text encoder reload when switching between models in the interactive demo (if not using the text encoder server API).
## [2026-03-31]
### Added
- New `kimodo_convert` CLI tool for converting generated motions between formats (NPZ, BVH, MuJoCo CSV, AMASS NPZ).
- Support for loading and saving BVH, CSV, and NPZ motion files in the interactive demo.
## [2026-03-27]
### Fixed
- Bug fix for foot contact visualization in the interactive demo.
- Patch bug with BVH export for SOMA models.
## [2026-03-19]
### Changed
- **Breaking:** Model inputs/outputs now use the SOMA 77-joint skeleton (`somaskel77`). This affects saved motion formats and constraint files from previous versions.
### Added
- Released timeline annotations for the BONES-SEED dataset on HuggingFace.
## [2026-03-16] - Initial Release
### Added
- Open-source release of Kimodo codebase under Apache-2.0 license.
- Five model variants: Kimodo-SOMA-RP-v1, Kimodo-G1-RP-v1, Kimodo-SOMA-SEED-v1, Kimodo-G1-SEED-v1, Kimodo-SMPLX-RP-v1.
- Command-line interface (`kimodo_gen`) for motion generation with text prompts and kinematic constraints.
- Interactive web-based motion authoring demo (`kimodo_demo`) with timeline editor, constraint tracks, and 3D visualization.
- Support for multiple output formats: default NPZ, MuJoCo qpos CSV (G1), AMASS NPZ (SMPL-X).
- Documentation site with quick start guide, installation instructions, CLI reference, and API docs.
- Compatibility with downstream tools: ProtoMotions (physics-based policy training) and GMR (motion retargeting).
================================================
FILE: CONTRIBUTING.MD
================================================
# How to Contribute
## Code Reviews
All submissions require review. We use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests.
## Signing Your Work
* We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license.
* Any contribution which contains commits that are not Signed-Off will not be accepted.
* To sign off on a commit you simply use the `--signoff` (or `-s`) option when committing your changes:
```bash
$ git commit -s -m "Add cool feature."
```
This will append the following to your commit message:
```
Signed-off-by: Your Name <your@email.com>
```
* Full text of the DCO:
```
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
```
```
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or
(b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or
(c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.
(d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.
```
================================================
FILE: Dockerfile
================================================
FROM nvcr.io/nvidia/pytorch:24.10-py3
# Avoid some interactive prompts + make pip quieter/reproducible-ish
ENV DEBIAN_FRONTEND=noninteractive \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# Where your code will live inside the container
WORKDIR /workspace
# System deps
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl ca-certificates \
cmake build-essential \
gosu \
&& rm -rf /var/lib/apt/lists/*
# Some base images ship a broken `/usr/local/bin/cmake` shim (from a partial pip install),
# which shadows `/usr/bin/cmake` and breaks builds that invoke `cmake` (e.g. MotionCorrection).
# Prefer the system cmake.
RUN rm -f /usr/local/bin/cmake || true
# Install from docker_requirements.txt: kimodo editable (-e .),
# but MotionCorrection non-editable (./MotionCorrection). The -e . line ensures [project.scripts]
# from pyproject.toml are installed (kimodo_gen, kimodo_demo, kimodo_textencoder).
# SKIP_MOTION_CORRECTION_IN_SETUP=1 so setup.py does not bundle motion_correction; it is
# installed separately from ./MotionCorrection in the requirements file (non-editable).
COPY docker_requirements.txt /workspace/docker_requirements.txt
COPY setup.py /workspace/setup.py
COPY pyproject.toml /workspace/pyproject.toml
COPY kimodo /workspace/kimodo
COPY kimodo-viser /workspace/kimodo-viser
COPY MotionCorrection /workspace/MotionCorrection
RUN --mount=type=cache,target=/root/.cache/pip \
python -m pip install --upgrade pip \
&& SKIP_MOTION_CORRECTION_IN_SETUP=1 python -m pip install -r docker_requirements.txt
# Use the docker-entrypoint script, to allow the docker to run as the actual user instead of root
COPY kimodo/scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint
RUN chmod +x /usr/local/bin/docker-entrypoint
# Default command (change to your entrypoint if you have one)
ENTRYPOINT ["docker-entrypoint"]
CMD ["bash"]
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: MANIFEST.in
================================================
include setup.py
recursive-include kimodo/assets *
recursive-include MotionCorrection/src *.cpp *.h *.inl
recursive-include MotionCorrection/python *.py *.dll
include MotionCorrection/CMakeLists.txt
include MotionCorrection/test_example.py
================================================
FILE: MotionCorrection/.gitignore
================================================
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
*.egg
*.egg-info/
dist/
build/
*.whl
.Python
develop-eggs/
.installed.cfg
pip-log.txt
pip-delete-this-directory.txt
.pytest_cache/
.coverage
htmlcov/
.tox/
.venv
venv/
ENV/
env/
# C/C++
*.o
*.obj
*.exe
*.out
*.app
*.dll
*.dylib
*.lib
*.a
*.la
*.lo
*.slo
*.ko
*.elf
*.ilk
*.map
*.exp
*.gch
*.pch
*.idb
*.pdb
*.mod
*.smod
*.lai
# CMake
CMakeCache.txt
CMakeFiles/
CMakeScripts/
cmake_install.cmake
install_manifest.txt
CTestTestfile.cmake
_deps/
cmake-build-*/
CMakeUserPresets.json
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
*.iml
.project
.cproject
.settings/
# Visual Studio
.vs/
*.user
*.suo
*.userosscache
*.sln.docstates
*.VC.db
*.VC.opendb
# Build directories
build/
Build/
out/
dist/
temp/
# Logs
*.log
================================================
FILE: MotionCorrection/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.15)
project(motion_correction)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Find Python
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
# Find or fetch pybind11
find_package(pybind11 CONFIG QUIET)
if(NOT pybind11_FOUND)
message(STATUS "pybind11 not found, fetching from GitHub...")
include(FetchContent)
FetchContent_Declare(
pybind11
GIT_REPOSITORY https://github.com/pybind/pybind11.git
GIT_TAG v2.11.1
)
FetchContent_MakeAvailable(pybind11)
endif()
# Find or fetch Eigen
find_package(Eigen3 3.3 CONFIG QUIET)
if(NOT Eigen3_FOUND)
message(STATUS "Eigen3 not found, fetching from GitLab...")
include(FetchContent)
FetchContent_Declare(
Eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
GIT_TAG 3.4.0
)
set(EIGEN_BUILD_DOC OFF CACHE BOOL "" FORCE)
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
set(EIGEN_BUILD_PKGCONFIG OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(Eigen)
endif()
# Source files
set(MATH_SOURCES
src/cpp/Math/Matrix.cpp
src/cpp/Math/Quaternion.cpp
src/cpp/Math/Transform.cpp
src/cpp/Math/Types.cpp
src/cpp/Math/Vector.cpp
)
set(ANIM_SOURCES
src/cpp/AnimProcessing/InverseKinematics.cpp
src/cpp/AnimProcessing/TrajectoryCorrector.cpp
src/cpp/AnimProcessing/Utility.cpp
)
# Create static library for the core functionality
add_library(motion_correction_cpp_base STATIC ${MATH_SOURCES} ${ANIM_SOURCES})
# Enable Position Independent Code (required for linking into shared library)
set_target_properties(motion_correction_cpp_base PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_include_directories(motion_correction_cpp_base PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/cpp
)
if(TARGET Eigen3::Eigen)
target_link_libraries(motion_correction_cpp_base PUBLIC Eigen3::Eigen)
else()
target_link_libraries(motion_correction_cpp_base PUBLIC eigen)
endif()
target_compile_definitions(motion_correction_cpp_base PUBLIC EIGEN_MPL2_ONLY)
# Compiler-specific settings
if(MSVC)
# MSVC-specific flags
target_compile_options(motion_correction_cpp_base PRIVATE /W4 /arch:AVX)
else()
# GCC/Clang flags (also applies to MinGW on Windows)
# Enable SSE4.1 and AVX instructions for SIMD operations
target_compile_options(motion_correction_cpp_base PRIVATE -Wall -Wextra -msse4.1 -mavx)
endif()
# Python bindings
pybind11_add_module(_motion_correction src/cpp/BindingsPython.cpp)
target_link_libraries(_motion_correction PRIVATE motion_correction_cpp_base)
target_include_directories(_motion_correction PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/cpp
)
# Install the Python module
install(TARGETS _motion_correction LIBRARY DESTINATION python/motion_correction)
install(FILES python/motion_correction/__init__.py DESTINATION python/motion_correction)
install(FILES python/motion_correction/motion_postprocess.py DESTINATION python/motion_correction)
================================================
FILE: MotionCorrection/MANIFEST.in
================================================
include CMakeLists.txt
include test_example.py
recursive-include src *.cpp *.h *.inl
recursive-include python *.py *.dll
================================================
FILE: MotionCorrection/README.md
================================================
# motion_correction
Standalone `correct_motion` implementation packaged as a small C++ motion trajectory correction library with Python bindings.
## Installation Guide
### Prerequisites
Ensure you have a C++17 compatible compiler (GCC 7.0+, Clang 5.0+, or MSVC 2017+) and CMake 3.15+. On Windows, install MinGW-w64 or Visual Studio with C++ tools. On Linux, install `build-essential` and `cmake`.
This project will download and install additional third-party open source software projects. Review the license terms of these open source projects before use.
### Build & Install
#### Standard Installation
```bash
pip install .
```
#### Development Installation
```bash
pip install -e .
```
### Verify Installation
```python
import motion_correction
print("Installation successful!")
```
You can also run `python run_test.py` for a simple test.
================================================
FILE: MotionCorrection/python/motion_correction/__init__.py
================================================
from ._motion_correction import *
================================================
FILE: MotionCorrection/python/motion_correction/motion_postprocess.py
================================================
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
import os
import pickle
import numpy as np
import torch
import motion_correction
def correct_motion(
hipTranslations,
jointRotations,
contacts,
hipTranslationsInput,
rotationsInput,
constraint_masks,
contact_threshold,
root_margin,
working_rig,
has_double_ankle_joints=False,
):
joint_names = [x.name for x in working_rig]
joint_parents = [
joint_names.index(working_rig[i].parent) if working_rig[i].parent in joint_names else -1
for i in range(len(working_rig))
]
joint_ref_translations = [list(x.t_pose_translation) for x in working_rig]
joint_ref_rotations = [list(x.t_pose_rotation) for x in working_rig]
left_hand_idx = [i for i in range(len(joint_names)) if working_rig[i].retarget_tag == "LeftHand"]
if len(left_hand_idx) != 1:
raise RuntimeError(f"correct_motion: Expected exactly one joint with LeftHand tag")
left_hand_idx = left_hand_idx[0]
right_hand_idx = [i for i in range(len(joint_names)) if working_rig[i].retarget_tag == "RightHand"]
if len(right_hand_idx) != 1:
raise RuntimeError(f"correct_motion: Expected exactly one joint with RightHand tag")
right_hand_idx = right_hand_idx[0]
left_foot_idx = [i for i in range(len(joint_names)) if working_rig[i].retarget_tag == "LeftFoot"]
if len(left_foot_idx) != 1:
raise RuntimeError(f"correct_motion: Expected exactly one joint with LeftFoot tag")
left_foot_idx = left_foot_idx[0]
right_foot_idx = [i for i in range(len(joint_names)) if working_rig[i].retarget_tag == "RightFoot"]
if len(right_foot_idx) != 1:
raise RuntimeError(f"correct_motion: Expected exactly one joint with RightFoot tag")
right_foot_idx = right_foot_idx[0]
end_frame = hipTranslations.shape[1]
default_mask = torch.zeros(hipTranslations.shape[1], dtype=torch.float32)
root_mask = constraint_masks.get("Root", default_mask)
full_body_mask = constraint_masks.get("FullBody", default_mask)
left_hand_mask = constraint_masks.get("LeftHand", default_mask)
right_hand_mask = constraint_masks.get("RightHand", default_mask)
left_foot_mask = constraint_masks.get("LeftFoot", default_mask)
right_foot_mask = constraint_masks.get("RightFoot", default_mask)
batch_size = hipTranslations.shape[0]
for b in range(batch_size):
hipTranslationsCorrected = hipTranslations[b, :end_frame].detach().cpu().flatten().numpy().astype(np.float32)
rotationsCorrected = jointRotations[b, :end_frame].detach().cpu().flatten().numpy().astype(np.float32)
hipTranslationsInput_flat = hipTranslationsInput.detach().cpu().flatten().numpy().astype(np.float32)
rotationsInput_flat = rotationsInput.detach().cpu().flatten().numpy().astype(np.float32)
ctcs = contacts[b].detach().cpu().flatten().numpy().astype(np.float32)
motion_correction.correct_motion(
hipTranslationsCorrected,
rotationsCorrected,
hipTranslationsInput_flat,
rotationsInput_flat,
full_body_mask,
left_hand_mask,
right_hand_mask,
left_foot_mask,
right_foot_mask,
root_mask,
np.array(ctcs, dtype=np.float32),
joint_parents,
joint_ref_translations,
joint_ref_rotations,
left_hand_idx,
right_hand_idx,
left_foot_idx,
right_foot_idx,
contact_threshold,
root_margin,
has_double_ankle_joints,
)
hipTranslations[b, :end_frame] = torch.from_numpy(
hipTranslationsCorrected.reshape(*hipTranslations[b, :end_frame].shape)
)
jointRotations[b, :end_frame] = torch.from_numpy(
rotationsCorrected.reshape(*jointRotations[b, :end_frame].shape)
)
================================================
FILE: MotionCorrection/run_test.py
================================================
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
import torch
from motion_correction.motion_postprocess import correct_motion
class Joint:
def __init__(self, name, parent, t_pose_translation, t_pose_rotation, retarget_tag=""):
self.name = name
self.parent = parent
self.t_pose_translation = t_pose_translation
self.t_pose_rotation = t_pose_rotation
self.retarget_tag = retarget_tag
def create_test_rig():
return [
Joint("Hips", None, [0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0], "Root"),
Joint("Spine", "Hips", [0.0, 0.1, 0.0], [0.0, 0.0, 0.0, 1.0]),
Joint("LeftUpLeg", "Hips", [-0.1, -0.05, 0.0], [0.0, 0.0, 0.0, 1.0]),
Joint("LeftLeg", "LeftUpLeg", [0.0, -0.4, 0.0], [0.0, 0.0, 0.0, 1.0]),
Joint("LeftFoot", "LeftLeg", [0.0, -0.4, 0.0], [0.0, 0.0, 0.0, 1.0], "LeftFoot"),
Joint("RightUpLeg", "Hips", [0.1, -0.05, 0.0], [0.0, 0.0, 0.0, 1.0]),
Joint("RightLeg", "RightUpLeg", [0.0, -0.4, 0.0], [0.0, 0.0, 0.0, 1.0]),
Joint("RightFoot", "RightLeg", [0.0, -0.4, 0.0], [0.0, 0.0, 0.0, 1.0], "RightFoot"),
Joint("LeftArm", "Spine", [-0.3, 0.3, 0.0], [0.0, 0.0, 0.0, 1.0]),
Joint("LeftHand", "LeftArm", [-0.3, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0], "LeftHand"),
Joint("RightArm", "Spine", [0.3, 0.3, 0.0], [0.0, 0.0, 0.0, 1.0]),
Joint("RightHand", "RightArm", [0.3, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0], "RightHand"),
]
if __name__ == "__main__":
# Test data
batch_size, num_frames, num_joints = 1, 60, 12
hipTranslations = torch.randn(batch_size, num_frames, 3)
jointRotations = torch.randn(batch_size, num_frames, num_joints, 4)
jointRotations = jointRotations / jointRotations.norm(dim=-1, keepdim=True)
contacts = torch.rand(batch_size, num_frames, 4)
hipTranslationsInput = hipTranslations.clone()
rotationsInput = jointRotations.clone()
constraint_masks = {
"Root": torch.zeros(num_frames),
"FullBody": torch.zeros(num_frames),
"LeftHand": torch.zeros(num_frames),
"RightHand": torch.zeros(num_frames),
"LeftFoot": torch.zeros(num_frames),
"RightFoot": torch.zeros(num_frames),
}
working_rig = create_test_rig()
# Run correction
correct_motion(
hipTranslations=hipTranslations,
jointRotations=jointRotations,
contacts=contacts,
hipTranslationsInput=hipTranslationsInput,
rotationsInput=rotationsInput,
constraint_masks=constraint_masks,
contact_threshold=0.5,
root_margin=0.01,
working_rig=working_rig,
)
print("Test completed successfully")
================================================
FILE: MotionCorrection/setup.py
================================================
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Setup script for correct_motion standalone package."""
import os
import shutil
import subprocess
import sys
from pathlib import Path
from setuptools import Extension, setup
from setuptools.command.build_ext import build_ext
class CMakeExtension(Extension):
def __init__(self, name, sourcedir=""):
Extension.__init__(self, name, sources=[])
self.sourcedir = os.path.abspath(sourcedir)
class CMakeBuild(build_ext):
def run(self):
try:
subprocess.check_output(["cmake", "--version"])
except OSError:
raise RuntimeError("CMake must be installed to build this package")
for ext in self.extensions:
self.build_extension(ext)
def build_extension(self, ext):
# import pdb; pdb.set_trace() # Debug build process
extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
cmake_args = [
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}",
f"-DPYTHON_EXECUTABLE={sys.executable}",
]
cfg = "Debug" if self.debug else "Release"
build_args = ["--config", cfg]
cmake_args += [f"-DCMAKE_BUILD_TYPE={cfg}"]
use_mingw = False
mingw_bin = None
if sys.platform == "win32":
generator = os.environ.get("CMAKE_GENERATOR", "")
if generator:
cmake_args = ["-G", generator] + cmake_args
if "mingw" in generator.lower():
use_mingw = True
else:
cmake_args += [f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}"]
else:
# Try MinGW Makefiles as default on Windows
try:
subprocess.check_output(["g++", "--version"], stderr=subprocess.STDOUT)
use_mingw = True
cmake_args = ["-G", "MinGW Makefiles"] + cmake_args
build_args = [] # MinGW Makefiles do not accept --config
except (OSError, subprocess.CalledProcessError):
# If g++ is not found, let CMake use its default (Visual Studio)
cmake_args += [f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}"]
if use_mingw:
gxx_path = shutil.which("g++")
if gxx_path:
mingw_bin = Path(gxx_path).parent
else:
build_args += ["--", "-j4"]
env = os.environ.copy()
env["CXXFLAGS"] = f'{env.get("CXXFLAGS", "")} -DVERSION_INFO=\\"{self.distribution.get_version()}\\"'
if not os.path.exists(self.build_temp):
os.makedirs(self.build_temp)
subprocess.check_call(["cmake", ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env)
subprocess.check_call(["cmake", "--build", "."] + build_args, cwd=self.build_temp)
if use_mingw and mingw_bin is not None:
runtime_libs = [
"libstdc++-6.dll",
"libgcc_s_seh-1.dll",
"libwinpthread-1.dll",
]
extdir_path = Path(extdir)
extdir_path.mkdir(parents=True, exist_ok=True)
for lib_name in runtime_libs:
src_path = mingw_bin / lib_name
if src_path.exists():
shutil.copy2(src_path, extdir_path / lib_name)
else:
self.announce(
f"Warning: Expected MinGW runtime DLL '{lib_name}' not found next to g++ (looked in {mingw_bin}). "
"The built extension may fail to import if the DLL is not on PATH.",
level=3,
)
setup(
name="motion_correction",
version="1.0.0",
author="NVIDIA",
description="Standalone correct_motion function",
long_description="",
packages=["motion_correction"],
package_dir={"": "python"},
ext_modules=[CMakeExtension("motion_correction._motion_correction")],
cmdclass={"build_ext": CMakeBuild},
zip_safe=False,
python_requires=">=3.8",
install_requires=[
"torch>=1.10.0",
"numpy>=1.19.0",
# 'cmake' # can install this via pip if the windows system does not have it. But need to run this by yourself before build, not in here.
],
)
================================================
FILE: MotionCorrection/src/cpp/AnimProcessing/InverseKinematics.cpp
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "InverseKinematics.h"
#include "Math/Scalar.h"
#include <iostream>
using namespace IK;
namespace
{
float getAngleWithTwoSideVectors(const Math::Vector& vecLeft, const Math::Vector& vecRight)
{
auto lNorm = vecLeft.GetNormalized3();
auto rNorm = vecRight.GetNormalized3();
float cosine = lNorm.GetDot3(rNorm);
float sine = lNorm.Cross3(rNorm).GetLength3();
return atan2f(sine, cosine); // in radian
}
float getAngleWithCosineRule (const float lSideLeft, const float lSideRight, const float lSideAcross)
{
float val =
(lSideRight * lSideRight + lSideLeft * lSideLeft - lSideAcross * lSideAcross) /
(2.0f * lSideLeft * lSideRight);
val = Math::Clamp(val, -1.0f, 1.0f); // numerical stability. also avoid impossible trangulars
return acosf(val); // in radian
}
}
void IK::TwoBoneIk(
Pose& pose,
const Math::Transform& rootTransform,
uint32_t cIdx,
float weight,
const Math::Vector& target,
const std::vector<int>& joint_parents_vec,
const Math::Vector& hintOffset
)
{
weight = Math::Clamp(weight, 0.0f, 1.0f);
if (!(weight > 0.0f))
return;
// Two bone IK: joints are represented as "a", "b", "c" in the below comments:
// 1. stage 1, bend joint a and joint b, so that |ac| = |at|, while vec_ac maintain the same direction
// 2. stage 2, rotate start joint a so that c and t are in the same place
// a a a |
// |\ |\ |\ |
// | \ | \ | \ |
// | \ (stage 1 ->) | \ (stage 2 ->) | \ |
// | b | b | b |
// | \ | | | / |
// | \ | | | / |
// t c t c t(c) |
// (a is the root joint, b is the middle joint and c is the end joint)
//
int32_t bIdx = joint_parents_vec[cIdx];
if (bIdx < 0)
{
return;
}
int32_t aIdx = joint_parents_vec[bIdx];
if (aIdx < 0)
{
return;
}
// Find the parent world transform of joint a:
Math::Transform aParentWorldTransform = Math::Transform::Identity;
int32_t idx = joint_parents_vec[aIdx];
while (idx >= 0)
{
aParentWorldTransform = aParentWorldTransform * pose[idx];
idx = joint_parents_vec[idx];
}
aParentWorldTransform = aParentWorldTransform * rootTransform;
// Compute world space transforms of a, b and c:
Math::Transform aWorld = pose[aIdx] * aParentWorldTransform;
Math::Transform bWorld = pose[bIdx] * aWorld;
Math::Transform cWorld = pose[cIdx] * bWorld;
auto a = aWorld.GetTranslation();
auto b = bWorld.GetTranslation();
auto c = cWorld.GetTranslation();
auto t = Math::Vector::Lerp(c, target, weight);
// step 1 (stage 1): extend / contract the joint chain to match the distance
float eps = 0.0001f; // numerical stability
float l_ab = (b - a).Length3().GetX();
float l_bc = (c - b).Length3().GetX();
float l_at = (a - t).Length3().GetX();
l_at = Math::Clamp(l_at, eps, (l_ab + l_bc) * 0.999f); // when not reachable, replace with maximum reachable length
// get the current angles
float theta_bac_current = getAngleWithTwoSideVectors(a - b, a - c);
float theta_abc_current = getAngleWithTwoSideVectors(b - a, b - c);
// get the desired angles
if (l_ab < eps || l_bc < eps || l_at < eps)
{
return; // the length is too small. rejecting potentially numerically unstable requests.
}
float theta_bac_desired = getAngleWithCosineRule(l_ab, l_at, l_bc);
float theta_abc_desired = getAngleWithCosineRule(l_ab, l_bc, l_at);
// in joint[0]'s parent's space
Math::Vector rotationAxis = Math::Vector::Cross3(c - a, bWorld.TransformPoint(hintOffset) - a);
float l = rotationAxis.GetLength3();
if (l == 0)
{
rotationAxis = Math::Vector(0,0,1);
}
else
{
rotationAxis /= l;
}
// get the rotation with axis in the local space of joint a and joint b
Math::Vector rotationAxisLocalInBSpace = bWorld.GetRotation().RotateVectorInverse(rotationAxis);
Math::Transform rotateInB(
Math::Quaternion(rotationAxisLocalInBSpace,
(theta_abc_desired - theta_abc_current)), Math::Vector::Zero);
pose[bIdx] = rotateInB * pose[bIdx];
Math::Vector rotationAxisLocalInASpace = aWorld.GetRotation().RotateVectorInverse(rotationAxis);
Math::Transform rotateInA(
Math::Quaternion(rotationAxisLocalInASpace,
(theta_bac_desired - theta_bac_current)), Math::Vector::Zero);
pose[aIdx] = rotateInA * pose[aIdx];
// recompute a's world space transform as we're going to need it:
aWorld = pose[aIdx] * aParentWorldTransform;
// step 2 (stage 2): rotate joint a so that the target and the end joint c matches
auto acLocal = aWorld.GetRotation().RotateVectorInverse(
c - a);
auto atLocal = aWorld.GetRotation().RotateVectorInverse(
target - a);
Math::Transform rotateStageTwo(
Math::Quaternion::FromRotationBetweenVectors(acLocal, atLocal), Math::Vector::Zero
);
pose[aIdx] = rotateStageTwo * pose[aIdx];
}
void IK::OneBoneIk(
Pose& pose,
const Math::Transform& rootTransform,
uint32_t bIdx,
float weight,
const Math::Vector& target,
const std::vector<int>& joint_parents_vec
)
{
weight = Math::Clamp(weight, 0.0f, 1.0f);
if (!(weight > 0.0f))
return;
int32_t aIdx = joint_parents_vec[bIdx];
if (aIdx < 0)
{
return;
}
// Find the parent world transform of joint a:
Math::Transform aParentWorldTransform = Math::Transform::Identity;
int32_t idx = joint_parents_vec[aIdx];
while (idx >= 0)
{
aParentWorldTransform = aParentWorldTransform * pose[idx];
idx = joint_parents_vec[idx];
}
aParentWorldTransform = aParentWorldTransform * rootTransform;
// Compute world space transforms of a, b and c:
Math::Transform aWorld = pose[aIdx] * aParentWorldTransform;
Math::Transform bWorld = pose[bIdx] * aWorld;
auto abLocal = aWorld.GetRotation().RotateVectorInverse(
bWorld.GetTranslation() - aWorld.GetTranslation());
auto atLocal = aWorld.GetRotation().RotateVectorInverse(
target - aWorld.GetTranslation());
auto deltaRLocal = Math::Quaternion::NLerp(Math::Quaternion::Identity, Math::Quaternion::FromRotationBetweenVectors(abLocal, atLocal), weight);
pose[aIdx].SetRotation(deltaRLocal * pose[aIdx].GetRotation());
}
================================================
FILE: MotionCorrection/src/cpp/AnimProcessing/InverseKinematics.h
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "Math/Transform.h"
#include <vector>
using Pose = std::vector<Math::Transform>;
namespace IK {
void TwoBoneIk(
Pose& pose,
const Math::Transform& rootTransform,
uint32_t jointIdx,
float weight,
const Math::Vector& target,
const std::vector<int>& joint_parents_vec,
const Math::Vector& hintOffset = Math::Vector::Zero
);
void OneBoneIk(
Pose& pose,
const Math::Transform& rootTransform,
uint32_t jointIdx,
float weight,
const Math::Vector& target,
const std::vector<int>& joint_parents_vec
);
}
================================================
FILE: MotionCorrection/src/cpp/AnimProcessing/TrajectoryCorrector.cpp
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "TrajectoryCorrector.h"
#include <iostream>
static void removeRows(
Eigen::SparseMatrix<double>& M,
Eigen::MatrixXd *v,
int minCoeffs)
{
Eigen::SparseMatrix<double, Eigen::RowMajor> rowMajorMat = M;
rowMajorMat.makeCompressed(); // Ensure compressed format
std::vector<Eigen::Triplet<double>> triplets;
triplets.reserve(rowMajorMat.nonZeros());
int newRow = 0;
for (int i = 0; i < rowMajorMat.outerSize(); ++i) {
// Get nonzero count via outerIndexPtr (compressed format only)
int nnz = rowMajorMat.outerIndexPtr()[i + 1] - rowMajorMat.outerIndexPtr()[i];
if (nnz >= minCoeffs) {
// Iterate through nonzeros in this row
for (Eigen::SparseMatrix<double, Eigen::RowMajor>::InnerIterator it(rowMajorMat, i); it; ++it) {
triplets.emplace_back(newRow, it.col(), it.value());
}
if (v)
{
v->row(newRow) = v->row(i);
}
newRow++;
}
}
M = Eigen::SparseMatrix<double>(newRow, M.cols());
M.setFromTriplets(triplets.begin(), triplets.end());
if (v)
{
v->conservativeResize(newRow, v->cols());
}
}
static void multVelWeights(
Eigen::SparseMatrix<double>& V,
Eigen::MatrixXd* v_rhs,
const Eigen::VectorXd& velocityWeights
)
{
Eigen::SparseMatrix<double, Eigen::RowMajor> rowMajorMat = V;
rowMajorMat.makeCompressed(); // Ensure compressed format
std::vector<Eigen::Triplet<double>> triplets;
triplets.reserve(rowMajorMat.nonZeros());
for (int i = 0; i < rowMajorMat.outerSize(); ++i) {
// Iterate through nonzeros in this row
Eigen::SparseMatrix<double, Eigen::RowMajor>::InnerIterator it(rowMajorMat, i);
double vel_weight = velocityWeights[it.col()];
for(; it; ++it)
{
triplets.emplace_back(i, it.col(), it.value() * vel_weight);
}
if (v_rhs)
{
(*v_rhs).row(i) = (*v_rhs).row(i) * vel_weight;
}
}
}
void TrajectoryCorrector::computeDiffMats(
Eigen::SparseMatrix<double>& V,
Eigen::SparseMatrix<double>& A,
uint32_t N,
const Eigen::VectorXd& velocityWeights,
Eigen::MatrixXd* v_rhs,
Eigen::MatrixXd* a_rhs)
{
std::vector<Eigen::Triplet<double>> tripletList;
// Identity matrix"
tripletList.clear();
Eigen::SparseMatrix<double> I(N, N);
for (uint32_t i = 0; i < N; ++i)
{
tripletList.emplace_back(i, i, 1);
}
I.setFromTriplets(tripletList.begin(), tripletList.end());
// urr, a time translation operator? Gives you the value on the next frame.
// Leave the last row blank because that's the end of the timeline.
tripletList.clear();
Eigen::SparseMatrix<double> T(N, N);
Eigen::MatrixXd t_rhs;
for(uint32_t i = 0; i < N-1; ++i)
{
// next frame is
tripletList.emplace_back(i, i+1, 1.0);
}
T.setFromTriplets(tripletList.begin(), tripletList.end());
// v = Tx + t_rhs - x;
// v = (T - I)x + t_rhs;
V = T - I;
if (v_rhs)
{
*v_rhs = t_rhs;
}
removeRows(V, v_rhs, 2);
// a = -x + 2 (T x + t_rhs) - (T (T x + t_rhs) + t_rhs)
// a = (-I + 2 T - T^2) x + t_rhs - T t_rhs
A = 2 * T - I - T * T;
if (a_rhs)
{
*a_rhs = t_rhs - T * t_rhs;
}
removeRows(A, a_rhs, 3);
if (velocityWeights.size() > 0)
{
multVelWeights(V, v_rhs, velocityWeights);
}
}
TrajectoryCorrector::TrajectoryCorrector(
const Eigen::VectorXd& margins,
float pos_weight,
float vel_weight,
float acc_weight,
const Eigen::VectorXd& velocityWeights,
uint32_t admm_iters ) :
m_admm_iters(admm_iters)
{
// This class is used to modify a trajectory to hit specific values at
// specific frames, while respecting the following soft constraints:
// * Preserve the original positions
// * Preserve the original velocities
// * Preserve the original accelerations
// The weights of these soft constraints are specified in "pos_weight" etc.
// This is posed as a minimization problem:
// E(x) = pos_weight * |x - x_orig|^2 + vel_weight * |V x - V x_orig| + acc_weight * |A x - A x_orig|
// where you minimize E(x) subject to specified values at indices where "mask"
// is equal to 1. V is a matrix that computes the N-1 velocities between frame n-1 and frame n,
// and A computes the N-2 accelerations associated with frames n-1, n and n+1.
// In addition to this, there are constraints where the trajectory is allowed to
// deviate from the target points by a maximum margin. The "margins" input to this
// constructor specifies what type of constraint is active on a particular frame:
// margins[0] < 0 ==> unconstrained
// margins[i] == 0 ==> pinned on this frame
// margins[i] > 0 ==> can deviate within the margin
// I'm solving the optimization problem using ADMM, ie following equations
// 8,9,10 on this paper:
// https://mattoverby.net/files/admm-pd-overby17.pdf
uint32_t N = uint32_t(margins.rows());
for(uint32_t i = 0; i < N; ++i)
{
if( margins[i] > 0 )
{
m_margin_locs.push_back(i);
m_margin_vals.push_back(margins[i]);
}
if(margins[i] == 0)
{
m_constrained_locs.push_back(i);
}
else
{
m_unconstrained_locs.push_back(i);
}
}
Eigen::SparseMatrix<double> V, A;
computeDiffMats(
V, A,
N, velocityWeights
);
// build an identity matrix:
std::vector<Eigen::Triplet<double>> tripletList;
Eigen::SparseMatrix<double> I(N, N);
for (uint32_t i = 0; i < N; ++i)
{
tripletList.emplace_back(i, i, 1.0f);
}
I.setFromTriplets(tripletList.begin(), tripletList.end());
/*
self.N = (
self.pos_weight * torch.diag_embed(torch.full_like(interp_mask, 1)) +
self.vel_weight * torch.matmul(self.V.T, self.V) +
self.acc_weight * torch.matmul(self.A.T, self.A)
)
*/
m_N = pos_weight * I + vel_weight * (V.transpose() * V) + acc_weight * (A.transpose() * A);
double diagMax = 0;
for (uint32_t i = 0; i < N; ++i)
{
diagMax = std::max(m_N.coeff(i,i), diagMax);
}
m_admm_stepsize = 0.5f * sqrtf(float(diagMax));
/*
M = (
self.N +
self.admm_stepsize * torch.matmul(self.S.T, self.S)
)
*/
tripletList.clear();
Eigen::SparseMatrix<double> M(N, N);
for( auto i : m_margin_locs)
{
tripletList.emplace_back(i, i, m_admm_stepsize);
}
M.setFromTriplets(tripletList.begin(), tripletList.end());
M += m_N;
/*
self.lhsmat = torch.matmul(self.U.T, torch.matmul(self.M, self.U))
self.lhsmat_inv = torch.inverse(self.lhsmat)
*/
tripletList.clear();
Eigen::SparseMatrix<double> S(m_unconstrained_locs.size(), N);
for (uint32_t i = 0; i < m_unconstrained_locs.size(); ++i)
{
uint32_t ifull = m_unconstrained_locs[i];
tripletList.emplace_back(i, ifull, 1.0f);
}
S.setFromTriplets(tripletList.begin(), tripletList.end());
M = S * M * S.transpose();
if(m_unconstrained_locs.size())
{
m_system_lu.compute(M);
}
}
void TrajectoryCorrector::Interpolate(
Eigen::MatrixXd& x,
const Eigen::MatrixXd& observations,
const Eigen::MatrixXd& ref_positions
) const
{
if(
m_constrained_locs.empty() &&
m_margin_locs.empty()
)
{
x = ref_positions;
return;
}
uint32_t numCols = uint32_t(x.cols());
if(m_margin_locs.empty())
{
x_update(
x,
Eigen::MatrixXd(0, numCols),
Eigen::MatrixXd(0, numCols),
ref_positions,
observations
);
}
else
{
x = ref_positions;
Eigen::MatrixXd z(m_margin_locs.size(), numCols);
Eigen::MatrixXd z_t(m_margin_locs.size(), numCols);
Eigen::MatrixXd u(m_margin_locs.size(), numCols);
for( uint32_t i = 0; i < m_margin_locs.size(); ++i)
{
for(uint32_t j = 0; j < numCols; ++j)
{
z_t(i, j) = observations(m_margin_locs[i], j);
z(i, j) = ref_positions(m_margin_locs[i], j);
u(i, j) =0;
}
}
for(uint32_t i = 0; i < m_admm_iters; ++i)
{
x_update(
x,
z,
u,
ref_positions,
observations
);
z_update(z, x, z_t, u);
u_update(u, x, z);
}
}
}
void TrajectoryCorrector::x_update(
Eigen::MatrixXd &x,
const Eigen::MatrixXd &z,
const Eigen::MatrixXd &u,
const Eigen::MatrixXd &x_t, // reference positions - defines the original shape of the curve that we want to preserve
const Eigen::MatrixXd &x_o // target positions for constraints
) const
{
uint32_t numRows = uint32_t(x.rows());
uint32_t numCols = uint32_t(x.cols());
// Here's what we're minimizing with ADMM:
// min f(x) + g(z)
// s.t A x + B z = c
// Make these choices so that z = S x:
// A = S, B = -I, c = 0
//
// g(z) = infinity when it's too far away from z_target, zero otherwise
//
// f(x) penalizes deviations in position, velocity and acceleration
// from a reference trajectory:
//
// f(x) = 1/2(
// kx |I x - x_t|^2 +
// kv |V x - v_t|^2 +
// kx |A x - a_t|^2
// )
//
// It's also infinite when components of x devaiate from their target
// values where they're pinned...
// Substituting the matrices into the standard admm update rules gives us this:
// x{n+1} = argmin(f(x) + ρ/2 |S x - z{n} + u{n}|^2)
// z{n+1} = argmin(g(z) + ρ/2 |S x{n+1} - z + u{n}|^2)
// u{n+1} = u{n} + (S x{n+1} - z{n+1})
//
// x update:
//
// x{n+1} = argmin 1/2 (
// kx |I x - x_t|^2 +
// kv |V x - v_t|^2 +
// ka |A x - a_t|^2 +
// ρ |S x - d|^2
// )
// d = (z{n} - u{n})
// Rewrite in a friendlier way:
// |A x - b|^2 = x^T A^T A x - 2 x^T A^T b + C
// 1/2 (
// kx (x^T x - 2 x^T x_t) +
// kv (x^T V^T V x - 2 x^T V^T v_t) +
// ka (x^T A^T A x - 2 x^T A^T a_t) +
// ρ (x^T S^T S x - 2 x^T S^T d)
// ) + C
//
// 1/2 x^T (kx I + kv V^T V + ka A^T A + ρ S^T S) x
// - x^T (kx x_t + kv V^T v_t + ka A^T a_t + ρ S^T d)
// + C
//
// voila:
// M = kx I + kv V^T V + ka A^T A + ρ S^T S
// r = kx x_t + kv V^T v_t + ka A^T a_t + ρ S^T d
// E = 1/2 x^T M x - x^T r + C
/*
r = (
torch.matmul(self.N, x_t - x_o_filtered) +
self.admm_stepsize * torch.matmul(self.S.T, - u + z)
)
*/
Eigen::MatrixXd x_diffs(x_t);
for(auto i : m_constrained_locs)
{
for(uint32_t j = 0; j < numCols; ++j)
{
x_diffs(i, j) = x_diffs(i,j) - x_o(i,j);
}
}
Eigen::MatrixXd r = m_N * x_diffs;
for(uint32_t i = 0; i < m_margin_locs.size(); ++i)
{
uint32_t ifull = m_margin_locs[i];
for(uint32_t j = 0; j < numCols; ++j)
{
r(ifull, j) = r(ifull, j) + m_admm_stepsize * (z(i,j) - u(i,j));
}
}
// Solve with respect to pin constraints:
// x = U x_r + x_o
// E = 1/2 (U x_r + x_o)^T M (U x_r + x_o) - (U x_r + x_o)^T r + C
// E = 1/2 (x_r^T U^T + x_o^T) M (U x_r + x_o) - (x_r^T U^T + x_o^T) r + C
// E = 1/2 (x_r^T U^T M (U x_r + x_o) + x_o^T M (U x_r + x_o)) - x_r^T U^T r - x_o^T r + C
// E = 1/2 (x_r^T U^T M U x_r) + x_r^T U^T (M x_o - r) + C
// minimized when x_r solves this equation:
// U^T M U x_r + U^T (M x_o - r) = 0
// x_r = (U^T M U)^-1 U^T (r - M x_o)
// collapse r down to unconstrained variable set:
// rhs = torch.matmul(self.U.T, r)
uint32_t numRows_reduced = m_unconstrained_locs.size();
Eigen::MatrixXd r_reduced(numRows_reduced, numCols);
for(uint32_t i = 0; i < numRows_reduced; ++i)
{
uint32_t ifull = m_unconstrained_locs[i];
for(uint32_t j = 0; j < numCols; ++j)
{
r_reduced(i,j) = r(ifull, j);
}
}
// solve system:
// x_r = torch.matmul(self.lhsmat_inv, rhs)
r_reduced.conservativeResize(r_reduced.rows(), r_reduced.cols());
Eigen::MatrixXd result;
if(m_unconstrained_locs.size())
{
result = m_system_lu.solve(r_reduced);
}
// map back to full variable set:
// return torch.matmul(self.U, x_r) + x_o_filtered
for(uint32_t i = 0; i < numRows_reduced; ++i)
{
uint32_t ifull = m_unconstrained_locs[i];
for(uint32_t j = 0; j < numCols; ++j)
{
x(ifull, j) = result(i, j);
}
}
for(auto i : m_constrained_locs)
{
for(uint32_t j = 0; j < numCols; ++j)
{
x(i, j) = x_o(i, j);
}
}
}
void TrajectoryCorrector::z_update(
Eigen::MatrixXd &z,
const Eigen::MatrixXd &x,
const Eigen::MatrixXd &z_t,
const Eigen::MatrixXd &u
) const
{
uint32_t numCols = uint32_t(z.cols());
for(uint32_t i = 0; i < m_margin_locs.size(); ++i)
{
// z_diffs = S x + u - z_t
uint32_t ifull = m_margin_locs[i];
for(uint32_t j = 0; j < numCols; ++j)
{
z(i, j) = x(ifull, j) + u(i, j) - z_t(i, j);
}
// find the norm of the current z diff vector:
double z_diff_norm = 0.0;
for(uint32_t j = 0; j < numCols; ++j)
{
double z_diff = z(i, j);
z_diff_norm += z_diff * z_diff;
}
z_diff_norm = sqrt(z_diff_norm);
// if the norm is greater than the margin size, we need to rescale
// the diff:
if( z_diff_norm > m_margin_vals[i] )
{
for(uint32_t j = 0; j < numCols; ++j)
{
z(i, j) = z(i, j) * m_margin_vals[i] / z_diff_norm;
}
}
// add the diff back on to the target:
for(uint32_t j = 0; j < numCols; ++j)
{
z(i, j) = z_t(i, j) + z(i, j);
}
}
}
void TrajectoryCorrector::u_update(
Eigen::MatrixXd &u,
const Eigen::MatrixXd &x,
const Eigen::MatrixXd &z
) const
{
uint32_t numCols = uint32_t(z.cols());
// u += S x - z
for(uint32_t i = 0; i < m_margin_locs.size(); ++i)
{
uint32_t ifull = m_margin_locs[i];
for(uint32_t j = 0; j < numCols; ++j)
{
u(i,j) += x(ifull, j) - z(i,j);
}
}
}
================================================
FILE: MotionCorrection/src/cpp/AnimProcessing/TrajectoryCorrector.h
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <Eigen/Sparse>
class TrajectoryCorrector
{
public:
static void computeDiffMats(
Eigen::SparseMatrix<double>& V,
Eigen::SparseMatrix<double>& A,
uint32_t N,
const Eigen::VectorXd& velocityWeights = Eigen::VectorXd(),
Eigen::MatrixXd* v_rhs = nullptr,
Eigen::MatrixXd* a_rhs = nullptr
);
TrajectoryCorrector(
const Eigen::VectorXd& margins,
float pos_weight,
float vel_weight,
float acc_weight,
const Eigen::VectorXd& velocityWeights = Eigen::VectorXd(),
uint32_t admm_iters=100 );
void Interpolate(
Eigen::MatrixXd& ret,
const Eigen::MatrixXd& observations,
const Eigen::MatrixXd& ref_positions
) const;
void x_update(
Eigen::MatrixXd& x,
const Eigen::MatrixXd& z,
const Eigen::MatrixXd& u,
const Eigen::MatrixXd& x_t,
const Eigen::MatrixXd& x_o
) const;
void z_update(
Eigen::MatrixXd& z,
const Eigen::MatrixXd& x,
const Eigen::MatrixXd& z_t,
const Eigen::MatrixXd& u
) const;
void u_update(
Eigen::MatrixXd& u,
const Eigen::MatrixXd& x,
const Eigen::MatrixXd& z
) const;
float admm_stepsize() const { return m_admm_stepsize; }
const std::vector<uint32_t>& margin_locs() { return m_margin_locs; }
private:
Eigen::SparseMatrix<double> m_N;
Eigen::SparseLU<Eigen::SparseMatrix<double>> m_system_lu;
uint32_t m_admm_iters;
std::vector<uint32_t> m_margin_locs;
std::vector<double> m_margin_vals;
std::vector<uint32_t> m_unconstrained_locs;
std::vector<uint32_t> m_constrained_locs;
float m_admm_stepsize;
};
================================================
FILE: MotionCorrection/src/cpp/AnimProcessing/Utility.cpp
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "TrajectoryCorrector.h"
#include "InverseKinematics.h"
#include "Utility.h"
#include <map>
#include <array>
#include <cmath>
#include <cstdlib>
#include <iostream>
using Pose = std::vector<Math::Transform>;
static const float pos_weight = 0.001f;
static const float vel_weight = 1.0f;
static const float acc_weight = 10.0f;
namespace {
// Enable with: MOTIONCORRECTION_DEBUG_INTERVALS=1
// Default: off (no Interval printing).
bool DebugPrintIntervalsEnabled()
{
const char* v = std::getenv("MOTIONCORRECTION_DEBUG_INTERVALS");
if (v == nullptr || v[0] == '\0')
{
return false;
}
// Treat "0" as false; any other non-empty value enables.
return v[0] != '0';
}
void FilterContactIntervals(
std::vector<std::pair<int, int>>& contactIntervals,
const std::vector<float>& mask,
bool one_bone_contact = false)
{
std::vector<uint32_t> keepIntervals;
for (size_t i = 0; i < contactIntervals.size(); ++i)
{
const auto& interval = contactIntervals[i];
bool startConstrained = (interval.first != 0 && mask[interval.first - 1]);
bool endConstrained;
endConstrained = (interval.second != mask.size() && mask[interval.second]);
if (one_bone_contact)
{
if (startConstrained || endConstrained)
{
continue;
}
}
else
{
// If both the start and end of the contact interval are masked,
// there's no way we can correct the contact without popping, so
// let's filter these out:
if (startConstrained && endConstrained)
{
continue;
}
}
keepIntervals.push_back(i);
}
for (size_t i = 0; i < keepIntervals.size(); ++i)
{
contactIntervals[i] = contactIntervals[keepIntervals[i]];
}
contactIntervals.resize(keepIntervals.size());
}
std::vector<std::pair<int, int>> ComputeContactIntervals(
const std::vector<float>& contacts,
const std::vector<float>& mask,
float contactThreshold)
{
// turn off the contacts for all frames that are constrained/masked:
std::vector<float> contactsNoMask = contacts;
for (size_t i = 0; i < mask.size(); ++i)
{
if (mask[i])
{
contactsNoMask[i] = 0;
}
}
// Find intervals that are in contact:
std::vector<std::pair<int, int>> contactIntervals;
int start = -1;
for (int frame = 0; frame < mask.size(); ++frame)
{
bool isContact = contactsNoMask[frame] > contactThreshold;
if (isContact && start == -1)
{
start = frame;
}
else if (!isContact && start != -1)
{
contactIntervals.emplace_back(start, frame);
start = -1;
}
}
// Close the final interval if needed:
if (start != -1)
{
contactIntervals.emplace_back(start, mask.size());
}
return contactIntervals;
}
void FindContactPoints(
std::vector<Math::Vector> &points,
std::vector<int> &inContact,
const std::vector<int>& joint_parents_vec,
int32_t jointIndex,
const std::vector<Pose> &poses,
const std::vector<std::pair<int, int>>& contactIntervals,
const std::vector<float>& mask,
size_t frameCount,
float minHeight)
{
// Find a representative frame for each interval.
// If the interval starts after a masked frame, use the start
// of the interval, if it ends before a mask use the end,
// otherwise use the middle frame.
inContact.clear();
inContact.resize(frameCount, 0);
points.clear();
points.resize(frameCount);
for (size_t i = 0; i < contactIntervals.size(); ++i)
{
const auto& interval = contactIntervals[i];
int frame = -1;
bool startConstrained = (interval.first != 0 && mask[interval.first - 1]);
bool endConstrained;
endConstrained = (interval.second != mask.size() && mask[interval.second]);
// Debug output (opt-in via env var)
if (DebugPrintIntervalsEnabled())
{
std::cout << "Interval " << i << ": start=" << interval.first
<< ", end=" << interval.second
<< ", startConstrained=" << startConstrained
<< ", endConstrained=" << endConstrained << std::endl;
}
if(startConstrained)
{
// If the interval starts on a constraint, use the constrained frame
// as a target (doing this modulo mask.size() in case we're looping)
frame = interval.first - 1;
}
else if (endConstrained)
{
// If the interval ends on a constraint, use the constrained frame
// as a target:
frame = interval.second;
}
else
{
// Otherwise use the midpoint of the interval:
frame = (interval.first + interval.second) / 2;
}
// get the target point:
Math::Vector target = Animation::JointLocalToGlobal(joint_parents_vec, jointIndex, poses[frame]).GetTranslation();
for(int i = interval.first; i < interval.second; ++i)
{
Math::Vector framePt = Animation::JointLocalToGlobal(joint_parents_vec, jointIndex, poses[i]).GetTranslation();
inContact[i] = 1;
points[i] = target;
if (!startConstrained && !endConstrained)
{
points[i].SetY(std::max(framePt.GetY(), minHeight));
// std::cout << " Frame " << i << ": SetY with framePt.GetY()=" << framePt.GetY()
// << ", minHeight=" << minHeight << std::endl;
}
}
}
}
float TargetReachFalloff(
const std::vector<int>& joint_parents_vec,
const Pose& defaultPose,
int32_t jointIndex,
Animation::IKType ikType,
const Math::Vector& target,
const Pose& pose,
const Math::Transform& rootTx = Math::Transform::Identity)
{
float maxReach = defaultPose[jointIndex].GetTranslation().GetLength3();
if (ikType == Animation::IKType::kTwoBone)
{
jointIndex = joint_parents_vec[jointIndex];
ASSERT(jointIndex > -1);
maxReach += defaultPose[jointIndex].GetTranslation().GetLength3();
}
// Get base joint world Tx
jointIndex = joint_parents_vec[jointIndex];
ASSERT(jointIndex > -1);
const auto worldTx = Animation::JointLocalToGlobal(joint_parents_vec, jointIndex, pose, rootTx);
// Gaussian falloff
float targetDist = target.GetDistance3(worldTx.GetTranslation());
float tmp = Math::Max(targetDist / maxReach - 0.99f, 0.f) / 0.01f;
tmp = tmp * tmp;
return std::exp(-2.f * tmp * tmp);
}
void CorrectHipsY(
std::vector<Pose>& poses,
const std::vector<Pose>& targetPoses,
const std::vector<float>& fullBodyMask,
const std::vector<Animation::ContactInfo>& contacts,
float contactThreshold
)
{
// Correct the y coordinates of the root.
auto N = poses.size();
Eigen::MatrixXd x(N, 1);
Eigen::MatrixXd observations(N, 1);
Eigen::MatrixXd xfixed(N, 1);
// Fill in the initial trajectory (x) and the values we want to hit when we
// warp it (observations):
Eigen::VectorXd yCorrectMargins(N);
for(size_t frame = 0; frame < N; ++frame)
{
yCorrectMargins[frame] = fullBodyMask[frame] ? 0.0f : -1.0f;
x(frame, 0) = ((float*)&poses[frame][0].GetTranslation())[1];
observations(frame, 0) = ((float*)&targetPoses[frame][0].GetTranslation())[1];
}
TrajectoryCorrector ycorrector(
yCorrectMargins,
pos_weight * 10,
vel_weight,
acc_weight * 0.1f
);
ycorrector.Interpolate(
xfixed,
observations,
x
);
// fill channel again:
for (uint32_t frame = 0; frame < N; ++frame)
{
((float*)&poses[frame][0].GetTranslation())[1] = float(xfixed(frame, 0));
}
}
void SmoothChannels(
Eigen::MatrixXd &x,
const std::vector<float>& mask
)
{
for( uint32_t i=0; i < mask.size(); ++i)
{
uint32_t i_prev = i == 0 ? 0 : i-1;
uint32_t i_next = std::min(uint32_t(i+1), uint32_t(mask.size()-1));
if(i > 0 && mask[i] > 0 && mask[i_prev] == 0)
{
// if the previous frame is unconstrained and the current frame is constrained,
// replace the current frame with the average of its neighbors:
for(long j=0; j < x.cols(); ++j)
{
x(i, j) = 0.5f * (x(i_prev, j) + x(i_next, j));
}
}
if(mask[i] > 0 && mask[i_next] == 0)
{
// if the next frame is unconstrained and the current frame is constrained,
// replace the current frame with the average of its neighbors:
for(long j=0; j < x.cols(); ++j)
{
x(i, j) = 0.5f * (x(i_prev, j) + x(i_next, j));
}
}
}
}
void CorrectHipsXZ(
std::vector<Pose>& poses,
const std::vector<Pose>& targetPoses,
const std::vector<float>& fullBodyMask,
const std::vector<float>& rootMask,
const std::vector<Animation::ContactInfo>& endEffectorPins,
const Eigen::VectorXd& velocity_weights,
float root_margin
)
{
auto N = poses.size();
Eigen::VectorXd margins(N);
for( size_t i = 0; i < N; ++i )
{
margins[i] = fullBodyMask[i] ? 0.0f : -1.0f;
}
std::vector<float> rootCombinedMask(N, 0.0f);
for(size_t i = 0; i < N; ++i)
{
rootCombinedMask[i] = (fullBodyMask[i] > 0) || (rootMask[i] > 0);
if(rootMask[i] > 0 && margins[i] != 0)
{
margins[i] = root_margin;
}
for (auto& c : endEffectorPins)
{
if (c.contactMask[i] && margins[i] != 0)
{
margins[i] = root_margin;
}
}
}
TrajectoryCorrector xzcorrector(
margins,
pos_weight,
vel_weight,
acc_weight,
velocity_weights
);
// Enforce pose constraints on root xz trajectory:
Eigen::MatrixXd x(N, 2);
Eigen::MatrixXd observations(N, 2);
Eigen::MatrixXd x_fixed(N, 2);
observations.setZero();
for (uint32_t frame = 0; frame < N; ++frame)
{
x(frame, 0) = ((float*)&poses[frame][0].GetTranslation())[0];
x(frame, 1) = ((float*)&poses[frame][0].GetTranslation())[2];
observations(frame, 0) = ((float*)&targetPoses[frame][0].GetTranslation())[0];
observations(frame, 1) = ((float*)&targetPoses[frame][0].GetTranslation())[2];
}
SmoothChannels(x, rootCombinedMask);
xzcorrector.Interpolate(
x_fixed,
observations,
x
);
// fill channels again:
for (uint32_t frame = 0; frame < N; ++frame)
{
((float*)&poses[frame][0].GetTranslation())[0] = float(x_fixed(frame, 0));
((float*)&poses[frame][0].GetTranslation())[2] = float(x_fixed(frame, 1));
}
}
void CorrectRotationsForBone(
std::vector<Pose>& poses,
const std::vector<Pose>& targetPoses,
const std::vector<float>& mask,
const TrajectoryCorrector& corrector,
int boneIdx,
bool performChannelSmoothing)
{
auto N = poses.size();
Eigen::MatrixXd x(N, 1);
Eigen::MatrixXd observations(N, 1);
observations.setZero();
Eigen::MatrixXd x_fixed(N, 1);
// Quaternion components can flip when they pass through 180 degree
// rotations, so let's convert all the quaternions in this channel to
// the forward/up vector representation, modify them, then convert back
// to quaternions:
// convert time series to 6d forward/up:
std::vector<float> forwardUp(6 * N);
std::vector<float> targetForwardUp(6 * N);
for (uint32_t frame = 0; frame < N; ++frame)
{
auto q = poses[frame][boneIdx].GetRotation();
auto forward = q.ZAxis();
auto up = q.YAxis();
forwardUp[N * 0 + frame] = forward.GetX();
forwardUp[N * 1 + frame] = forward.GetY();
forwardUp[N * 2 + frame] = forward.GetZ();
forwardUp[N * 3 + frame] = up.GetX();
forwardUp[N * 4 + frame] = up.GetY();
forwardUp[N * 5 + frame] = up.GetZ();
q = targetPoses[frame][boneIdx].GetRotation();
forward = q.ZAxis();
up = q.YAxis();
targetForwardUp[N * 0 + frame] = forward.GetX();
targetForwardUp[N * 1 + frame] = forward.GetY();
targetForwardUp[N * 2 + frame] = forward.GetZ();
targetForwardUp[N * 3 + frame] = up.GetX();
targetForwardUp[N * 4 + frame] = up.GetY();
targetForwardUp[N * 5 + frame] = up.GetZ();
}
// correct trajectories:
for (uint32_t dim = 0; dim < 6; ++dim)
{
for (uint32_t frame = 0; frame < N; ++frame)
{
x(frame, 0) = forwardUp[N * dim + frame];
observations(frame, 0) = mask[frame] * targetForwardUp[N * dim + frame];
}
if (performChannelSmoothing)
{
SmoothChannels(x, mask);
}
corrector.Interpolate(
x_fixed,
observations,
x
);
// fill channel again:
for (uint32_t frame = 0; frame < N; ++frame)
{
forwardUp[N * dim + frame] = float(x_fixed(frame, 0));
}
}
for (uint32_t frame = 0; frame < N; ++frame)
{
Math::Vector forward = { forwardUp[N * 0 + frame] ,forwardUp[N * 1 + frame] ,forwardUp[N * 2 + frame] };
Math::Vector up = { forwardUp[N * 3 + frame] ,forwardUp[N * 4 + frame] ,forwardUp[N * 5 + frame] };
forward.Normalize3();
up.Normalize3();
poses[frame][boneIdx].SetRotation(Math::Quaternion::LookRotation(forward, up));
}
}
void CorrectJointRotations(
std::vector<Pose>& poses,
const std::vector<Pose>& targetPoses,
const std::vector<float>& fullBodyMask,
const Eigen::VectorXd& velocity_weights
)
{
auto N = poses.size();
// Create a trajectory corrector for fixing the full body fullBodyMask positions:
Eigen::VectorXd margins(N);
for( size_t i = 0; i < N; ++i )
{
margins[i] = fullBodyMask[i] ? 0.0f : -1.0f;
}
TrajectoryCorrector corrector(
margins,
pos_weight * 10,
vel_weight,
acc_weight,
velocity_weights
);
for (uint32_t boneIdx = 0; boneIdx < poses[0].size(); ++boneIdx)
{
CorrectRotationsForBone(
poses,
targetPoses,
fullBodyMask,
corrector,
boneIdx,
true
);
}
}
void DoEffectorIK(
std::vector<Pose>& poses,
const std::vector<Pose>& targetPoses,
const std::vector<float>& fullBodyMask,
const std::vector<Animation::ContactInfo>& endEffectorPins,
const std::vector<int>& joint_parents_vec,
const std::vector<Math::Transform>& defaultPose
)
{
// Apply IK for effector pins
auto N = poses.size();
std::map<uint32_t, std::vector<float>> jointCorrectionMasks;
std::vector<Pose> ikFixedPoses = poses;
for (auto& c : endEffectorPins)
{
auto jointIdx = c.jointIndex;
if(jointCorrectionMasks[jointIdx].empty())
{
// initialize to the full body constraint mask because we
// want to constrain that anyway:
jointCorrectionMasks[jointIdx] = fullBodyMask;
}
// Add a trajectory correction mask for the parent joint:
auto parentIdx = joint_parents_vec[jointIdx];
if(jointCorrectionMasks[parentIdx].empty())
{
// initialize to the full body constraint mask because we
// want to constrain that anyway:
jointCorrectionMasks[parentIdx] = fullBodyMask;
}
// Add a trajectory correction mask for its parent if this is
// 2 bone IK:
auto parentParentIdx = joint_parents_vec[parentIdx];
if(c.contactType == Animation::kTwoBone)
{
if(jointCorrectionMasks[parentParentIdx].empty())
{
// initialize to the full body constraint mask because we
// want to constrain that anyway:
jointCorrectionMasks[parentParentIdx] = fullBodyMask;
}
}
for (uint32_t fixFrame = 0; fixFrame < fullBodyMask.size(); ++fixFrame)
{
if (c.contactMask[fixFrame])
{
const auto targetGlobalTransform = Animation::JointLocalToGlobal(joint_parents_vec, jointIdx, targetPoses[fixFrame]);
// flag the parent joint as fixed in its correction mask:
jointCorrectionMasks[parentIdx][fixFrame] = 1;
switch(c.contactType)
{
case Animation::kOneBone:
{
IK::OneBoneIk(
ikFixedPoses[fixFrame],
Math::Transform::Identity,
jointIdx,
1.0,
targetGlobalTransform.GetTranslation(),
joint_parents_vec
);
break;
}
case Animation::kTwoBone:
{
// flag the parent parent joint as fixed in its correction mask:
jointCorrectionMasks[parentParentIdx][fixFrame] = 1;
IK::TwoBoneIk(
ikFixedPoses[fixFrame],
Math::Transform::Identity,
jointIdx,
1.0,
targetGlobalTransform.GetTranslation(),
joint_parents_vec,
c.hintOffset
);
break;
}
}
// now we need to fix things so the global rotation of the joint
// matches the input:
jointCorrectionMasks[jointIdx][fixFrame] = 1;
auto parentGlobalTransform = Animation::JointLocalToGlobal(joint_parents_vec, parentIdx, ikFixedPoses[fixFrame]);
ikFixedPoses[fixFrame][jointIdx].SetRotation(
targetGlobalTransform.GetRotation() * parentGlobalTransform.GetRotation().GetConjugate()
);
}
}
}
// Applying the effector pin IK introduces popping into the animation,
// so let's apply the interpolator to all the joints we modified so as to
// line the trajectory up properly again:
Eigen::VectorXd margins(N);
for( auto &kv : jointCorrectionMasks)
{
for( size_t i = 0; i < N; ++i )
{
margins[i] = kv.second[i] ? 0.0f : -1.0f;
}
TrajectoryCorrector corrector(margins, pos_weight * 10, vel_weight, acc_weight);
CorrectRotationsForBone(
poses,
ikFixedPoses,
kv.second,
corrector,
kv.first,
false
);
}
}
void DoContactIK(
std::vector<Pose>& poses,
const std::vector<float>& fullBodyMask,
const std::vector<Animation::ContactInfo>& contacts,
const std::vector<Animation::ContactInfo>& endEffectorPins,
const std::vector<int>& joint_parents_vec,
const std::vector<Math::Transform>& defaultPose,
float contactThreshold,
bool has_double_ankle_joints
)
{
auto N = poses.size();
Eigen::VectorXd margins = Eigen::VectorXd::Zero(N);
// Apply IK to stabilize limbs on contacts
std::map<uint32_t, std::vector<float>> jointCorrectionMasks;
std::vector<Pose> ikFixedPoses = poses;
// Save original poses before any modifications (for double ankle correction later)
const std::vector<Pose> originalPoses = poses;
// Track which frames were corrected for each 2-bone contact (for double ankle correction later)
std::map<uint32_t, std::vector<bool>> twoBoneContactFrames;
auto addEndEffectorMask = [&](uint32_t jointIdx, uint32_t parentIdx, std::vector<float>& jointMask)
{
auto it = std::find_if(
endEffectorPins.begin(), endEffectorPins.end(),
[&](const auto &c)
{
if(jointIdx == c.jointIndex)
{
return true;
}
return false;
}
);
if(it == endEffectorPins.end())
{
// We could be correcting the toe joint, in which case we need to use
// the parent joint instead:
it = std::find_if(
endEffectorPins.begin(), endEffectorPins.end(),
[&](const auto &c)
{
if(parentIdx == c.jointIndex)
{
return true;
}
return false;
}
);
}
if(it != endEffectorPins.end())
{
const auto &msk = it->contactMask;
for(size_t i=0; i < msk.size(); ++i)
{
if(msk[i])
{
jointMask[i] = 1.0f;
}
}
}
};
// Process two bone contacts first:
for (auto& c : contacts)
{
if(c.contactType != Animation::kTwoBone)
{
continue;
}
const auto jointIdx = c.jointIndex;
auto parentIdx = joint_parents_vec[jointIdx];
auto parentParentIdx = joint_parents_vec[parentIdx];
auto jointMask = fullBodyMask;
addEndEffectorMask(jointIdx, parentIdx, jointMask);
// We'll actually be modifying 3 joints here:
// * The two joints immediately up in the hierarchy because of the 2 bone IK
// * The joint itself because we restore its original global rotation
if(jointCorrectionMasks[parentIdx].empty())
{
jointCorrectionMasks[parentIdx] = jointMask;
}
if(jointCorrectionMasks[parentParentIdx].empty())
{
jointCorrectionMasks[parentParentIdx] = jointMask;
}
if(jointCorrectionMasks[jointIdx].empty())
{
jointCorrectionMasks[jointIdx] = jointMask;
}
// Compute the intervals in which the joint is in contact with the floor:
auto contactIntervals = ComputeContactIntervals(c.contactMask, jointMask, contactThreshold);
FilterContactIntervals(contactIntervals, jointMask);
std::vector<Math::Vector> contactPoints;
std::vector<int> inContact;
FindContactPoints(
contactPoints,
inContact,
joint_parents_vec,
jointIdx,
poses,
contactIntervals,
jointMask,
c.contactMask.size(),
c.minHeight
);
for (uint32_t fixFrame = 0; fixFrame < fullBodyMask.size(); ++fixFrame)
{
if (inContact[fixFrame])
{
auto target = contactPoints[fixFrame];
jointCorrectionMasks[parentIdx][fixFrame] = 1.0f;
jointCorrectionMasks[parentParentIdx][fixFrame] = 1.0f;
jointCorrectionMasks[jointIdx][fixFrame] = 1.0f;
// Track this frame for double ankle correction later
if (has_double_ankle_joints)
{
if (twoBoneContactFrames[jointIdx].empty())
twoBoneContactFrames[jointIdx].resize(fullBodyMask.size(), false);
twoBoneContactFrames[jointIdx][fixFrame] = true;
}
// save the original global rotation of the joint:
auto jointGlobalRotation = Animation::JointLocalToGlobal(
joint_parents_vec,
jointIdx,
ikFixedPoses[fixFrame]
).GetRotation();
const float w = TargetReachFalloff(
joint_parents_vec,
defaultPose,
jointIdx,
c.contactType,
target,
ikFixedPoses[fixFrame]
);
// std::cout << "Frame " << fixFrame << ": w=" << w << std::endl;
// apply the 2 bone IK:
auto origParentRotation = ikFixedPoses[fixFrame][parentIdx].GetRotation();
auto origParentParentRotation = ikFixedPoses[fixFrame][parentParentIdx].GetRotation();
IK::TwoBoneIk(
ikFixedPoses[fixFrame],
Math::Transform::Identity,
jointIdx,
1.0f,
target,
joint_parents_vec,
c.hintOffset
);
ikFixedPoses[fixFrame][parentIdx].SetRotation(Math::Quaternion::SLerp(origParentRotation, ikFixedPoses[fixFrame][parentIdx].GetRotation(), w));
ikFixedPoses[fixFrame][parentParentIdx].SetRotation(Math::Quaternion::SLerp(origParentParentRotation, ikFixedPoses[fixFrame][parentParentIdx].GetRotation(), w));
// restore previous global rotation of this joint:
auto parentGloblalRotation = Animation::JointLocalToGlobal(
joint_parents_vec,
parentIdx,
ikFixedPoses[fixFrame]
).GetRotation();
jointCorrectionMasks[jointIdx][fixFrame] = 1.0f;
ikFixedPoses[fixFrame][jointIdx].SetRotation(
jointGlobalRotation * parentGloblalRotation.GetConjugate()
);
auto result = Animation::JointLocalToGlobal(
joint_parents_vec,
jointIdx,
ikFixedPoses[fixFrame]
).GetTranslation();
}
}
}
for( auto &kv : jointCorrectionMasks)
{
for( size_t i = 0; i < N; ++i )
{
margins[i] = kv.second[i] ? 0.0f : -1.0f;
}
TrajectoryCorrector corrector(margins, pos_weight * 10, vel_weight, acc_weight);
CorrectRotationsForBone(
poses,
ikFixedPoses,
kv.second,
corrector,
kv.first,
false
);
}
jointCorrectionMasks.clear();
// Then process one bone contacts:
for(auto &c : contacts)
{
if(c.contactType != Animation::kOneBone)
{
continue;
}
const auto jointIdx = c.jointIndex;
auto parentIdx = joint_parents_vec[jointIdx];
// We can't touch frames that have been constrained with full body constraints
// or the end effector constraints for this joint, so let's combine fullBodyMask
// with the end effector mask for this joint if it exists so we can use that
// information later:
auto jointMask = fullBodyMask;
addEndEffectorMask(jointIdx, parentIdx, jointMask);
// Add a trajectory correction mask for the parent joint:
if(jointCorrectionMasks[parentIdx].empty())
{
jointCorrectionMasks[parentIdx] = jointMask;
}
// Compute the intervals in which the joint is in contact with the floor:
auto contactIntervals = ComputeContactIntervals(c.contactMask, jointMask, contactThreshold);
FilterContactIntervals(contactIntervals, jointMask, true);
for(const auto &interval : contactIntervals)
{
for (int fixFrame = interval.first; fixFrame < interval.second; ++fixFrame)
{
// All we're going to do here is stick the joint to the floor -
// we're going to allow it to slide from side to side.
// Find a target position that lies on the floor by iteratively
// projecting the joint to the floor (pure laziness really, this could
// be done analytically):
Math::Vector parentPos = Animation::JointLocalToGlobal(joint_parents_vec, parentIdx, ikFixedPoses[fixFrame]).GetTranslation();
Math::Vector target = Animation::JointLocalToGlobal(joint_parents_vec, jointIdx, ikFixedPoses[fixFrame]).GetTranslation();
float jointLength = (target - parentPos).GetLength3();
for(int32_t i = 0; i < 10; ++i)
{
target.SetY(c.minHeight);
auto dir = (target - parentPos).GetNormalized3();
target = parentPos + dir * jointLength;
}
IK::OneBoneIk(
ikFixedPoses[fixFrame],
Math::Transform::Identity,
jointIdx,
1.0f,
target,
joint_parents_vec
);
jointCorrectionMasks[parentIdx][fixFrame] = 1.0f;
}
}
}
// Fixing the contacts with IK will introduce popping into the animation,
// so let's apply the interpolator to all the joints we modified so as to
// line the trajectory up properly again:
for( auto &kv : jointCorrectionMasks)
{
for( size_t i = 0; i < N; ++i )
{
margins[i] = kv.second[i] ? 0.0f : -1.0f;
}
TrajectoryCorrector corrector(margins, pos_weight * 10, vel_weight, acc_weight);
CorrectRotationsForBone(
poses,
ikFixedPoses,
kv.second,
corrector,
kv.first,
false
);
}
if (has_double_ankle_joints)
{
// Maps to save target positions BEFORE 2-bone IK modifies them
std::map<uint32_t, std::map<uint32_t, Math::Vector>> savedFirstAnkleTargets; // [firstAnkleIdx][frame] -> position
std::map<uint32_t, std::map<uint32_t, Math::Vector>> savedToeTargets; // [firstAnkleIdx][frame] -> position
std::map<uint32_t, uint32_t> contactToToeIdx; // firstAnkleIdx -> toeIdx
// Find toe joints for each leg
for (const auto& tc : contacts)
{
if (tc.contactType == Animation::kOneBone)
{
// The parent of the toe is the 1st ankle
int parentIdx = joint_parents_vec[tc.jointIndex];
if (parentIdx >= 0)
{
contactToToeIdx[parentIdx] = tc.jointIndex;
}
}
}
// For each 2-bone contact, correct the parent (2nd ankle) joint
for (auto& c : contacts)
{
if (c.contactType != Animation::kTwoBone)
continue;
const auto firstAnkleIdx = c.jointIndex;
const auto secondAnkleIdx = joint_parents_vec[firstAnkleIdx];
const auto kneeIdx = joint_parents_vec[secondAnkleIdx];
const auto hipIdx = joint_parents_vec[kneeIdx];
if (hipIdx < 0) continue; // safety check
// Get saved contact frames for this ankle
auto it = twoBoneContactFrames.find(firstAnkleIdx);
if (it == twoBoneContactFrames.end())
continue;
const auto& contactFrames = it->second;
// Add correction mask for knee and hip
auto jointMask = fullBodyMask;
addEndEffectorMask(firstAnkleIdx, secondAnkleIdx, jointMask);
if (jointCorrectionMasks[kneeIdx].empty())
jointCorrectionMasks[kneeIdx] = jointMask;
if (jointCorrectionMasks[hipIdx].empty())
jointCorrectionMasks[hipIdx] = jointMask;
for (uint32_t fixFrame = 0; fixFrame < fullBodyMask.size(); ++fixFrame)
{
// Only correct frames where the 1st ankle was corrected
if (!contactFrames[fixFrame])
continue;
// *** SAVE TARGET POSITIONS BEFORE 2-BONE IK ***
savedFirstAnkleTargets[firstAnkleIdx][fixFrame] = Animation::JointLocalToGlobal(
joint_parents_vec, firstAnkleIdx, ikFixedPoses[fixFrame]).GetTranslation();
if (contactToToeIdx.count(firstAnkleIdx))
{
savedToeTargets[firstAnkleIdx][fixFrame] = Animation::JointLocalToGlobal(
joint_parents_vec, contactToToeIdx[firstAnkleIdx], ikFixedPoses[fixFrame]).GetTranslation();
}
// Get original global transforms (before any IK corrections)
auto originalFirstAnkleGlobal = Animation::JointLocalToGlobal(
joint_parents_vec, firstAnkleIdx, originalPoses[fixFrame]);
auto originalSecondAnkleGlobal = Animation::JointLocalToGlobal(
joint_parents_vec, secondAnkleIdx, originalPoses[fixFrame]);
// Compute delta from 1st ankle to 2nd ankle in original animation
auto deltaFirstToSecond = originalFirstAnkleGlobal.GetDeltaToOther(originalSecondAnkleGlobal);
// Get corrected 1st ankle global transform
auto correctedFirstAnkleGlobal = Animation::JointLocalToGlobal(
joint_parents_vec, firstAnkleIdx, ikFixedPoses[fixFrame]);
// Apply the original delta to the corrected 1st ankle to get target for 2nd ankle
auto target = (deltaFirstToSecond * correctedFirstAnkleGlobal).GetTranslation();
// print current and target second ankle positions
auto currPos = Animation::JointLocalToGlobal(
joint_parents_vec, secondAnkleIdx, ikFixedPoses[fixFrame]).GetTranslation();
// Apply 2-bone IK: Hip -> Knee -> 2nd Ankle
IK::TwoBoneIk(
ikFixedPoses[fixFrame],
Math::Transform::Identity,
secondAnkleIdx,
1.0f,
target,
joint_parents_vec,
c.hintOffset
);
// auto correctedPos = Animation::JointLocalToGlobal(
// joint_parents_vec, secondAnkleIdx, ikFixedPoses[fixFrame]).GetTranslation();
// std::cout << "Frame " << fixFrame << ": target second ankle=(" << target.GetX() << ", " << target.GetY() << ", " << target.GetZ() << "), corrected second ankle position=(" << correctedPos.GetX() << ", " << correctedPos.GetY() << ", " << correctedPos.GetZ() << ")" << std::endl;
jointCorrectionMasks[kneeIdx][fixFrame] = 1.0f;
jointCorrectionMasks[hipIdx][fixFrame] = 1.0f;
}
}
// Smooth the corrected joints
for (auto& kv : jointCorrectionMasks)
{
for (size_t i = 0; i < N; ++i)
margins[i] = kv.second[i] ? 0.0f : -1.0f;
TrajectoryCorrector corrector(margins, pos_weight * 10, vel_weight, acc_weight);
CorrectRotationsForBone(poses, ikFixedPoses, kv.second, corrector, kv.first, false);
}
// *** PHASE 2: 1-bone IKs to restore 1st ankle and toe ***
jointCorrectionMasks.clear();
for (auto& c : contacts)
{
if (c.contactType != Animation::kTwoBone)
continue;
const auto firstAnkleIdx = c.jointIndex;
const auto secondAnkleIdx = joint_parents_vec[firstAnkleIdx];
auto it = twoBoneContactFrames.find(firstAnkleIdx);
if (it == twoBoneContactFrames.end())
continue;
// Setup correction masks
auto jointMask = fullBodyMask;
addEndEffectorMask(firstAnkleIdx, secondAnkleIdx, jointMask);
if (jointCorrectionMasks[secondAnkleIdx].empty())
jointCorrectionMasks[secondAnkleIdx] = jointMask;
if (jointCorrectionMasks[firstAnkleIdx].empty())
jointCorrectionMasks[firstAnkleIdx] = jointMask;
for (uint32_t fixFrame = 0; fixFrame < fullBodyMask.size(); ++fixFrame)
{
if (!it->second[fixFrame])
continue;
// 1-bone IK: Rotate 2nd ankle so 1st ankle reaches saved target
IK::OneBoneIk(
ikFixedPoses[fixFrame],
Math::Transform::Identity,
firstAnkleIdx,
1.0f,
savedFirstAnkleTargets[firstAnkleIdx][fixFrame],
joint_parents_vec
);
jointCorrectionMasks[secondAnkleIdx][fixFrame] = 1.0f;
// auto target = savedFirstAnkleTargets[firstAnkleIdx][fixFrame];
// auto corrected = Animation::JointLocalToGlobal(
// joint_parents_vec, firstAnkleIdx, ikFixedPoses[fixFrame]).GetTranslation();
// std::cout << "Frame " << fixFrame << ": target first ankle=(" << target.GetX() << ", " << target.GetY() << ", " << target.GetZ() << "), corrected first ankle=(" << corrected.GetX() << ", " << corrected.GetY() << ", " << corrected.GetZ() << ")" << std::endl;
// 1-bone IK: Rotate 1st ankle so toe reaches saved target
if (contactToToeIdx.count(firstAnkleIdx) && savedToeTargets[firstAnkleIdx].count(fixFrame))
{
IK::OneBoneIk(
ikFixedPoses[fixFrame],
Math::Transform::Identity,
contactToToeIdx[firstAnkleIdx],
1.0f,
savedToeTargets[firstAnkleIdx][fixFrame],
joint_parents_vec
);
jointCorrectionMasks[firstAnkleIdx][fixFrame] = 1.0f;
}
// target = savedToeTargets[firstAnkleIdx][fixFrame];
// corrected = Animation::JointLocalToGlobal(
// joint_parents_vec, contactToToeIdx[firstAnkleIdx], ikFixedPoses[fixFrame]).GetTranslation();
// std::cout << "Frame " << fixFrame << ": target toe=(" << target.GetX() << ", " << target.GetY() << ", " << target.GetZ() << "), corrected toe=(" << corrected.GetX() << ", " << corrected.GetY() << ", " << corrected.GetZ() << ")" << std::endl;
}
}
// Smooth 2nd ankle and 1st ankle
for (auto& kv : jointCorrectionMasks)
{
for (size_t i = 0; i < N; ++i)
margins[i] = kv.second[i] ? 0.0f : -1.0f;
TrajectoryCorrector corrector(margins, pos_weight * 10, vel_weight, acc_weight);
CorrectRotationsForBone(poses, ikFixedPoses, kv.second, corrector, kv.first, false);
}
}
}
}
Math::Transform Animation::JointLocalToGlobal(
const std::vector<int>& joint_parents_vec,
int32_t index,
const Pose& localPose,
const Math::Transform& rootTx)
{
Math::Transform worldTx = Math::Transform::Identity;
while (index > -1)
{
worldTx = worldTx * localPose[index];
index = joint_parents_vec[index];
}
return worldTx * rootTx;
}
void Animation::CorrectMotion(
std::vector<Pose>& poses,
const std::vector<Pose>& targetPoses,
const std::vector<float>& fullBodyMask,
const std::vector<float>& rootMask,
const std::vector<ContactInfo>& contacts,
const std::vector<ContactInfo>& endEffectorPins,
const std::vector<int>& joint_parents_vec,
const std::vector<Math::Transform>& defaultPose,
float contactThreshold,
float root_margin,
bool has_double_ankle_joints
)
{
// Calculate some weights so we can preserve velocities more strongly on frames where
// the root velocity is low
const uint32_t N = poses.size();
Eigen::VectorXd velocity_weights(N);
for (uint32_t frame = 1; frame < N; ++frame)
{
// work out xz velocity for this frame:
float xdiff = poses[frame][0].GetTranslation()[0] - poses[frame - 1][0].GetTranslation()[0];
float zdiff = poses[frame][0].GetTranslation()[2] - poses[frame - 1][0].GetTranslation()[2];
// find velocity magnitude, divided by a typical walking speed:
float v_mag = sqrtf(xdiff*xdiff + zdiff*zdiff) / 0.05f;
// weight lower velocities higher so that the corrector doesn't make the character drift around
// when it's supposed to stand still:
v_mag = std::max(v_mag, 1.0f/1000.0f);
velocity_weights(frame) = 1.0f / v_mag;
}
velocity_weights[0] = velocity_weights[1];
// Correct root y coordinates.
// This will warp the root y coordinates in "poses" so they match the root y coordinates
// in "targetPoses", on frames where the root y coordinates are constrained, ie the frames
// where fullBodyMask = 1.
// In addition to this, it preserves the root y coordinates in "pose" on frames where foot
// contacts are active, to avoid mushiness when characters are jumping.
CorrectHipsY(
poses,
targetPoses,
fullBodyMask,
contacts,
contactThreshold
);
// Correct root xz coordinates:
// This will warp the root xz coordinates in "poses" so they match the xz coordinates
// in "targetPoses" on frames where fullBodyMask = 1, and warp them so they're within
// "root_margin" units of targetPoses on frames where rootMask = 1.
CorrectHipsXZ(
poses,
targetPoses,
fullBodyMask,
rootMask,
endEffectorPins,
velocity_weights,
root_margin
);
// Correct joint rotations by warping the rotations so they match targetPoses on frames
// where fullBodyMask = 1:
CorrectJointRotations(
poses,
targetPoses,
fullBodyMask,
velocity_weights
);
// Apply IK for end effector pins
DoEffectorIK(
poses,
targetPoses,
fullBodyMask,
endEffectorPins,
joint_parents_vec,
defaultPose
);
// Apply IK to stabilize limbs on contacts
DoContactIK(
poses,
fullBodyMask,
contacts,
endEffectorPins,
joint_parents_vec,
defaultPose,
contactThreshold,
has_double_ankle_joints
);
// std::cout << "Running post processing." << std::endl;
}
================================================
FILE: MotionCorrection/src/cpp/AnimProcessing/Utility.h
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "Math/Transform.h"
#include <string>
#include <vector>
namespace Animation
{
enum IKType {
kOneBone,
kTwoBone
};
Math::Transform JointLocalToGlobal(
const std::vector<int>& joint_parents_vec,
int32_t index,
const std::vector<Math::Transform>& localPose,
const Math::Transform& rootTx = Math::Transform::Identity
);
struct ContactInfo {
// index IK contact joint:
int jointIndex;
// mask indicating which frames are in contact:
std::vector<float> contactMask;
// contact type:
IKType contactType = kTwoBone;
// Extra info for TwoBoneIK
Math::Vector hintOffset = Math::Vector::Zero;
float minHeight = 0.0f;
};
void CorrectMotion(
std::vector< std::vector<Math::Transform> >& poses,
const std::vector< std::vector<Math::Transform> >& targetPoses,
const std::vector<float>& mask,
const std::vector<float>& rootMask,
const std::vector<ContactInfo>& contacts,
const std::vector<ContactInfo>& endEffectorPins,
const std::vector<int>& joint_parents_vec,
const std::vector<Math::Transform>& defaultPose,
float contactThreshold,
float root_margin,
bool has_double_ankle_joints
);
}
================================================
FILE: MotionCorrection/src/cpp/BindingsPython.cpp
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "AnimProcessing/Utility.h"
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4623 4191 4686 4868 5219 4191 4355)
#endif
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#ifdef _WIN32
#pragma warning(pop)
#endif
namespace py = pybind11;
float strip_nan_inf(float x) noexcept
{
if (std::isnan(x)) return 0;
if (std::isinf(x)) return 0;
return x;
}
void correct_motion(
py::array_t<float> &rootTranslations,
py::array_t<float> &jointRotations,
const py::array_t<float>& rootTranslationsTarget,
const py::array_t<float>& jointRotationsTarget,
const py::array_t<float>& fullPoseMask,
const py::array_t<float>& leftHandMask,
const py::array_t<float>& rightHandMask,
const py::array_t<float>& leftFootMask,
const py::array_t<float>& rightFootMask,
const py::array_t<float>& rootMask,
const py::array_t<float>& contacts,
const py::list& joint_parents,
const py::list& joint_ref_translations,
const py::list& joint_ref_rotations,
int left_hand_idx,
int right_hand_idx,
int left_foot_idx,
int right_foot_idx,
float contact_threshold,
float root_margin,
bool has_double_ankle_joints
)
{
if(joint_parents.size() != joint_ref_translations.size())
{
throw std::runtime_error("correct_motion python bindings: joint_parents and joint_ref_translations must have the same size");
}
if(joint_parents.size() != joint_ref_rotations.size())
{
throw std::runtime_error("correct_motion python bindings: joint_parents and joint_ref_rotations must have the same size");
}
if(left_hand_idx < 0 || right_hand_idx < 0 || left_foot_idx < 0 || right_foot_idx < 0)
{
throw std::runtime_error("correct_motion python bindings: left_hand_idx, right_hand_idx, left_foot_idx, and right_foot_idx must be non-negative");
}
if(left_hand_idx >= joint_parents.size() || right_hand_idx >= joint_parents.size() || left_foot_idx >= joint_parents.size() || right_foot_idx >= joint_parents.size())
{
throw std::runtime_error("correct_motion python bindings: left_hand_idx, right_hand_idx, left_foot_idx, and right_foot_idx must be less than the number of joints");
}
std::vector<Math::Transform> defaultPose(joint_parents.size());
for (size_t i = 0; i < joint_ref_translations.size(); ++i)
{
if (!py::isinstance<py::list>(joint_ref_translations[i]))
{
throw std::runtime_error("correct_motion python bindings: Expected joint_ref_translations to be a list of lists");
}
py::list inner_list = joint_ref_translations[i].cast<py::list>();
if (inner_list.size() != 3) {
throw std::runtime_error("correct_motion python bindings: Expected joint_ref_translations to be a list of lists, length 3");
}
if (
!py::isinstance<py::float_>(inner_list[0]) ||
!py::isinstance<py::float_>(inner_list[1]) ||
!py::isinstance<py::float_>(inner_list[2])
)
{
throw std::runtime_error("correct_motion python bindings: Expected joint_ref_translations to be a list of lists, length 3, float values");
}
if (!py::isinstance<py::list>(joint_ref_rotations[i]))
{
throw std::runtime_error("correct_motion python bindings: Expected joint_ref_rotations to be a list of lists");
}
py::list inner_list_rot = joint_ref_rotations[i].cast<py::list>();
if (inner_list_rot.size() != 4) {
throw std::runtime_error("correct_motion python bindings: Expected joint_ref_rotations to be a list of lists, length 4");
}
if (
!py::isinstance<py::float_>(inner_list_rot[0]) ||
!py::isinstance<py::float_>(inner_list_rot[1]) ||
!py::isinstance<py::float_>(inner_list_rot[2]) ||
!py::isinstance<py::float_>(inner_list_rot[3])
)
{
throw std::runtime_error("correct_motion python bindings: Expected joint_ref_rotations to be a list of lists, length 4, float values");
}
defaultPose[i].SetTranslation(Math::Vector(
inner_list[0].cast<float>(),
inner_list[1].cast<float>(),
inner_list[2].cast<float>()));
defaultPose[i].SetRotation(Math::Quaternion(
inner_list_rot[0].cast<float>(),
inner_list_rot[1].cast<float>(),
inner_list_rot[2].cast<float>(),
inner_list_rot[3].cast<float>()
));
}
std::vector<int> joint_parents_vec(joint_parents.size());
for (size_t i = 0; i < joint_parents.size(); ++i)
{
if (!py::isinstance<py::int_>(joint_parents[i]))
{
throw std::runtime_error("correct_motion python bindings: Expected joint_parents to be a list of ints");
}
joint_parents_vec[i] = joint_parents[i].cast<int>();
if (joint_parents_vec[i] >= (int)joint_parents.size())
{
throw std::runtime_error("correct_motion python bindings: joint_parents must be a list of ints, and all values must be less than the number of joints");
}
}
size_t num_joints = defaultPose.size();
size_t gen_length = fullPoseMask.size();
if(
leftHandMask.size() != (int)gen_length ||
rightHandMask.size() != (int)gen_length ||
leftFootMask.size() != (int)gen_length ||
rightFootMask.size() != (int)gen_length ||
rootMask.size() != (int)gen_length
)
{
throw std::runtime_error("correct_motion python bindings: all masks must have the same size");
}
if(rootTranslations.size() != 3 * (int)gen_length)
{
throw std::runtime_error("correct_motion python bindings: rootTranslations has the wrong size");
}
if(jointRotations.size() != 4 * (int)num_joints * (int)gen_length)
{
throw std::runtime_error("correct_motion python bindings: jointRotations has the wrong size");
}
if(rootTranslationsTarget.size() != 3 * (int)gen_length)
{
throw std::runtime_error("correct_motion python bindings: rootTranslationsTarget has the wrong size");
}
if(jointRotationsTarget.size() != 4 * (int)num_joints * (int)gen_length)
{
throw std::runtime_error("correct_motion python bindings: jointRotationsTarget has the wrong size");
}
std::vector<Animation::ContactInfo> endEffectorPins(4);
endEffectorPins[0].jointIndex = left_hand_idx;
endEffectorPins[0].hintOffset = Math::Vector(0.0f, 0.0f, -0.1f);
endEffectorPins[1].jointIndex = right_hand_idx;
endEffectorPins[1].hintOffset = Math::Vector(0.0f, 0.0f, -0.1f);
endEffectorPins[2].jointIndex = left_foot_idx;
endEffectorPins[2].hintOffset = Math::Vector(0.0f, 0.0f, 0.1f);
endEffectorPins[3].jointIndex = right_foot_idx;
endEffectorPins[3].hintOffset = Math::Vector(0.0f, 0.0f, 0.1f);
endEffectorPins[0].contactMask.reserve(gen_length);
endEffectorPins[1].contactMask.reserve(gen_length);
endEffectorPins[2].contactMask.reserve(gen_length);
endEffectorPins[3].contactMask.reserve(gen_length);
for(size_t i = 0; i < gen_length; ++i)
{
endEffectorPins[0].contactMask.push_back((1.0f - fullPoseMask.at(i)) * leftHandMask.at(i));
endEffectorPins[1].contactMask.push_back((1.0f - fullPoseMask.at(i)) * rightHandMask.at(i));
endEffectorPins[2].contactMask.push_back((1.0f - fullPoseMask.at(i)) * leftFootMask.at(i));
endEffectorPins[3].contactMask.push_back((1.0f - fullPoseMask.at(i)) * rightFootMask.at(i));
}
std::vector<Animation::ContactInfo> contactInfo(2);
auto footTranslation = Animation::JointLocalToGlobal(
joint_parents_vec,
right_foot_idx,
defaultPose
).GetTranslation();
contactInfo[0].jointIndex = right_foot_idx;
contactInfo[0].hintOffset = Math::Vector(0.0f, 0.0f, 0.1f);
contactInfo[0].minHeight = footTranslation.GetY();
footTranslation = Animation::JointLocalToGlobal(
joint_parents_vec,
left_foot_idx,
defaultPose
).GetTranslation();
contactInfo[1].jointIndex = left_foot_idx;
contactInfo[1].hintOffset = Math::Vector(0.0f, 0.0f, 0.1f);
contactInfo[1].minHeight = footTranslation.GetY();
auto& rContacts = contactInfo[0].contactMask;
auto& lContacts = contactInfo[1].contactMask;
rContacts.resize(fullPoseMask.size());
lContacts.resize(fullPoseMask.size());
for (int i = 0; i < fullPoseMask.size(); ++i)
{
// don't flag it as a contact if it's been masked:
rContacts[i] = rightFootMask.at(i) ? 0 : contacts.at(4 * i + 2);
lContacts[i] = leftFootMask.at(i) ? 0 : contacts.at(4 * i + 0);
// Flag the heel as a contact if the toe is a contact:
rContacts[i] = std::min((rightFootMask.at(i) ? 0 : contacts.at(4 * i + 3)) + rContacts[i], 1.0f);
lContacts[i] = std::min((leftFootMask.at(i) ? 0 : contacts.at(4 * i + 1)) + lContacts[i], 1.0f);
}
int left_toe_idx = -1;
int right_toe_idx = -1;
for(int i = 0; i < num_joints; ++i)
{
if(joint_parents_vec[i] == left_foot_idx)
{
left_toe_idx = i;
}
if(joint_parents_vec[i] == right_foot_idx)
{
right_toe_idx = i;
}
}
if(left_toe_idx != -1 && right_toe_idx != -1)
{
auto toeTranslation = Animation::JointLocalToGlobal(
joint_parents_vec,
right_toe_idx,
defaultPose
).GetTranslation();
contactInfo.resize(4);
contactInfo[2].jointIndex = right_toe_idx;
contactInfo[2].contactType = Animation::kOneBone;
contactInfo[2].minHeight = toeTranslation.GetY();
contactInfo[3].jointIndex = left_toe_idx;
contactInfo[3].contactType = Animation::kOneBone;
contactInfo[3].minHeight = toeTranslation.GetY();
auto& rToeContacts = contactInfo[2].contactMask;
auto& lToeContacts = contactInfo[3].contactMask;
// fill up the ankle contacts:
rToeContacts.resize(fullPoseMask.size());
lToeContacts.resize(fullPoseMask.size());
for (int i = 0; i < fullPoseMask.size(); ++i)
{
// don't flag it as a contact if it's been masked:
rToeContacts[i] = rightFootMask.at(i) ? 0 : contacts.at(4 * i + 3);
lToeContacts[i] = leftFootMask.at(i) ? 0 : contacts.at(4 * i + 1);
}
}
auto setTransforms = [gen_length, num_joints](
std::vector< std::vector<Math::Transform> > &poses,
const py::array_t<float> &rootTranslations,
const py::array_t<float> &jointRotations
)
{
for (size_t f = 0; f < gen_length; ++f)
{
poses[f][0].SetTranslation({
strip_nan_inf(rootTranslations.at(3*f+0)),
strip_nan_inf(rootTranslations.at(3*f+1)),
strip_nan_inf(rootTranslations.at(3*f+2))
});
}
for (size_t f = 0; f < gen_length; ++f)
{
for (size_t j = 0; j < num_joints; ++j)
{
// x y z w order:
Math::Quaternion q(
strip_nan_inf(jointRotations.at(4 * (num_joints * f + j) + 1)),
strip_nan_inf(jointRotations.at(4 * (num_joints * f + j) + 2)),
strip_nan_inf(jointRotations.at(4 * (num_joints * f + j) + 3)),
strip_nan_inf(jointRotations.at(4 * (num_joints * f + j) + 0))
);
q.Normalize();
poses[f][j].SetRotation(q);
}
}
};
std::vector< std::vector<Math::Transform> > posesFixed(gen_length, defaultPose);
setTransforms(posesFixed, rootTranslations, jointRotations);
std::vector< std::vector<Math::Transform> > posesTarget(gen_length, defaultPose);
setTransforms(posesTarget, rootTranslationsTarget, jointRotationsTarget);
std::vector<float> fullPoseMask_vec;
std::vector<float> rootMask_vec;
for (size_t f = 0; f < gen_length; ++f)
{
fullPoseMask_vec.push_back(fullPoseMask.at(f));
rootMask_vec.push_back(rootMask.at(f));
}
Animation::CorrectMotion(
posesFixed,
posesTarget,
fullPoseMask_vec,
rootMask_vec,
contactInfo,
endEffectorPins,
joint_parents_vec,
defaultPose,
contact_threshold,
root_margin,
has_double_ankle_joints
);
for (size_t f = 0; f < gen_length; ++f)
{
auto t = posesFixed[f][0].GetTranslation();
rootTranslations.mutable_at(3*f+0) = t.GetX();
rootTranslations.mutable_at(3*f+1) = t.GetY();
rootTranslations.mutable_at(3*f+2) = t.GetZ();
}
for (size_t f = 0; f < gen_length; ++f)
{
for (size_t j = 0; j < num_joints; ++j)
{
auto q = posesFixed[f][j].GetRotation();
// w x y z order
jointRotations.mutable_at(4 * (num_joints * f + j) + 0) = ((float*)&q)[3];
jointRotations.mutable_at(4 * (num_joints * f + j) + 1) = ((float*)&q)[0];
jointRotations.mutable_at(4 * (num_joints * f + j) + 2) = ((float*)&q)[1];
jointRotations.mutable_at(4 * (num_joints * f + j) + 3) = ((float*)&q)[2];
}
}
}
PYBIND11_MODULE(_motion_correction, m) {
m.doc() = "Motion Correction Python bindings";
m.def("correct_motion", &correct_motion);
}
================================================
FILE: MotionCorrection/src/cpp/Compiler.h
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
// Compiler specific defines
// Finds the compiler type and version.
#if defined(__clang__)
# define COMPILER_CLANG
#elif defined(__GNUC__) // Check after Clang, as Clang defines this too
# define COMPILER_GNUC
#elif defined(_MSC_VER) // Check after Clang, since we could be building with either within VS
# define COMPILER_MSVC
#else
# pragma error "Unknown compiler. "
#endif
#if defined(COMPILER_MSVC)
#define FORCE_INLINE __forceinline
#elif defined(COMPILER_GNUC)
#define FORCE_INLINE inline __attribute__((always_inline))
#endif
================================================
FILE: MotionCorrection/src/cpp/Debug.h
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "Platform.h"
#define ASSERT( cond ) do { if( !(cond) ) { DEBUG_BREAK(); } } while( 0 )
#define HALT() { DEBUG_BREAK(); }
#define UNIMPLEMENTED_FUNCTION() { DEBUG_BREAK(); }
#define UNREACHABLE_CODE() { DEBUG_BREAK(); }
================================================
FILE: MotionCorrection/src/cpp/Math/Constants.h
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <limits>
// Mathematical constants
namespace Math
{
static constexpr float const Epsilon = 1.0e-06f;
static constexpr float const LargeEpsilon = 1.0e-04f;
static constexpr float const HugeEpsilon = 1.0e-02f;
static constexpr float const Pi = 3.141592654f;
static constexpr float const TwoPi = 6.283185307f;
static constexpr float const OneDivPi = 0.318309886f;
static constexpr float const OneDivTwoPi = 0.159154943f;
static constexpr float const PiDivTwo = 1.570796327f;
static constexpr float const PiDivFour = 0.785398163f;
static constexpr float const SqrtTwo = 1.4142135623730950488016887242097f;
static constexpr float const OneDivSqrtTwo = 1.0f / SqrtTwo;
static constexpr float const DegreesToRadians = 0.0174532925f;
static constexpr float const RadiansToDegrees = 57.2957795f;
static constexpr float const Infinity = std::numeric_limits<float>::infinity();
static constexpr float const QNaN = std::numeric_limits<float>::quiet_NaN();
}
================================================
FILE: MotionCorrection/src/cpp/Math/Matrix.cpp
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "Matrix.h"
#include <cfloat>
using namespace Math;
namespace
{
static bool CheckForZeroScaleInRow(float scale, const Vector& row)
{
float const absScale = Math::Abs(scale);
for (int i = 0; i < 3; i++)
{
if (absScale < 1 && Math::Abs(row[i]) >= FLT_MAX * absScale)
{
return false;
}
}
return true;
}
static bool ExtractAndRemoveScalingAndShear(Matrix& matrix, Vector& scale, Vector& shear)
{
scale = Vector::Zero;
shear = Vector::Zero;
Float3 scaleValues = Float3::Zero;
Float3 shearValues = Float3::Zero;
// This implementation follows the technique described in the paper by
// Spencer W. Thomas in the Graphics Gems II article: "Decomposing a
// Matrix into Simple Transformations", p. 320.
Vector row[3];
row[0] = Vector(matrix[0][0], matrix[0][1], matrix[0][2]);
row[1] = Vector(matrix[1][0], matrix[1][1], matrix[1][2]);
row[2] = Vector(matrix[2][0], matrix[2][1], matrix[2][2]);
float maxVal = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (Math::Abs(row[i][j]) > maxVal)
{
maxVal = Math::Abs(row[i][j]);
}
}
}
// We normalize the 3x3 matrix here.
// It was noticed that this can improve numerical stability significantly,
// especially when many of the upper 3x3 matrix's coefficients are very
// close to zero; we correct for this step at the end by multiplying the
// scaling factors by maxVal at the end (shear and rotation are not
// affected by the normalization).
if (maxVal != 0)
{
for (int i = 0; i < 3; i++)
{
if (!CheckForZeroScaleInRow(maxVal, row[i]))
{
return false;
}
else
{
row[i] /= maxVal;
}
}
}
// Compute X scale factor.
scaleValues.m_x = row[0].Length3().ToFloat();
if (!CheckForZeroScaleInRow(scaleValues.m_x, row[0]))
{
return false;
}
// Normalize first row.
row[0] /= scaleValues.m_x;
// An XY shear factor will shear the X coord. as the Y coord. changes.
// There are 6 combinations (XY, XZ, YZ, YX, ZX, ZY), although we only
// extract the first 3 because we can effect the last 3 by shearing in
// XY, XZ, YZ combined rotations and scales.
//
// shear matrix < 1, YX, ZX, 0,
// XY, 1, ZY, 0,
// XZ, YZ, 1, 0,
// 0, 0, 0, 1 >
// Compute XY shear factor and make 2nd row orthogonal to 1st.
shearValues[0] = Vector::Dot3(row[0], row[1]).ToFloat();
row[1] -= row[0] * shearValues[0];
// Now, compute Y scale.
scaleValues.m_y = row[1].Length3().ToFloat();
if (!CheckForZeroScaleInRow(scaleValues.m_y, row[1]))
{
return false;
}
// Normalize 2nd row and correct the XY shear factor for Y scaling.
row[1] /= scaleValues.m_y;
shearValues[0] /= scaleValues.m_y;
// Compute XZ and YZ shears, orthogonalize 3rd row.
shearValues[1] = Vector::Dot3(row[0], row[2]).ToFloat();
row[2] -= row[0] * shearValues[1];
shearValues[2] = Vector::Dot3(row[1], row[2]).ToFloat();
row[2] -= row[1] * shearValues[2];
// Next, get Z scale.
scaleValues.m_z = row[2].Length3().ToFloat();
if (!CheckForZeroScaleInRow(scaleValues.m_z, row[2]))
{
return false;
}
// Normalize 3rd row and correct the XZ and YZ shear factors for Z scaling.
row[2] /= scaleValues.m_z;
shearValues[1] /= scaleValues.m_z;
shearValues[2] /= scaleValues.m_z;
// At this point, the upper 3x3 matrix in mat is orthonormal.
// Check for a coordinate system flip. If the determinant
// is less than zero, then negate the matrix and the scaling factors.
if (Vector::Dot3(row[0], Vector::Cross3(row[1], row[2])).ToFloat() < 0)
{
for (int i = 0; i < 3; i++)
{
scaleValues[i] *= -1;
row[i] *= -1;
}
}
// Copy over the orthonormal rows into the returned matrix.
// The upper 3x3 matrix in mat is now a rotation matrix.
for (int i = 0; i < 3; i++)
{
matrix[i].SetX(row[i][0]);
matrix[i].SetY(row[i][1]);
matrix[i].SetZ(row[i][2]);
}
// Correct the scaling factors for the normalization step that we
// performed above; shear and rotation are not affected by the
// normalization.
scaleValues *= maxVal;
scale = Vector(scaleValues);
shear = Vector(shearValues);
return true;
}
}
namespace Math
{
Matrix const Matrix::Identity(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
Matrix::Matrix(float v00, float v01, float v02, float v03, float v10, float v11, float v12, float v13, float v20, float v21, float v22, float v23, float v30, float v31, float v32, float v33)
{
m_rows[0] = Vector(v00, v01, v02, v03);
m_rows[1] = Vector(v10, v11, v12, v13);
m_rows[2] = Vector(v20, v21, v22, v23);
m_rows[3] = Vector(v30, v31, v32, v33);
}
Matrix::Matrix(float values[16])
{
m_rows[0] = Vector(values[0], values[1], values[2], values[3]);
m_rows[1] = Vector(values[4], values[5], values[6], values[7]);
m_rows[2] = Vector(values[8], values[9], values[10], values[11]);
m_rows[3] = Vector(values[12], values[13], values[14], values[15]);
}
Matrix::Matrix(const Vector& xAxis, const Vector& yAxis, const Vector& zAxis)
{
m_rows[0] = xAxis;
m_rows[1] = yAxis;
m_rows[2] = zAxis;
m_rows[3] = Vector::UnitW;
}
Matrix::Matrix(const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector& translation)
{
m_rows[0] = xAxis;
m_rows[1] = yAxis;
m_rows[2] = zAxis;
m_rows[3] = translation.GetWithW1();
}
Matrix::Matrix(const EulerAngles& eulerAngles, const Vector translation)
{
float cx, cy, cz, sx, sy, sz, czsx, cxcz, sysz;
sx = sinf((float)eulerAngles.m_x); cx = cosf((float)eulerAngles.m_x);
sy = sinf((float)eulerAngles.m_y); cy = cosf((float)eulerAngles.m_y);
sz = sinf((float)eulerAngles.m_z); cz = cosf((float)eulerAngles.m_z);
czsx = cz * sx;
cxcz = cx * cz;
sysz = sy * sz;
// Order is XYZ
m_values[0][0] = cy * cz;
m_values[0][1] = cy * sz;
m_values[0][2] = -sy;
m_values[1][0] = czsx * sy - cx * sz;
m_values[1][1] = cxcz + sx * sysz;
m_values[1][2] = cy * sx;
m_values[2][0] = cxcz * sy + sx * sz;
m_values[2][1] = -czsx + cx * sysz;
m_values[2][2] = cx * cy;
m_values[0][3] = 0.0f;
m_values[1][3] = 0.0f;
m_values[2][3] = 0.0f;
// Translation
m_rows[3] = translation.GetWithW1();
}
EulerAngles Matrix::ToEulerAngles() const
{
EulerAngles result;
result.m_x = Radians(Math::ATan2(m_values[1][2], m_values[2][2]));
float const c2 = Math::Sqrt((m_values[0][0] * m_values[0][0]) + (m_values[0][1] * m_values[0][1]));
result.m_y = Radians(Math::ATan2(-m_values[0][2], c2));
float const s1 = Math::Sin((float)result.m_x);
float const c1 = Math::Cos((float)result.m_x);
result.m_z = Radians(Math::ATan2((s1 * m_values[2][0]) - (c1 * m_values[1][0]), (c1 * m_values[1][1]) - (s1 * m_values[2][1])));
return result;
}
bool Matrix::Decompose(Quaternion& outRotation, Vector& outTranslation, Vector& outScale) const
{
Matrix copy = *this;
Vector shr = Vector::Zero;
outScale = Vector::Zero;
// Extract and remove scale and shear from matrix
if (ExtractAndRemoveScalingAndShear(copy, outScale, shr))
{
// Extract rotation and translation from unscaled matrix
outRotation = copy.GetRotation();
outTranslation = copy.GetTranslation().GetWithW0();
return true;
}
return false;
}
Vector Matrix::GetScale() const
{
Matrix copy = *this;
Vector scale = Vector::Zero, shear;
if (!ExtractAndRemoveScalingAndShear(copy, scale, shear))
{
float const lengthX = m_rows[0].Length3().ToFloat();
float const lengthY = m_rows[1].Length3().ToFloat();
float const lengthZ = m_rows[2].Length3().ToFloat();
scale = Vector(lengthX, lengthY, lengthZ, 0.0f);
}
return scale;
}
Matrix& Matrix::SetScale(const Vector& newScale)
{
Vector scale, shear;
bool result = ExtractAndRemoveScalingAndShear(*this, scale, shear);
// Cannot set scale on matrix that contains zero-scale
ASSERT(result);
m_rows[0] = m_rows[0] * newScale.GetSplatX();
m_rows[1] = m_rows[1] * newScale.GetSplatY();
m_rows[2] = m_rows[2] * newScale.GetSplatZ();
return *this;
}
Matrix& Matrix::RemoveScale()
{
Vector scale, shear;
bool result = ExtractAndRemoveScalingAndShear(*this, scale, shear);
// Cannot remove zero scale from matrix
ASSERT(result);
return *this;
}
}
================================================
FILE: MotionCorrection/src/cpp/Math/Matrix.h
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "Vector.h"
#include "Quaternion.h"
enum class CoordinateSpace : uint8_t
{
World,
Local,
};
//
// Matrices are Row-Major
// Multiplication order is right to left
// ObjectWorldTransform = LocalObjectTransform * WorldTransform
//
namespace Math
{
class alignas(16) Matrix
{
public:
static Matrix const Identity;
public:
static Matrix FromRotation(const Quaternion& rotation);
static Matrix FromTranslation(const Vector& translation);
static Matrix FromScale(const Vector& scale);
static Matrix FromUniformScale(float uniformScale);
static Matrix FromTranslationAndScale(const Vector& translation, const Vector& scale);
static Matrix FromRotationBetweenVectors(const Vector sourceVector, const Vector targetVector);
public:
explicit Matrix();
explicit Matrix(NoInit_t);
explicit Matrix(ZeroInit_t);
explicit Matrix(float v00, float v01, float v02, float v03,
float v10, float v11, float v12, float v13,
float v20, float v21, float v22, float v23,
float v30, float v31, float v32, float v33);
explicit Matrix(float values[16]);
explicit Matrix(Vector const& xAxis, Vector const& yAxis, Vector const& zAxis);
explicit Matrix(Vector const& xAxis, Vector const& yAxis, Vector const& zAxis, Vector const& translation);
Matrix(const Vector axis, Radians angleRadians);
Matrix(const AxisAngle axisAngle);
explicit Matrix(const Quaternion& rotation);
explicit Matrix(const Quaternion& rotation, const Vector& translation, const Vector& scale = Vector::One);
explicit Matrix(const Quaternion& rotation, const Vector& translation, float scale = 1.0f);
explicit Matrix(const EulerAngles& eulerAngles, const Vector translation = Vector::UnitW);
EulerAngles ToEulerAngles() const;
float* AsFloatArray();
const float* AsFloatArray() const;
const Vector& GetRow(uint32_t row) const;
const Vector& GetAxisX() const;
const Vector& GetAxisY() const;
const Vector& GetAxisZ() const;
void SetAxisX(const Vector& xAxis);
void SetAxisY(const Vector& yAxis);
void SetAxisZ(const Vector& zAxis);
Float3 GetForwardVector() const;
Float3 GetRightVector() const;
Float3 GetUpVector() const;
Vector GetUnitAxisX() const;
Vector GetUnitAxisY() const;
Vector GetUnitAxisZ() const;
bool IsIdentity() const;
bool IsOrthogonal() const;
bool IsOrthonormal() const;
bool Decompose(Quaternion& outRotation, Vector& outTranslation, Vector& outScale) const;
Matrix& Transpose();
Matrix GetTransposed() const;
Matrix& Invert();
Matrix GetInverse() const;
Vector GetDeterminant() const;
float GetDeterminantAsFloat() const;
Vector GetTranslation() const;
const Vector& GetTranslationWithW() const;
Matrix& SetTranslation(Vector const& v);
Matrix& SetTranslation(Float3 const& v);
Matrix& SetTranslation(Float4 const& v);
Quaternion GetRotation() const;
Matrix& SetRotation(const Matrix& rotation);
Matrix& SetRotation(const Quaternion& rotation);
Matrix& SetRotationMaintainingScale(const Matrix& rotation);
Matrix& SetRotationMaintainingScale(const Quaternion& rotation);
Vector GetScale() const;
Matrix& RemoveScale();
Matrix& SetScale(const Vector& scale);
Matrix& SetScale(float uniformScale);
Matrix& RemoveScaleFast();
Matrix& SetScaleFast(const Vector& scale);
Matrix& SetScaleFast(float uniformScale);
//
// Operators
//
// Applies rotation and scale to a vector and returns a result with the W = 0
Vector RotateVector(const Vector& vector) const;
// Applies rotation and scale to a vector and returns a result with the W = 0
Vector TransformNormal(const Vector& vector) const;
// Applies the transformation to a given point and ensures the resulting W = 1
Vector TransformPoint(const Vector& point) const;
// Applies the transformation to a vector ignoring the W value.
// Same as TransformPoint with the result W left unchanged
Vector TransformVector3(const Vector& vector) const;
// Applies the transformation to a given vector with the result W left unchanged
Vector TransformVector4(const Vector& vector) const;
Vector& operator[](uint32_t i);
const Vector operator[](uint32_t i) const;
Matrix operator*(const Matrix& rhs) const;
Matrix& operator*=(const Matrix& rhs);
Matrix operator*(const Quaternion& rhs) const;
Matrix operator*=(const Quaternion& rhs);
bool operator==(const Matrix& rhs) const;
public:
union
{
Vector m_rows[4];
float m_values[4][4];
};
};
}
#include "Matrix.inl"
================================================
FILE: MotionCorrection/src/cpp/Math/Matrix.inl
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <cstring>
#include "Matrix.h"
namespace Math
{
inline Matrix Matrix::FromRotation(const Quaternion& rotation)
{
return Matrix(rotation);
}
inline Matrix Matrix::FromTranslation(const Vector& translation)
{
Matrix M;
M.m_rows[0] = Vector::UnitX;
M.m_rows[1] = Vector::UnitY;
M.m_rows[2] = Vector::UnitZ;
M.m_rows[3] = translation.GetWithW1();
return M;
}
inline Matrix Matrix::FromScale(const Vector& scale)
{
Matrix M;
M.m_rows[0] = _mm_and_ps(scale, SIMD::g_maskX000);
M.m_rows[1] = _mm_and_ps(scale, SIMD::g_mask0Y00);
M.m_rows[2] = _mm_and_ps(scale, SIMD::g_mask00Z0);
M.m_rows[3] = Vector::UnitW;
return M;
}
inline Matrix Matrix::FromUniformScale(float uniformScale)
{
Matrix M;
M.m_rows[0] = _mm_set_ps(0, 0, 0, uniformScale);
M.m_rows[1] = _mm_set_ps(0, 0, uniformScale, 0);
M.m_rows[2] = _mm_set_ps(0, uniformScale, 0, 0);
M.m_rows[3] = Vector::UnitW;
return M;
}
inline Matrix Matrix::FromTranslationAndScale(const Vector& translation, const Vector& scale)
{
Matrix M;
M.m_rows[0] = _mm_and_ps(scale, SIMD::g_maskX000);
M.m_rows[1] = _mm_and_ps(scale, SIMD::g_mask0Y00);
M.m_rows[2] = _mm_and_ps(scale, SIMD::g_mask00Z0);
M.m_rows[3] = translation.GetWithW1();
return M;
}
inline Matrix Matrix::FromRotationBetweenVectors(Vector const sourceVector, Vector const targetVector)
{
return Matrix(Quaternion::FromRotationBetweenNormalizedVectors(sourceVector, targetVector));
}
inline Matrix::Matrix()
{
memcpy(this, &Matrix::Identity, sizeof(Matrix));
}
inline Matrix::Matrix(NoInit_t)
{
}
inline Matrix::Matrix(ZeroInit_t)
{
memset(this, 0, sizeof(Matrix));
}
inline Matrix::Matrix(const Vector axis, Radians angleRadians)
{
Vector normal = axis.GetNormalized3();
Vector C0, C1;
Vector::SinCos(C0, C1, Vector((float)angleRadians));
Vector C2 = Vector::One - C1;
__m128 N0 = _mm_shuffle_ps(normal, normal, _MM_SHUFFLE(3, 0, 2, 1));
__m128 N1 = _mm_shuffle_ps(normal, normal, _MM_SHUFFLE(3, 1, 0, 2));
__m128 V0 = _mm_mul_ps(C2, N0);
V0 = _mm_mul_ps(V0, N1);
__m128 R0 = _mm_mul_ps(C2, normal);
R0 = _mm_mul_ps(R0, normal);
R0 = _mm_add_ps(R0, C1);
__m128 R1 = _mm_mul_ps(C0, normal);
R1 = _mm_add_ps(R1, V0);
__m128 R2 = _mm_mul_ps(C0, normal);
R2 = _mm_sub_ps(V0, R2);
V0 = _mm_and_ps(R0, SIMD::g_maskXYZ0);
__m128 V1 = _mm_shuffle_ps(R1, R2, _MM_SHUFFLE(2, 1, 2, 0));
V1 = _mm_shuffle_ps(V1, V1, _MM_SHUFFLE(0, 3, 2, 1));
__m128 V2 = _mm_shuffle_ps(R1, R2, _MM_SHUFFLE(0, 0, 1, 1));
V2 = _mm_shuffle_ps(V2, V2, _MM_SHUFFLE(2, 0, 2, 0));
R2 = _mm_shuffle_ps(V0, V1, _MM_SHUFFLE(1, 0, 3, 0));
R2 = _mm_shuffle_ps(R2, R2, _MM_SHUFFLE(1, 3, 2, 0));
m_rows[0] = R2;
R2 = _mm_shuffle_ps(V0, V1, _MM_SHUFFLE(3, 2, 3, 1));
R2 = _mm_shuffle_ps(R2, R2, _MM_SHUFFLE(1, 3, 0, 2));
m_rows[1] = R2;
V2 = _mm_shuffle_ps(V2, V0, _MM_SHUFFLE(3, 2, 1, 0));
m_rows[2] = V2;
m_rows[3] = Vector::UnitW;
}
inline Matrix::Matrix(const AxisAngle axisAngle)
: Matrix(Vector(axisAngle.m_axis), axisAngle.m_angle)
{
}
inline Matrix::Matrix(const Quaternion& rotation)
{
SetRotation(rotation);
m_rows[3] = Vector::UnitW;
}
inline Matrix::Matrix(const Quaternion& rotation, const Vector& translation, const Vector& scale)
{
SetRotation(rotation);
m_rows[0] = m_rows[0] * scale.GetSplatX();
m_rows[1] = m_rows[1] * scale.GetSplatY();
m_rows[2] = m_rows[2] * scale.GetSplatZ();
m_rows[3] = translation.GetWithW1();
}
inline Matrix::Matrix(const Quaternion& rotation, const Vector& translation, float scale)
: Matrix(rotation, translation, Vector(scale))
{
}
inline float* Matrix::AsFloatArray()
{
return &m_values[0][0];
}
inline const float* Matrix::AsFloatArray() const
{
return &m_values[0][0];
}
inline const Vector& Matrix::GetRow(uint32_t row) const
{
return m_rows[row];
}
inline const Vector& Matrix::GetAxisX() const
{
return m_rows[0];
}
inline const Vector& Matrix::GetAxisY() const
{
return m_rows[1];
}
inline const Vector& Matrix::GetAxisZ() const
{
return m_rows[2];
}
inline void Matrix::SetAxisX(const Vector& xAxis)
{
m_rows[0] = xAxis;
}
inline void Matrix::SetAxisY(const Vector& yAxis)
{
m_rows[1] = yAxis;
}
inline void Matrix::SetAxisZ(const Vector& zAxis)
{
m_rows[2] = zAxis;
}
inline Float3 Matrix::GetForwardVector() const
{
return GetAxisZ();
}
inline Float3 Matrix::GetRightVector() const
{
return GetAxisX();
}
inline Float3 Matrix::GetUpVector() const
{
return GetAxisY();
}
inline Vector Matrix::GetUnitAxisX() const
{
return m_rows[0].GetNormalized3();
}
inline Vector Matrix::GetUnitAxisY() const
{
return m_rows[1].GetNormalized3();
}
inline Vector Matrix::GetUnitAxisZ() const
{
return m_rows[2].GetNormalized3();
}
inline bool Matrix::IsIdentity() const
{
__m128 vTemp1 = _mm_cmpeq_ps(m_rows[0], Vector::UnitX);
__m128 vTemp2 = _mm_cmpeq_ps(m_rows[1], Vector::UnitY);
__m128 vTemp3 = _mm_cmpeq_ps(m_rows[2], Vector::UnitZ);
__m128 vTemp4 = _mm_cmpeq_ps(m_rows[3], Vector::UnitW);
vTemp1 = _mm_and_ps(vTemp1, vTemp2);
vTemp3 = _mm_and_ps(vTemp3, vTemp4);
vTemp1 = _mm_and_ps(vTemp1, vTemp3);
return (_mm_movemask_ps(vTemp1) == 0x0f);
}
inline bool Matrix::IsOrthogonal() const
{
Matrix const transpose = GetTransposed();
Matrix result = *this * transpose;
return result.IsIdentity();
}
inline bool Matrix::IsOrthonormal() const
{
static const Vector three(3);
auto dotCheck = Vector::Dot3(m_rows[0], m_rows[1]) + Vector::Dot3(m_rows[0], m_rows[2]) + Vector::Dot3(m_rows[1], m_rows[2]);
auto magnitudeCheck = m_rows[0].LengthSquared3() + m_rows[1].LengthSquared3() + m_rows[2].LengthSquared3();
auto result = dotCheck + magnitudeCheck;
return result.IsNearEqual3(three);
}
inline Matrix& Matrix::Transpose()
{
__m128 vTemp1 = _mm_shuffle_ps(m_rows[0], m_rows[1], _MM_SHUFFLE(1, 0, 1, 0));
__m128 vTemp3 = _mm_shuffle_ps(m_rows[0], m_rows[1], _MM_SHUFFLE(3, 2, 3, 2));
__m128 vTemp2 = _mm_shuffle_ps(m_rows[2], m_rows[3], _MM_SHUFFLE(1, 0, 1, 0));
__m128 vTemp4 = _mm_shuffle_ps(m_rows[2], m_rows[3], _MM_SHUFFLE(3, 2, 3, 2));
m_rows[0] = _mm_shuffle_ps(vTemp1, vTemp2, _MM_SHUFFLE(2, 0, 2, 0));
m_rows[1] = _mm_shuffle_ps(vTemp1, vTemp2, _MM_SHUFFLE(3, 1, 3, 1));
m_rows[2] = _mm_shuffle_ps(vTemp3, vTemp4, _MM_SHUFFLE(2, 0, 2, 0));
m_rows[3] = _mm_shuffle_ps(vTemp3, vTemp4, _MM_SHUFFLE(3, 1, 3, 1));
return *this;
}
inline Matrix Matrix::GetTransposed() const
{
Matrix m = *this;
m.Transpose();
return m;
}
inline Matrix& Matrix::Invert()
{
Matrix MT = GetTransposed();
__m128 V00 = _mm_shuffle_ps(MT.m_rows[2], MT.m_rows[2], _MM_SHUFFLE(1, 1, 0, 0));
__m128 V10 = _mm_shuffle_ps(MT.m_rows[3], MT.m_rows[3], _MM_SHUFFLE(3, 2, 3, 2));
__m128 V01 = _mm_shuffle_ps(MT.m_rows[0], MT.m_rows[0], _MM_SHUFFLE(1, 1, 0, 0));
__m128 V11 = _mm_shuffle_ps(MT.m_rows[1], MT.m_rows[1], _MM_SHUFFLE(3, 2, 3, 2));
__m128 V02 = _mm_shuffle_ps(MT.m_rows[2], MT.m_rows[0], _MM_SHUFFLE(2, 0, 2, 0));
__m128 V12 = _mm_shuffle_ps(MT.m_rows[3], MT.m_rows[1], _MM_SHUFFLE(3, 1, 3, 1));
__m128 D0 = _mm_mul_ps(V00, V10);
__m128 D1 = _mm_mul_ps(V01, V11);
__m128 D2 = _mm_mul_ps(V02, V12);
V00 = _mm_shuffle_ps(MT.m_rows[2], MT.m_rows[2], _MM_SHUFFLE(3, 2, 3, 2));
V10 = _mm_shuffle_ps(MT.m_rows[3], MT.m_rows[3], _MM_SHUFFLE(1, 1, 0, 0));
V01 = _mm_shuffle_ps(MT.m_rows[0], MT.m_rows[0], _MM_SHUFFLE(3, 2, 3, 2));
V11 = _mm_shuffle_ps(MT.m_rows[1], MT.m_rows[1], _MM_SHUFFLE(1, 1, 0, 0));
V02 = _mm_shuffle_ps(MT.m_rows[2], MT.m_rows[0], _MM_SHUFFLE(3, 1, 3, 1));
V12 = _mm_shuffle_ps(MT.m_rows[3], MT.m_rows[1], _MM_SHUFFLE(2, 0, 2, 0));
V00 = _mm_mul_ps(V00, V10);
V01 = _mm_mul_ps(V01, V11);
V02 = _mm_mul_ps(V02, V12);
D0 = _mm_sub_ps(D0, V00);
D1 = _mm_sub_ps(D1, V01);
D2 = _mm_sub_ps(D2, V02);
// V11 = D0Y,D0W,D2Y,D2Y
V11 = _mm_shuffle_ps(D0, D2, _MM_SHUFFLE(1, 1, 3, 1));
V00 = _mm_shuffle_ps(MT.m_rows[1], MT.m_rows[1], _MM_SHUFFLE(1, 0, 2, 1));
V10 = _mm_shuffle_ps(V11, D0, _MM_SHUFFLE(0, 3, 0, 2));
V01 = _mm_shuffle_ps(MT.m_rows[0], MT.m_rows[0], _MM_SHUFFLE(0, 1, 0, 2));
V11 = _mm_shuffle_ps(V11, D0, _MM_SHUFFLE(2, 1, 2, 1));
// V13 = D1Y,D1W,D2W,D2W
__m128 V13 = _mm_shuffle_ps(D1, D2, _MM_SHUFFLE(3, 3, 3, 1));
V02 = _mm_shuffle_ps(MT.m_rows[3], MT.m_rows[3], _MM_SHUFFLE(1, 0, 2, 1));
V12 = _mm_shuffle_ps(V13, D1, _MM_SHUFFLE(0, 3, 0, 2));
__m128 V03 = _mm_shuffle_ps(MT.m_rows[2], MT.m_rows[2], _MM_SHUFFLE(0, 1, 0, 2));
V13 = _mm_shuffle_ps(V13, D1, _MM_SHUFFLE(2, 1, 2, 1));
__m128 C0 = _mm_mul_ps(V00, V10);
__m128 C2 = _mm_mul_ps(V01, V11);
__m128 C4 = _mm_mul_ps(V02, V12);
__m128 C6 = _mm_mul_ps(V03, V13);
// V11 = D0X,D0Y,D2X,D2X
V11 = _mm_shuffle_ps(D0, D2, _MM_SHUFFLE(0, 0, 1, 0));
V00 = _mm_shuffle_ps(MT.m_rows[1], MT.m_rows[1], _MM_SHUFFLE(2, 1, 3, 2));
V10 = _mm_shuffle_ps(D0, V11, _MM_SHUFFLE(2, 1, 0, 3));
V01 = _mm_shuffle_ps(MT.m_rows[0], MT.m_rows[0], _MM_SHUFFLE(1, 3, 2, 3));
V11 = _mm_shuffle_ps(D0, V11, _MM_SHUFFLE(0, 2, 1, 2));
// V13 = D1X,D1Y,D2Z,D2Z
V13 = _mm_shuffle_ps(D1, D2, _MM_SHUFFLE(2, 2, 1, 0));
V02 = _mm_shuffle_ps(MT.m_rows[3], MT.m_rows[3], _MM_SHUFFLE(2, 1, 3, 2));
V12 = _mm_shuffle_ps(D1, V13, _MM_SHUFFLE(2, 1, 0, 3));
V03 = _mm_shuffle_ps(MT.m_rows[2], MT.m_rows[2], _MM_SHUFFLE(1, 3, 2, 3));
V13 = _mm_shuffle_ps(D1, V13, _MM_SHUFFLE(0, 2, 1, 2));
V00 = _mm_mul_ps(V00, V10);
V01 = _mm_mul_ps(V01, V11);
V02 = _mm_mul_ps(V02, V12);
V03 = _mm_mul_ps(V03, V13);
C0 = _mm_sub_ps(C0, V00);
C2 = _mm_sub_ps(C2, V01);
C4 = _mm_sub_ps(C4, V02);
C6 = _mm_sub_ps(C6, V03);
V00 = _mm_shuffle_ps(MT.m_rows[1], MT.m_rows[1], _MM_SHUFFLE(0, 3, 0, 3));
// V10 = D0Z,D0Z,D2X,D2Y
V10 = _mm_shuffle_ps(D0, D2, _MM_SHUFFLE(1, 0, 2, 2));
V10 = _mm_shuffle_ps(V10, V10, _MM_SHUFFLE(0, 2, 3, 0));
V01 = _mm_shuffle_ps(MT.m_rows[0], MT.m_rows[0], _MM_SHUFFLE(2, 0, 3, 1));
// V11 = D0X,D0W,D2X,D2Y
V11 = _mm_shuffle_ps(D0, D2, _MM_SHUFFLE(1, 0, 3, 0));
V11 = _mm_shuffle_ps(V11, V11, _MM_SHUFFLE(2, 1, 0, 3));
V02 = _mm_shuffle_ps(MT.m_rows[3], MT.m_rows[3], _MM_SHUFFLE(0, 3, 0, 3));
// V12 = D1Z,D1Z,D2Z,D2W
V12 = _mm_shuffle_ps(D1, D2, _MM_SHUFFLE(3, 2, 2, 2));
V12 = _mm_shuffle_ps(V12, V12, _MM_SHUFFLE(0, 2, 3, 0));
V03 = _mm_shuffle_ps(MT.m_rows[2], MT.m_rows[2], _MM_SHUFFLE(2, 0, 3, 1));
// V13 = D1X,D1W,D2Z,D2W
V13 = _mm_shuffle_ps(D1, D2, _MM_SHUFFLE(3, 2, 3, 0));
V13 = _mm_shuffle_ps(V13, V13, _MM_SHUFFLE(2, 1, 0, 3));
V00 = _mm_mul_ps(V00, V10);
V01 = _mm_mul_ps(V01, V11);
V02 = _mm_mul_ps(V02, V12);
V03 = _mm_mul_ps(V03, V13);
__m128 C1 = _mm_sub_ps(C0, V00);
C0 = _mm_add_ps(C0, V00);
__m128 C3 = _mm_add_ps(C2, V01);
C2 = _mm_sub_ps(C2, V01);
__m128 C5 = _mm_sub_ps(C4, V02);
C4 = _mm_add_ps(C4, V02);
__m128 C7 = _mm_add_ps(C6, V03);
C6 = _mm_sub_ps(C6, V03);
C0 = _mm_shuffle_ps(C0, C1, _MM_SHUFFLE(3, 1, 2, 0));
C2 = _mm_shuffle_ps(C2, C3, _MM_SHUFFLE(3, 1, 2, 0));
C4 = _mm_shuffle_ps(C4, C5, _MM_SHUFFLE(3, 1, 2, 0));
C6 = _mm_shuffle_ps(C6, C7, _MM_SHUFFLE(3, 1, 2, 0));
C0 = _mm_shuffle_ps(C0, C0, _MM_SHUFFLE(3, 1, 2, 0));
C2 = _mm_shuffle_ps(C2, C2, _MM_SHUFFLE(3, 1, 2, 0));
C4 = _mm_shuffle_ps(C4, C4, _MM_SHUFFLE(3, 1, 2, 0));
C6 = _mm_shuffle_ps(C6, C6, _MM_SHUFFLE(3, 1, 2, 0));
__m128 vTemp = Vector::Dot4(C0, MT.m_rows[0]);
vTemp = _mm_div_ps(Vector::One, vTemp);
m_rows[0] = _mm_mul_ps(C0, vTemp);
m_rows[1] = _mm_mul_ps(C2, vTemp);
m_rows[2] = _mm_mul_ps(C4, vTemp);
m_rows[3] = _mm_mul_ps(C6, vTemp);
return *this;
}
inline Matrix Matrix::GetInverse() const
{
Matrix m = *this;
m.Invert();
return m;
}
inline Vector Matrix::GetDeterminant() const
{
Vector V0 = m_rows[2].Shuffle(1, 0, 0, 0);
Vector V1 = m_rows[3].Shuffle(2, 2, 1, 1);
Vector V2 = m_rows[2].Shuffle(1, 0, 0, 0);
Vector V3 = m_rows[3].Shuffle(3, 3, 3, 2);
Vector V4 = m_rows[2].Shuffle(2, 2, 1, 1);
Vector V5 = m_rows[3].Shuffle(3, 3, 3, 2);
Vector P0 = V0 * V1;
Vector P1 = V2 * V3;
Vector P2 = V4 * V5;
V0 = m_rows[2].Shuffle(2, 2, 1, 1);
V1 = m_rows[3].Shuffle(1, 0, 0, 0);
V2 = m_rows[2].Shuffle(3, 3, 3, 2);
V3 = m_rows[3].Shuffle(1, 0, 0, 0);
V4 = m_rows[2].Shuffle(3, 3, 3, 2);
V5 = m_rows[3].Shuffle(2, 2, 1, 1);
P0 = Vector::NegativeMultiplySubtract(V0, V1, P0);
P1 = Vector::NegativeMultiplySubtract(V2, V3, P1);
P2 = Vector::NegativeMultiplySubtract(V4, V5, P2);
V0 = m_rows[1].Shuffle(3, 3, 3, 2);
V1 = m_rows[1].Shuffle(2, 2, 1, 1);
V2 = m_rows[1].Shuffle(1, 0, 0, 0);
static Vector const Sign(1.0f, -1.0f, 1.0f, -1.0f);
Vector S = m_rows[0] * Sign;
Vector R = V0 * P0;
R = Vector::NegativeMultiplySubtract(V1, P1, R);
R = Vector::MultiplyAdd(V2, P2, R);
return Vector::Dot4(S, R);
}
inline float Matrix::GetDeterminantAsFloat() const
{
return GetDeterminant().GetX();
}
inline Vector Matrix::GetTranslation() const
{
return m_rows[3].GetWithW0();
}
inline const Vector& Matrix::GetTranslationWithW() const
{
return m_rows[3];
}
inline Matrix& Matrix::SetTranslation(const Vector& v)
{
m_rows[3] = v.GetWithW1();
return *this;
}
inline Matrix& Matrix::SetTranslation(const Float3& v)
{
m_rows[3] = Vector(v, 1.0f);
return *this;
}
inline Matrix& Matrix::SetTranslation(const Float4& v)
{
m_rows[3] = Vector(v.m_x, v.m_y, v.m_z, 1.0f);
return *this;
}
inline Quaternion Matrix::GetRotation() const
{
// based on RTM: https://github.com/nfrechette/rtm
const Vector& axisX = m_rows[0];
const Vector& axisY = m_rows[1];
const Vector& axisZ = m_rows[2];
// Zero scale is not supported
if (axisX.IsNearZero4() || axisY.IsNearZero4() || axisZ.IsNearZero4())
{
HALT();
}
float const axisX_X = axisX.GetX();
float const axisY_Y = axisY.GetY();
float const axisZ_Z = axisZ.GetZ();
float const mtx_trace = axisX_X + axisY_Y + axisZ_Z;
if (mtx_trace > 0.0)
{
float const axisX_y = axisX.GetY();
float const axisX_z = axisX.GetZ();
float const axisY_x = axisY.GetX();
float const axisY_z = axisY.GetZ();
float const axisZ_x = axisZ.GetX();
float const axisZ_y = axisZ.GetY();
float const inv_trace = Math::Reciprocal(Math::Sqrt(mtx_trace + 1.0f));
float const half_inv_trace = inv_trace * 0.5f;
float const m_x = (axisY_z - axisZ_y) * half_inv_trace;
float const m_y = (axisZ_x - axisX_z) * half_inv_trace;
float const m_z = (axisX_y - axisY_x) * half_inv_trace;
float const m_w = Math::Reciprocal(inv_trace) * 0.5f;
return Quaternion(m_x, m_y, m_z, m_w).GetNormalized();
}
else
{
// Find the axis with the highest diagonal value
int32_t axisIdx0 = 0;
if (axisY_Y > axisX_X)
{
axisIdx0 = 1;
}
if (axisZ_Z > m_rows[axisIdx0][axisIdx0])
{
axisIdx0 = 2;
}
int32_t const axisIdx1 = (axisIdx0 + 1) % 3;
int32_t const axisIdx2 = (axisIdx1 + 1) % 3;
float const pseudoTrace = 1.0f + m_rows[axisIdx0][axisIdx0] - m_rows[axisIdx1][axisIdx1] - m_rows[axisIdx2][axisIdx2];
float const inversePseudoTrace = Math::Reciprocal(Math::Sqrt(pseudoTrace));
float const halfInversePseudoTrace = inversePseudoTrace * 0.5f;
Float4 rawQuatValues;
rawQuatValues[axisIdx0] = Math::Reciprocal(inversePseudoTrace) * 0.5f;
rawQuatValues[axisIdx1] = halfInversePseudoTrace * (m_rows[axisIdx0][axisIdx1] + m_rows[axisIdx1][axisIdx0]);
rawQuatValues[axisIdx2] = halfInversePseudoTrace * (m_rows[axisIdx0][axisIdx2] + m_rows[axisIdx2][axisIdx0]);
rawQuatValues[3] = halfInversePseudoTrace * (m_rows[axisIdx1][axisIdx2] - m_rows[axisIdx2][axisIdx1]);
return Quaternion(rawQuatValues).GetNormalized();
}
}
inline Matrix& Matrix::SetRotation(const Matrix& rotation)
{
ASSERT(Math::Abs(rotation.GetDeterminant().GetX()) == 1.0f);
m_rows[0] = rotation.m_rows[0];
m_rows[1] = rotation.m_rows[1];
m_rows[2] = rotation.m_rows[2];
return *this;
}
inline Matrix& Matrix::SetRotation(const Quaternion& rotation)
{
static __m128 const constant1110 = { 1.0f, 1.0f, 1.0f, 0.0f };
__m128 Q0 = _mm_add_ps(rotation, rotation);
__m128 Q1 = _mm_mul_ps(rotation, Q0);
__m128 V0 = _mm_shuffle_ps(Q1, Q1, _MM_SHUFFLE(3, 0, 0, 1));
V0 = _mm_and_ps(V0, SIMD::g_maskXYZ0);
__m128 V1 = _mm_shuffle_ps(Q1, Q1, _MM_SHUFFLE(3, 1, 2, 2));
V1 = _mm_and_ps(V1, SIMD::g_maskXYZ0);
__m128 R0 = _mm_sub_ps(constant1110, V0);
R0 = _mm_sub_ps(R0, V1);
V0 = _mm_shuffle_ps(rotation, rotation, _MM_SHUFFLE(3, 1, 0, 0));
V1 = _mm_shuffle_ps(Q0, Q0, _MM_SHUFFLE(3, 2, 1, 2));
V0 = _mm_mul_ps(V0, V1);
V1 = _mm_shuffle_ps(rotation, rotation, _MM_SHUFFLE(3, 3, 3, 3));
__m128 V2 = _mm_shuffle_ps(Q0, Q0, _MM_SHUFFLE(3, 0, 2, 1));
V1 = _mm_mul_ps(V1, V2);
__m128 R1 = _mm_add_ps(V0, V1);
__m128 R2 = _mm_sub_ps(V0, V1);
V0 = _mm_shuffle_ps(R1, R2, _MM_SHUFFLE(1, 0, 2, 1));
V0 = _mm_shuffle_ps(V0, V0, _MM_SHUFFLE(1, 3, 2, 0));
V1 = _mm_shuffle_ps(R1, R2, _MM_SHUFFLE(2, 2, 0, 0));
V1 = _mm_shuffle_ps(V1, V1, _MM_SHUFFLE(2, 0, 2, 0));
Q1 = _mm_shuffle_ps(R0, V0, _MM_SHUFFLE(1, 0, 3, 0));
Q1 = _mm_shuffle_ps(Q1, Q1, _MM_SHUFFLE(1, 3, 2, 0));
m_rows[0] = Q1;
Q1 = _mm_shuffle_ps(R0, V0, _MM_SHUFFLE(3, 2, 3, 1));
Q1 = _mm_shuffle_ps(Q1, Q1, _MM_SHUFFLE(1, 3, 0, 2));
m_rows[1] = Q1;
Q1 = _mm_shuffle_ps(V1, R0, _MM_SHUFFLE(3, 2, 1, 0));
m_rows[2] = Q1;
return *this;
}
inline Matrix& Matrix::SetRotationMaintainingScale(const Matrix& rotation)
{
Vector const scale = GetScale();
SetRotation(rotation);
return SetScale(scale);
}
inline Matrix& Matrix::SetRotationMaintainingScale(const Quaternion& rotation)
{
Vector const scale = GetScale();
SetRotation(rotation);
return SetScale(scale);
}
inline Matrix& Matrix::SetScale(float uniformScale)
{
SetScale(Vector(uniformScale));
return *this;
}
inline Matrix& Matrix::RemoveScaleFast()
{
m_rows[0] = m_rows[0].GetNormalized4();
m_rows[1] = m_rows[1].GetNormalized4();
m_rows[2] = m_rows[2].GetNormalized4();
return *this;
}
inline Matrix& Matrix::SetScaleFast(const Vector& scale)
{
m_rows[0] = m_rows[0].GetNormalized3() * scale.GetSplatX();
m_rows[1] = m_rows[1].GetNormalized3() * scale.GetSplatY();
m_rows[2] = m_rows[2].GetNormalized3() * scale.GetSplatZ();
return *this;
}
inline Matrix& Matrix::SetScaleFast(float uniformScale)
{
SetScaleFast(Vector(uniformScale));
return *this;
}
inline Vector Matrix::RotateVector(const Vector& vector) const
{
Vector const X = vector.GetSplatX();
Vector const Y = vector.GetSplatY();
Vector const Z = vector.GetSplatZ();
Vector Result = Z * m_rows[2];
Result = Vector::MultiplyAdd(Y, m_rows[1], Result);
Result = Vector::MultiplyAdd(X, m_rows[0], Result);
return Result;
}
inline Vector Matrix::TransformNormal(const Vector& vector) const
{
return RotateVector(vector);
}
inline Vector Matrix::TransformPoint(const Vector& point) const
{
Vector const X = point.GetSplatX();
Vector const Y = point.GetSplatY();
Vector const Z = point.GetSplatZ();
Vector result = Vector::MultiplyAdd(Z, m_rows[2], m_rows[3]);
result = Vector::MultiplyAdd(Y, m_rows[1], result);
result = Vector::MultiplyAdd(X, m_rows[0], result);
Vector const W = result.GetSplatW();
return result / W;
}
inline Vector Matrix::TransformVector3(const Vector& V) const
{
Vector const X = V.GetSplatX();
Vector const Y = V.GetSplatY();
Vector const Z = V.GetSplatZ();
Vector result = Vector::MultiplyAdd(Z, m_rows[2], m_rows[3]);
result = Vector::MultiplyAdd(Y, m_rows[1], result);
result = Vector::MultiplyAdd(X, m_rows[0], result);
return result;
}
inline Vector Matrix::TransformVector4(const Vector& V) const
{
// Splat m_x,m_y,m_z and m_w
Vector vTempX = V.GetSplatX();
Vector vTempY = V.GetSplatY();
Vector vTempZ = V.GetSplatZ();
Vector vTempW = V.GetSplatW();
// Mul by the matrix
vTempX = _mm_mul_ps(vTempX, m_rows[0]);
vTempY = _mm_mul_ps(vTempY, m_rows[1]);
vTempZ = _mm_mul_ps(vTempZ, m_rows[2]);
vTempW = _mm_mul_ps(vTempW, m_rows[3]);
// Add them all together
vTempX = _mm_add_ps(vTempX, vTempY);
vTempZ = _mm_add_ps(vTempZ, vTempW);
vTempX = _mm_add_ps(vTempX, vTempZ);
return vTempX;
}
inline Vector& Matrix::operator[](uint32_t i)
{
ASSERT(i < 4);
return m_rows[i];
}
inline const Vector Matrix::operator[](uint32_t i) const
{
ASSERT(i < 4);
return m_rows[i];
}
inline Matrix Matrix::operator*(const Matrix& rhs) const
{
Matrix result = *this;
result *= rhs;
return result;
}
inline Matrix& Matrix::operator*= (const Matrix& rhs)
{
Vector vX, vY, vZ, vW;
// Use vW to hold the original row
vW = m_rows[0];
vX = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(0, 0, 0, 0));
vY = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(1, 1, 1, 1));
vZ = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(2, 2, 2, 2));
vW = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(3, 3, 3, 3));
vX = _mm_mul_ps(vX, rhs.m_rows[0]);
vY = _mm_mul_ps(vY, rhs.m_rows[1]);
vZ = _mm_mul_ps(vZ, rhs.m_rows[2]);
vW = _mm_mul_ps(vW, rhs.m_rows[3]);
vX = _mm_add_ps(vX, vZ);
vY = _mm_add_ps(vY, vW);
vX = _mm_add_ps(vX, vY);
m_rows[0] = vX;
// Repeat for the other 3 rows
vW = m_rows[1];
vX = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(0, 0, 0, 0));
vY = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(1, 1, 1, 1));
vZ = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(2, 2, 2, 2));
vW = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(3, 3, 3, 3));
vX = _mm_mul_ps(vX, rhs.m_rows[0]);
vY = _mm_mul_ps(vY, rhs.m_rows[1]);
vZ = _mm_mul_ps(vZ, rhs.m_rows[2]);
vW = _mm_mul_ps(vW, rhs.m_rows[3]);
vX = _mm_add_ps(vX, vZ);
vY = _mm_add_ps(vY, vW);
vX = _mm_add_ps(vX, vY);
m_rows[1] = vX;
vW = m_rows[2];
vX = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(0, 0, 0, 0));
vY = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(1, 1, 1, 1));
vZ = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(2, 2, 2, 2));
vW = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(3, 3, 3, 3));
vX = _mm_mul_ps(vX, rhs.m_rows[0]);
vY = _mm_mul_ps(vY, rhs.m_rows[1]);
vZ = _mm_mul_ps(vZ, rhs.m_rows[2]);
vW = _mm_mul_ps(vW, rhs.m_rows[3]);
vX = _mm_add_ps(vX, vZ);
vY = _mm_add_ps(vY, vW);
vX = _mm_add_ps(vX, vY);
m_rows[2] = vX;
vW = m_rows[3];
vX = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(0, 0, 0, 0));
vY = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(1, 1, 1, 1));
vZ = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(2, 2, 2, 2));
vW = _mm_shuffle_ps(vW, vW, _MM_SHUFFLE(3, 3, 3, 3));
vX = _mm_mul_ps(vX, rhs.m_rows[0]);
vY = _mm_mul_ps(vY, rhs.m_rows[1]);
vZ = _mm_mul_ps(vZ, rhs.m_rows[2]);
vW = _mm_mul_ps(vW, rhs.m_rows[3]);
vX = _mm_add_ps(vX, vZ);
vY = _mm_add_ps(vY, vW);
vX = _mm_add_ps(vX, vY);
m_rows[3] = vX;
return *this;
}
inline Matrix Matrix::operator*(const Quaternion& rhs) const
{
return operator*(Matrix(rhs));
}
inline Matrix Matrix::operator*=(const Quaternion& rhs)
{
return operator*=(Matrix(rhs));
}
inline bool Matrix::operator==(const Matrix& rhs) const
{
for (auto i = 0; i < 4; i++)
{
for (auto j = 0; j < 4; j++)
{
if (m_values[i][j] != rhs.m_values[i][j])
{
return false;
}
}
}
return true;
}
}
================================================
FILE: MotionCorrection/src/cpp/Math/Quaternion.cpp
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "Quaternion.h"
#include "Matrix.h"
namespace Math
{
Quaternion const Quaternion::Identity(0, 0, 0, 1);
// Rotation order is XYZ
EulerAngles Quaternion::ToEulerAngles() const
{
return Matrix(*this).ToEulerAngles();
}
Quaternion Quaternion::LookRotation(const Vector& forward, const Vector& up)
{
const Vector t = Vector::Cross3(up, forward).Normalize3();
return Matrix(t, Vector::Cross3(forward, t), forward).GetRotation();
}
}
================================================
FILE: MotionCorrection/src/cpp/Math/Quaternion.h
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "Vector.h"
namespace Math
{
class alignas(16) Quaternion
{
public:
static Quaternion const Identity;
// Calculate the rotation required to align the source vector to the target vector (shortest path)
static Quaternion FromRotationBetweenNormalizedVectors(const Vector& sourceVector, const Vector& targetVector);
// Calculate the rotation required to align one vector onto another but also taking account a fallback rotation axis for opposite parallel vectors
static Quaternion FromRotationBetweenNormalizedVectors(const Vector& sourceVector, const Vector& targetVector, const Vector& fallbackRotationAxis);
// Calculate the rotation required to align the source vector to the target vector (shortest path)
static Quaternion FromRotationBetweenVectors(const Vector& sourceVector, const Vector& targetVector);
// Normalized LERP - not accurate - only use for really short distances
static Quaternion NLerp(const Quaternion& from, const Quaternion& to, float t);
// Standard and accurate Spherical LERP - based on DirectX Math
static Quaternion SLerp(const Quaternion& from, const Quaternion& to, float t);
// Fast approximation of a Spherical LERP - based on "A fast and accurate estimate for SLERP" by David Eberly
static Quaternion FastSLerp(const Quaternion& from, const Quaternion& to, float t);
// Spherical quadrangle/cubic interpolation for quaternions
static Quaternion SQuad(const Quaternion& q0, const Quaternion& q1, const Quaternion& q2, const Quaternion& q3, float t);
// Calculate the shortest delta quaternion needed to rotate 'from' onto 'to'
static Quaternion Delta(const Quaternion& from, const Quaternion& to);
// Simple vector dot product between two quaternions
static Vector Dot(const Quaternion& q0, const Quaternion& q1);
// Calculate the angular distance between two quaternions
static Radians Distance(const Quaternion& q0, const Quaternion& q1);
// Calculate look rotation given forward and up vectors
static Quaternion LookRotation(const Vector& forward, const Vector& up);
public:
Quaternion() = default;
explicit Quaternion(NoInit_t);
explicit Quaternion(IdentityInit_t);
explicit Quaternion(const Vector& v);
explicit Quaternion(float ix, float iy, float iz, float iw);
explicit Quaternion(const Float4& v);
explicit Quaternion(const Vector& axis, Radians angle);
explicit Quaternion(AxisAngle axisAngle);
explicit Quaternion(const EulerAngles& eulerAngles);
explicit Quaternion(Radians rotX, Radians rotY, Radians rotZ);
operator __m128& ();
operator const __m128& () const;
Float4 ToFloat4() const;
Vector ToVector() const;
Vector Length();
float GetLength() const;
// Get the angle this rotation represents around the specified axis
Radians GetAngle() const;
AxisAngle ToAxisAngle() const;
EulerAngles ToEulerAngles() const;
Vector RotateVector(const Vector& vector) const;
Vector RotateVectorInverse(const Vector& vector) const;
Quaternion& Conjugate();
Quaternion GetConjugate() const;
Quaternion& Negate();
Quaternion GetNegated() const;
Quaternion& Invert();
Quaternion GetInverse() const;
Quaternion& Normalize();
Quaternion GetNormalized() const;
Vector XAxis() const noexcept;
Vector YAxis() const noexcept;
Vector ZAxis() const noexcept;
// Ensure that this rotation is the shortest in terms of the angle (i.e. -5 instead of 355)
Quaternion& MakeShortestPath();
// Ensure that this rotation is the shortest in terms of the angle (i.e. -5 instead of 355)
Quaternion GetShortestPath() const;
// This function will return the estimated normalized quaternion, this is not super accurate but a lot faster (use with care)
Quaternion& NormalizeInaccurate();
// This function will return the estimated normalized quaternion, this is not super accurate but a lot faster (use with care)
Quaternion GetNormalizedInaccurate() const;
bool IsNormalized() const;
bool IsIdentity() const;
// Concatenate the rotation of this onto rhs and return the result i.e. first rotate by rhs then by this
// This means order of rotation is right-to-left: child-rotation * parent-rotation
Quaternion operator*(const Quaternion& rhs) const;
Quaternion& operator*=(const Quaternion& rhs);
// Is the distance between this quaternion and another one under the threshold?
bool IsNearEqual(const Quaternion& rhs, Radians const threshold = Math::DegreesToRadians) const;
// Exact equality
bool operator==(const Quaternion& rhs) const;
// Exact equality
bool operator!=(const Quaternion& rhs) const;
private:
Vector GetSplatW() const;
float GetW() const;
Quaternion& operator=(const Vector& v) = delete;
public:
__m128 m_data;
};
static_assert(sizeof(Vector) == 16, "Quaternion size must be 16 bytes!");
}
#include "Quaternion.inl"
================================================
FILE: MotionCorrection/src/cpp/Math/Quaternion.inl
================================================
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "Quaternion.h"
namespace Math
{
inline Quaternion Quaternion::FromRotationBetweenNormalizedVectors(const Vector& from, const Vector& to)
{
ASSERT(from.IsNormalized3() && to.IsNormalized3());
Quaternion result;
// Parallel vectors - return zero rotation
Vector const dot = Vector::Dot3(from, to);
if (dot.IsGreaterThanEqual4(Vector::OneMinusEpsilon))
{
result = Quaternion::Identity;
}
// Opposite vectors - return 180 rotation around any orthogonal axis
else if (dot.IsLessThanEqual4(Vector::EpsilonMinusOne))
{
Float4 const fromValues = from.ToFloat4();
result = Quaternion(-fromValues.m_z, fromValues.m_y, fromValues.m_x, 0);
result.Normalize();
}
else // Calculate quaternion rotation
{
Vector const cross = Vector::Cross3(from, to);
Vector Q = Vector::Select(cross, dot, Vector::Select0001);
Q += Vector::Select(Vector::Zero, Q.Length4(), Vector::Select0001);
result = Quaternion(Q);
result.Normalize();
}
return result;
}
inline Quaternion Quaternion::FromRotationBetweenNormalizedVectors(const Vector& from, const Vector& to, const Vector& fallbackRotationAxis)
{
ASSERT(from.IsNormalized3() && to.IsNormalized3());
Quaternion Q(NoInit);
Vector rotationAxis = from.Cross3(to).GetNormalized3();
if (rotationAxis.GetLengthSquared3() == 0)
{
rotationAxis = fallbackRotationAxis;
}
float const dot = from.GetDot3(to);
if (dot >= (1.0f - Math::Epsilon))
{
Q = Quaternion::Identity;
}
else
{
float const angle = Math::ACos(dot);
Q = Quaternion(rotationAxis, angle);
}
return Q;
}
inline Quaternion Quaternion::FromRotationBetweenVectors(const Vector& sourceVector, const Vector& targetVector)
{
return FromRotationBetweenNormalizedVectors(
sourceVector.GetNormalized3(),
targetVector.GetNormalized3());
}
inline Quaternion Quaternion::NLerp(const Quaternion& from, const Quaternion& to, float T)
{
ASSERT(T >= 0.0f && T <= 1.0f);
Quaternion adjustedFrom(from);
// Ensure that the rotations are in the same direction
if (Quaternion::Dot(from, to).IsLessThan4(Vector::Zero))
{
adjustedFrom.Negate();
}
Quaternion result(Vector::Lerp(adjustedFrom.ToVector(), to.ToVector(), T));
result.Normalize();
return result;
}
inline Quaternion Quaternion::SLerp(const Quaternion& from, const Quaternion& to, float T)
{
ASSERT(T >= 0.0f && T <= 1.0f);
static SIMD::UIntMask const maskSign = { 0x80000000,0x00000000,0x00000000,0x00000000 };
static __m128 const oneMinusEpsilon = { 1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f, 1.0f - 0.00001f };
Vector const VecT(T);
Vector cosOmega = Quaternion::Dot(from, to);
Vector control = cosOmega.LessThan(Vector::Zero);
Vector sign = Vector::Select(Vector::One, Vector::NegativeOne, control);
cosOmega = _mm_mul_ps(cosOmega, sign);
control = cosOmega.LessThan(oneMinusEpsilon);
Vector sinOmega = _mm_mul_ps(cosOmega, cosOmega);
sinOmega = _mm_sub_ps(Vector::One, sinOmega);
sinOmega = _mm_sqrt_ps(sinOmega);
Vector omega = Vector::ATan2(sinOmega, cosOmega);
Vector V01 = _mm_shuffle_ps(VecT, VecT, _MM_SHUFFLE(2, 3, 0, 1));
V01 = _mm_and_ps(V01, SIMD::g_maskXY00);
V01 = _mm_xor_ps(V01, maskSign);
V01 = _mm_add_ps(Vector::UnitX, V01);
Vector S0 = _mm_mul_ps(V01, omega);
S0 = Vector::Sin(S0);
S0 = _mm_div_ps(S0, sinOmega);
S0 = Vector::Select(V01, S0, control);
Vector S1 = S0.GetSplatY();
S0 = S0.GetSplatX();
S1 = _mm_mul_ps(S1, sign);
Vector result = _mm_mul_ps(from, S0);
S1 = _mm_mul_ps(S1, to);
result = _mm_add_ps(result, S1);
return Quaternion(result);
}
inline Quaternion Quaternion::FastSLerp(const Quaternion& q0, const Quaternion& q1, float t)
{
// Precomputed constants
constexpr float const mu = 1.85298109240830f;
static Vector const u0123 = _mm_setr_ps(1.f / (1 * 3), 1.f / (2 * 5), 1.f / (3 * 7), 1.f / (4 * 9));
static Vector const u4567 = _mm_setr_ps(1.f / (5 * 11), 1.f / (6 * 13), 1.f / (7 * 15), mu / (8 * 17));
static Vector const v0123 = _mm_setr_ps(1.f / 3, 2.f / 5, 3.f / 7, 4.f / 9);
static Vector const v4567 = _mm_setr_ps(5.f / 11, 6.f / 13, 7.f / 15, mu * 8 / 17);
static Vector const vSignMask = _mm_set1_ps(-0.f);
// Common code for computing the scalar coefficients of SLERP
auto CalculateCoefficient = [](Vector vT, Vector xm1)
{
Vector const vTSquared = vT * vT;
// ( b4, b5, b6, b7 ) = ( x-1 ) * ( u4 * t^2 - v4, u5 * t^2 - v5, u6 * t^2 - v6, u7 * t^2 - v7 )
Vector b4567 = Vector::MultiplySubtract(u4567, vTSquared, v4567);
b4567 *= xm1;
// ( b7, b7, b7, b7 )
Vector b = b4567.GetSplatW();
Vector c = b + Vector::One;
// ( b6, b6, b6, b6 )
b = b4567.GetSplatZ();
c = Vector::MultiplyAdd(b, c, Vector::One);
// ( b5, b5, b5, b5 )
b = b4567.GetSplatY();
c = Vector::MultiplyAdd(b, c, Vector::One);
// ( b4, b4, b4, b4 )
b = b4567.GetSplatX();
c = Vector::MultiplyAdd(b, c, Vector::One);
// ( b0, b1, b2, b3 ) =
// ( x-1)*(u0* t^2-v0, u1 * t^2 -v1, u2* t^2-v2, u3* t^2-v3 )
Vector b0123 = Vector::MultiplySubtract(u0123, vTSquared, v0123);
b0123 *= xm1;
// ( b3, b3, b3, b3 )
b = b0123.GetSplatW();
c = Vector::MultiplyAdd(b, c, Vector::One);
// ( b2, b2, b2, b2 )
b = b0123.GetSplatZ();
c = Vector::MultiplyAdd(b, c, Vector::One);
// ( b1, b1, b1, b1 )
b = b0123.GetSplatY();
c = Vector::MultiplyAdd(b, c, Vector::One);
// ( b0, b0, b0, b0 )
b = b0123.GetSplatX();
c = Vector::MultiplyAdd(b, c, Vector::One);
c *= vT;
return c;
};
Vector x = Vector::Dot4(q0.m_data, q1.m_data); // cos ( theta ) in all components
Vector sign = _mm_and_ps(vSignMask, x);
x = _mm_xor_ps(sign, x);
Vector localQ1 = _mm_xor_ps(sign, q1);
Vector xm1 = x - Vector::One;
Vector cT = CalculateCoefficient(Vector(t), xm1);
Vector cD = CalculateCoefficient(Vector(1.0f - t), xm1);
cT = cT * localQ1;
Quaternion result(Vector::MultiplyAdd(cD, q0.m_data, cT));
return result;
}
inline Quaternion Quaternion::SQuad(const Quaternion& q0, const Quaternion& q1, const Quaternion& q2, const Quaternion& q3, float t)
{
ASSERT(t >= 0.0f && t <= 1.0f);
Quaternion const q03 = Quaternion::SLerp(q0, q3, t);
Quaternion const q12 = Quaternion::SLerp(q1, q2, t);
t = (t - (t * t)) * 2;
Quaternion const result = Quaternion::SLerp(q03, q12, t);
return result;
}
inline Quaternion Quaternion::Delta(const Quaternion& from, const Quaternion& to)
{
return to * from.GetInverse();
}
inline Vector Quaternion::Dot(const Quaternion& q0, const Quaternion& q1)
{
return Vector::Dot4(q0.m_data, q1.m_data);
}
inline Radians Quaternion::Distance(const Quaternion& q0, const Quaternion& q1)
{
float const dot = Math::Clamp(Dot(q0, q1).ToFloat(), -1.0f, 1.0f);
return Radians(2 * Math::ACos(Math::Abs(dot)));
}
inline Quaternion::Quaternion(NoInit_t)
{
}
inline Quaternion::Quaternion(IdentityInit_t)
: m_data(Vector::UnitW.m_data)
{
}
inline Quaternion::Quaternion(const Vector& v)
: m_data(v.m_data)
{
}
inline Quaternion::Quaternion(float ix, float iy, float iz, float iw)
{
m_data = _mm_set_ps(iw, iz, iy, ix);
}
inline Quaternion::Quaternion(const Float4& v)
: Quaternion(v.m_x, v.m_y, v.m_z, v.m_w)
{
}
inline Quaternion::Quaternion(const Vector& axis, Radians angle)
{
ASSERT(axis.IsNormalized3());
auto N = _mm_and_ps(axis, SIMD::g_maskXYZ0);
N = _mm_or_ps(N, Vector::UnitW);
auto scale = _mm_set_ps1(0.5f * (float)angle);
Vector sine, cosine;
Vector::SinCos(sine, cosine, scale);
scale = _mm_and_ps(sine, SIMD::g_maskXYZ0);
cosine = _mm_and_ps(cosine, SIMD::g_mask000W);
scale = _mm_or_ps(scale, cosine);
N = _mm_mul_ps(N, scale);
m_data = N;
}
inline Quaternion::Quaternion(AxisAngle axisAngle)
: Quaternion(Vector(axisAngle.m_axis), axisAngle.m_angle)
{
}
inline Quaternion::Quaternion(const EulerAngles& eulerAngles)
{
auto const rotationX = Quaternion(Vector::UnitX, eulerAngles.m_x);
auto const rotationY = Quaternion(Vector::UnitY, eulerAngles.m_y);
auto const rotationZ = Quaternion(Vector::UnitZ, eulerAngles.m_z);
// Rotation order is XYZ - all in global space, hence the order is reversed
m_data = (rotationX * rotationY * rotationZ).GetNormalized().m_data;
}
inline Quaternion::Quaternion(Radians rotX, Radians rotY, Radians rotZ)
: Quaternion(EulerAngles(rotX, rotY, rotZ))
{
}
inline Quaternion::operator __m128& ()
{
return m_data;
}
inline Quaternion::operator const __m128& () const
{
return m_data;
}
inline Float4 Quaternion::ToFloat4() const
{
Float4 v;
_mm_storeu_ps(&v.m_x, m_data);
return v;
}
inline Vector Quaternion::ToVector() const
{
return Vector(m_data);
}
inline Vector Quaternion::Length()
{
return ToVector().Length4();
}
inline float Quaternion::GetLength() const
{
return ToVector().GetLength4();
}
inline Radians Quaternion::GetAngle() const
{
return Radians(2.0f * Math::ACos(GetW()));
}
inline AxisAngle Quaternion::ToAxisAngle() const
{
return AxisAngle(ToVector(), Radians(2.0f * Math::ACos(GetW())));
}
inline Vector Quaternion::RotateVector(const Vector& vector) const
{
Quaternion const A(Vector::Select(Vector::Select1110, vector, Vector::Select1110));
Quaternion const result = GetConjugate() * A;
return (result * *this).ToVector();
}
inline Vector Quaternion::RotateVectorInverse(const Vector& vector) const
{
Quaternion const A(Vector::Select(Vector::Select1110, vector, Vector::Select1110));
Quaternion const result = *this * A;
return (result * GetConjugate()).ToVector();
}
inline Quaternion& Quaternion::Conjugate()
{
static __m128 const conj = { -1.0f, -1.0f, -1.0f, 1.0f };
m_data = _mm_mul_ps(*this, conj);
return *this;
}
inline Quaternion Quaternion::GetConjugate() const
{
Quaternion q = *this;
q.Conjugate();
return q;
}
inline Quaternion& Quaternion::Negate()
{
m_data = _mm_mul_ps(*this, Vector::NegativeOne);
return *this;
}
inline Quaternion Quaternion::GetNegated() const
{
Quaternion q = *this;
q.Negate();
return q;
}
inline Quaternion& Quaternion::Invert()
{
Vector const conjugate(GetConjugate().m_data);
Vector const length = ToVector().Length4();
Vector const mask = length.LessThanEqual(Vector::Epsilon);
Vector const result = conjugate / length;
m_data = result.Select(result, Vector::Zero, mask);
return *this;
}
inline Quaternion Quaternion::GetInverse() const
{
Quaternion q = *this;
q.Invert();
return q;
}
inline Quaternion& Quaternion::Normalize()
{
m_data = ToVector().GetNormalized4().m_data;
return *this;
}
inline Quaternion Quaternion::GetNormalized() const
{
Quaternion q = *this;
q.Normalize();
return q;
}
inline Vector Quaternion::XAxis() const noexcept
{
const float x = _mm_cvtss_f32(m_data);
const float y = _mm_cvtss_f32(
_mm_shuffle_ps(m_data, m_data,
_MM_SHUFFLE(1, 1, 1, 1)));
const float z = _mm_cvtss_f32(
_mm_shuffle_ps(m_data, m_data,
_MM_SHUFFLE(2, 2, 2, 2)));
const float w = _mm_cvtss_f32(
_mm_shuffle_ps(m_data, m_data,
_MM_SHUFFLE(3, 3, 3, 3)));
const float s = 2.0f * w;
const float x2 = 2.0f * x;
return Vector(
x2 * x + s * w - 1.0f,
x2 * y + s * z,
x2 * z + s * -y);
}
inline Vector Quaternion::YAxis() const noexcept
{
const float x = _mm_cvtss_f32(m_data);
const float y = _mm_cvtss_f32(
_mm_shuffle_ps(m_data, m_data,
_MM_SHUFFLE(1, 1, 1, 1)));
const float z = _mm_cvtss_f32(
_mm_shuffle_ps(m_data, m_data,
_MM_SHUFFLE(2, 2, 2, 2)));
const float w = _mm_cvtss_f32(
_mm_shuffle_ps(m_data, m_data,
_MM_SHUFFLE(3, 3, 3, 3)));
const float s = 2.0f * w;
const float y2 = 2.0f * y;
return Vector(
y2 * x + s * -z,
y2 * y + s * w - 1.0f,
y2 * z + s * x);
}
inline Vector Quaternion::ZAxis() const noexcept
{
const float x = _mm_cvtss_f32(m_data);
const float y = _mm_cvtss_f32(
_mm_shuffle_ps(m_data, m_data,
_MM_SHUFFLE(1, 1, 1, 1)));
const float z = _mm_cvtss_f32(
_mm_shuffle_ps(m_data, m_data,
_MM_SHUFFLE(2, 2, 2, 2)));
const float w = _mm_cvtss_f32(
_mm_shuffle_ps(m_data, m_data,
_MM_SHUFFLE(3, 3, 3, 3)));
const float s = 2.0f * w;
const float z2 = 2.0f * z;
return Vector(
x * z2 + s * y,
y * z2 + s * -x,
z * z2 + s * w - 1.0f);
}
inline Quaternion& Quaternion::MakeShortestPath()
{
// If we have a > 180 angle, negate
// w < 0.0f is the same as dot( identity, q ) < 0
if (GetW() < 0.0f)
{
Negate();
}
return *this;
}
inline Quaternion Quaternion::GetShortestPath() const
{
Quaternion sp = *this;
sp.MakeShortestPath();
return sp;
}
inline Quaternion& Quaternion::NormalizeInaccurate()
{
*this = GetNormalizedInaccurate();
return *this;
}
inline Quaternion Quaternion::GetNormalizedInaccurate() const
{
__m128 vLengthSq = _mm_mul_ps(m_data, m_data);
__m128 vTemp = _mm_shuffle_ps(vLengthSq, vLengthSq, _MM_SHUFFLE(3, 2, 3, 2));
vLengthSq = _mm_add_ps(vLengthSq, vTemp);
vLengthSq = _mm_shuffle_ps(vLengthSq, vLengthSq, _MM_SHUFFLE(1, 0, 0, 0));
vTemp = _mm_shuffle_ps(vTemp, vLengthSq, _MM_SHUFFLE(3, 3, 0, 0));
vLengthSq = _mm_add_ps(vLengthSq, vTemp);
vLengthSq = _mm_shuffle_ps(vLengthSq, vLengthS
gitextract__xaaoo6k/ ├── .gitignore ├── .pre-commit-config.yaml ├── ATTRIBUTIONS.MD ├── CHANGELOG.md ├── CONTRIBUTING.MD ├── Dockerfile ├── LICENSE ├── MANIFEST.in ├── MotionCorrection/ │ ├── .gitignore │ ├── CMakeLists.txt │ ├── MANIFEST.in │ ├── README.md │ ├── python/ │ │ └── motion_correction/ │ │ ├── __init__.py │ │ └── motion_postprocess.py │ ├── run_test.py │ ├── setup.py │ └── src/ │ └── cpp/ │ ├── AnimProcessing/ │ │ ├── InverseKinematics.cpp │ │ ├── InverseKinematics.h │ │ ├── TrajectoryCorrector.cpp │ │ ├── TrajectoryCorrector.h │ │ ├── Utility.cpp │ │ └── Utility.h │ ├── BindingsPython.cpp │ ├── Compiler.h │ ├── Debug.h │ ├── Math/ │ │ ├── Constants.h │ │ ├── Matrix.cpp │ │ ├── Matrix.h │ │ ├── Matrix.inl │ │ ├── Quaternion.cpp │ │ ├── Quaternion.h │ │ ├── Quaternion.inl │ │ ├── SIMD.h │ │ ├── Scalar.h │ │ ├── Transform.cpp │ │ ├── Transform.h │ │ ├── Transform.inl │ │ ├── Types.cpp │ │ ├── Types.h │ │ ├── Vector.cpp │ │ ├── Vector.h │ │ └── Vector.inl │ └── Platform.h ├── README.md ├── benchmark/ │ ├── create_benchmark.py │ ├── embed_folder.py │ ├── evaluate_folder.py │ ├── generate_eval.py │ └── parse_folder.py ├── docker-compose.yaml ├── docker_requirements.in ├── docker_requirements.txt ├── docs/ │ ├── .gitattributes │ ├── Makefile │ ├── README.md │ ├── make.bat │ ├── requirements.txt │ └── source/ │ ├── _static/ │ │ └── custom.css │ ├── _templates/ │ │ └── apidoc/ │ │ ├── module.rst.jinja │ │ └── package.rst.jinja │ ├── api_reference/ │ │ ├── _generated/ │ │ │ ├── kimodo.demo.rst │ │ │ ├── kimodo.exports.rst │ │ │ ├── kimodo.metrics.rst │ │ │ ├── kimodo.model.llm2vec.models.rst │ │ │ ├── kimodo.model.llm2vec.rst │ │ │ ├── kimodo.model.rst │ │ │ ├── kimodo.motion_rep.reps.rst │ │ │ ├── kimodo.motion_rep.rst │ │ │ ├── kimodo.rst │ │ │ ├── kimodo.scripts.rst │ │ │ ├── kimodo.skeleton.rst │ │ │ ├── kimodo.viz.rst │ │ │ └── modules.rst │ │ ├── constraints.rst │ │ ├── exports.rst │ │ ├── index.rst │ │ ├── model.rst │ │ ├── motion_rep.rst │ │ ├── post-processing.rst │ │ ├── utilities.rst │ │ └── viz.rst │ ├── benchmark/ │ │ ├── introduction.md │ │ ├── metrics.md │ │ ├── pipeline.md │ │ └── results.md │ ├── conf.py │ ├── getting_started/ │ │ ├── installation.md │ │ ├── installation_docker.md │ │ ├── installation_smpl.md │ │ ├── installation_virtual_env.md │ │ └── quick_start.md │ ├── index.md │ ├── interactive_demo/ │ │ ├── constraints.md │ │ ├── examples.md │ │ ├── export_results.md │ │ ├── generation.md │ │ ├── index.md │ │ ├── launching.md │ │ ├── model_selection.md │ │ └── ui_overview.md │ ├── key_concepts/ │ │ ├── constraints.md │ │ ├── limitations.md │ │ ├── model.md │ │ ├── motion_representation.md │ │ └── skeleton.md │ ├── project_info.md │ ├── project_structure.md │ └── user_guide/ │ ├── cli.md │ ├── configuration.md │ ├── constraints.md │ ├── motion_convert.md │ ├── output_formats.md │ └── seed_dataset.md ├── kimodo/ │ ├── __init__.py │ ├── assets/ │ │ ├── demo/ │ │ │ └── examples/ │ │ │ ├── kimodo-g1-rp/ │ │ │ │ ├── 01_single_text_prompt/ │ │ │ │ │ ├── meta.json │ │ │ │ │ └── motion.npz │ │ │ │ ├── 02_multi_text_ee_constraint/ │ │ │ │ │ ├── constraints.json │ │ │ │ │ ├── meta.json │ │ │ │ │ └── motion.npz │ │ │ │ ├── 03_full_body_keyframes/ │ │ │ │ │ ├── constraints.json │ │ │ │ │ ├── meta.json │ │ │ │ │ └── motion.npz │ │ │ │ ├── 04_ee_constraint/ │ │ │ │ │ ├── constraints.json │ │ │ │ │ ├── meta.json │ │ │ │ │ └── motion.npz │ │ │ │ ├── 05_root_path/ │ │ │ │ │ ├── constraints.json │ │ │ │ │ ├── meta.json │ │ │ │ │ └── motion.npz │ │ │ │ ├── 06_root_waypoints/ │ │ │ │ │ ├── constraints.json │ │ │ │ │ ├── meta.json │ │ │ │ │ └── motion.npz │ │ │ │ ├── 07_text_terrain/ │ │ │ │ │ ├── meta.json │ │ │ │ │ └── motion.npz │ │ │ │ └── 08_text_object/ │ │ │ │ ├── meta.json │ │ │ │ └── motion.npz │ │ │ └── kimodo-soma-rp/ │ │ │ ├── 01_single_text_prompt/ │ │ │ │ ├── meta.json │ │ │ │ └── motion.npz │ │ │ ├── 02_multi_text_prompt/ │ │ │ │ ├── meta.json │ │ │ │ └── motion.npz │ │ │ ├── 03_full_body_keyframes/ │ │ │ │ ├── constraints.json │ │ │ │ ├── meta.json │ │ │ │ └── motion.npz │ │ │ ├── 04_ee_constraint/ │ │ │ │ ├── constraints.json │ │ │ │ ├── meta.json │ │ │ │ └── motion.npz │ │ │ ├── 05_root_path/ │ │ │ │ ├── constraints.json │ │ │ │ ├── meta.json │ │ │ │ └── motion.npz │ │ │ ├── 06_root_waypoints/ │ │ │ │ ├── constraints.json │ │ │ │ ├── meta.json │ │ │ │ └── motion.npz │ │ │ ├── 07_mixed_constraints/ │ │ │ │ ├── constraints.json │ │ │ │ ├── meta.json │ │ │ │ └── motion.npz │ │ │ └── 08_stylized_text/ │ │ │ ├── meta.json │ │ │ └── motion.npz │ │ └── skeletons/ │ │ ├── g1skel34/ │ │ │ ├── joints.p │ │ │ ├── meshes/ │ │ │ │ └── g1/ │ │ │ │ ├── head_link.STL │ │ │ │ ├── left_ankle_pitch_link.STL │ │ │ │ ├── left_ankle_roll_link.STL │ │ │ │ ├── left_elbow_link.STL │ │ │ │ ├── left_hand_index_0_link.STL │ │ │ │ ├── left_hand_index_1_link.STL │ │ │ │ ├── left_hand_middle_0_link.STL │ │ │ │ ├── left_hand_middle_1_link.STL │ │ │ │ ├── left_hand_palm_link.STL │ │ │ │ ├── left_hand_thumb_0_link.STL │ │ │ │ ├── left_hand_thumb_1_link.STL │ │ │ │ ├── left_hand_thumb_2_link.STL │ │ │ │ ├── left_hip_pitch_link.STL │ │ │ │ ├── left_hip_roll_link.STL │ │ │ │ ├── left_hip_yaw_link.STL │ │ │ │ ├── left_knee_link.STL │ │ │ │ ├── left_rubber_hand.STL │ │ │ │ ├── left_shoulder_pitch_link.STL │ │ │ │ ├── left_shoulder_roll_link.STL │ │ │ │ ├── left_shoulder_yaw_link.STL │ │ │ │ ├── left_wrist_pitch_link.STL │ │ │ │ ├── left_wrist_roll_link.STL │ │ │ │ ├── left_wrist_roll_rubber_hand.STL │ │ │ │ ├── left_wrist_yaw_link.STL │ │ │ │ ├── logo_link.STL │ │ │ │ ├── pelvis.STL │ │ │ │ ├── pelvis_contour_link.STL │ │ │ │ ├── right_ankle_pitch_link.STL │ │ │ │ ├── right_ankle_roll_link.STL │ │ │ │ ├── right_elbow_link.STL │ │ │ │ ├── right_hand_index_0_link.STL │ │ │ │ ├── right_hand_index_1_link.STL │ │ │ │ ├── right_hand_middle_0_link.STL │ │ │ │ ├── right_hand_middle_1_link.STL │ │ │ │ ├── right_hand_palm_link.STL │ │ │ │ ├── right_hand_thumb_0_link.STL │ │ │ │ ├── right_hand_thumb_1_link.STL │ │ │ │ ├── right_hand_thumb_2_link.STL │ │ │ │ ├── right_hip_pitch_link.STL │ │ │ │ ├── right_hip_roll_link.STL │ │ │ │ ├── right_hip_yaw_link.STL │ │ │ │ ├── right_knee_link.STL │ │ │ │ ├── right_rubber_hand.STL │ │ │ │ ├── right_shoulder_pitch_link.STL │ │ │ │ ├── right_shoulder_roll_link.STL │ │ │ │ ├── right_shoulder_yaw_link.STL │ │ │ │ ├── right_wrist_pitch_link.STL │ │ │ │ ├── right_wrist_roll_link.STL │ │ │ │ ├── right_wrist_roll_rubber_hand.STL │ │ │ │ ├── right_wrist_yaw_link.STL │ │ │ │ ├── torso_constraint_L_link.STL │ │ │ │ ├── torso_constraint_L_rod_link.STL │ │ │ │ ├── torso_constraint_R_link.STL │ │ │ │ ├── torso_constraint_R_rod_link.STL │ │ │ │ ├── torso_link.STL │ │ │ │ ├── torso_link_23dof_rev_1_0.STL │ │ │ │ ├── torso_link_rev_1_0.STL │ │ │ │ ├── waist_constraint_L.STL │ │ │ │ ├── waist_constraint_R.STL │ │ │ │ ├── waist_roll_link.STL │ │ │ │ ├── waist_roll_link_rev_1_0.STL │ │ │ │ ├── waist_support_link.STL │ │ │ │ ├── waist_yaw_link.STL │ │ │ │ └── waist_yaw_link_rev_1_0.STL │ │ │ ├── rest_pose_local_rot.p │ │ │ └── xml/ │ │ │ └── g1.xml │ │ ├── smplx22/ │ │ │ ├── beta.npy │ │ │ ├── joints.p │ │ │ └── mean_hands.npy │ │ ├── somaskel30/ │ │ │ ├── joints.p │ │ │ └── soma_base_fit_mhr_params.npz │ │ └── somaskel77/ │ │ ├── bvh_joints.p │ │ ├── joints.p │ │ ├── relaxed_hands_rest_pose.npy │ │ ├── skin_standard.npz │ │ ├── somaskel77_standard_tpose.bvh │ │ └── standard_t_pose_global_offsets_rots.p │ ├── assets.py │ ├── constraints.py │ ├── demo/ │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── app.py │ │ ├── config.py │ │ ├── embedding_cache.py │ │ ├── generation.py │ │ ├── queue_manager.py │ │ ├── state.py │ │ └── ui.py │ ├── exports/ │ │ ├── __init__.py │ │ ├── bvh.py │ │ ├── motion_convert_lib.py │ │ ├── motion_formats.py │ │ ├── motion_io.py │ │ ├── mujoco.py │ │ └── smplx.py │ ├── geometry.py │ ├── meta.py │ ├── metrics/ │ │ ├── __init__.py │ │ ├── base.py │ │ ├── constraints.py │ │ ├── foot_skate.py │ │ └── tmr.py │ ├── model/ │ │ ├── __init__.py │ │ ├── backbone.py │ │ ├── cfg.py │ │ ├── common.py │ │ ├── diffusion.py │ │ ├── kimodo_model.py │ │ ├── llm2vec/ │ │ │ ├── README.md │ │ │ ├── __init__.py │ │ │ ├── llm2vec.py │ │ │ ├── llm2vec_wrapper.py │ │ │ └── models/ │ │ │ ├── __init__.py │ │ │ ├── attn_mask_utils.py │ │ │ ├── bidirectional_llama.py │ │ │ └── utils.py │ │ ├── load_model.py │ │ ├── loading.py │ │ ├── registry.py │ │ ├── text_encoder_api.py │ │ ├── tmr.py │ │ └── twostage_denoiser.py │ ├── motion_rep/ │ │ ├── __init__.py │ │ ├── conditioning.py │ │ ├── feature_utils.py │ │ ├── feet.py │ │ ├── reps/ │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── kimodo_motionrep.py │ │ │ └── tmr_motionrep.py │ │ ├── smooth_root.py │ │ └── stats.py │ ├── postprocess.py │ ├── sanitize.py │ ├── scripts/ │ │ ├── __init__.py │ │ ├── docker-entrypoint.sh │ │ ├── generate.py │ │ ├── gradio_theme.py │ │ ├── lock_requirements.py │ │ ├── motion_convert.py │ │ ├── mujoco_load.py │ │ └── run_text_encoder_server.py │ ├── skeleton/ │ │ ├── __init__.py │ │ ├── base.py │ │ ├── bvh.py │ │ ├── definitions.py │ │ ├── kinematics.py │ │ ├── registry.py │ │ └── transforms.py │ ├── tools.py │ └── viz/ │ ├── __init__.py │ ├── constraint_ui.py │ ├── coords.py │ ├── g1_rig.py │ ├── gui.py │ ├── playback.py │ ├── scene.py │ ├── smplx_skin.py │ ├── soma_layer_skin.py │ ├── soma_skin.py │ └── viser_utils.py ├── pyproject.toml └── setup.py
SYMBOL INDEX (874 symbols across 97 files)
FILE: MotionCorrection/python/motion_correction/motion_postprocess.py
function correct_motion (line 13) | def correct_motion(
FILE: MotionCorrection/run_test.py
class Joint (line 10) | class Joint:
method __init__ (line 11) | def __init__(self, name, parent, t_pose_translation, t_pose_rotation, ...
function create_test_rig (line 19) | def create_test_rig():
FILE: MotionCorrection/setup.py
class CMakeExtension (line 17) | class CMakeExtension(Extension):
method __init__ (line 18) | def __init__(self, name, sourcedir=""):
class CMakeBuild (line 23) | class CMakeBuild(build_ext):
method run (line 24) | def run(self):
method build_extension (line 33) | def build_extension(self, ext):
FILE: MotionCorrection/src/cpp/AnimProcessing/InverseKinematics.cpp
function getAngleWithTwoSideVectors (line 16) | float getAngleWithTwoSideVectors(const Math::Vector& vecLeft, const Math...
function getAngleWithCosineRule (line 27) | float getAngleWithCosineRule (const float lSideLeft, const float lSideRi...
FILE: MotionCorrection/src/cpp/AnimProcessing/InverseKinematics.h
function namespace (line 14) | namespace IK {
FILE: MotionCorrection/src/cpp/AnimProcessing/TrajectoryCorrector.cpp
function removeRows (line 9) | static void removeRows(
function multVelWeights (line 46) | static void multVelWeights(
FILE: MotionCorrection/src/cpp/AnimProcessing/TrajectoryCorrector.h
function class (line 10) | class TrajectoryCorrector
FILE: MotionCorrection/src/cpp/AnimProcessing/Utility.cpp
function DebugPrintIntervalsEnabled (line 27) | bool DebugPrintIntervalsEnabled()
function FilterContactIntervals (line 39) | void FilterContactIntervals(
function ComputeContactIntervals (line 82) | std::vector<std::pair<int, int>> ComputeContactIntervals(
function FindContactPoints (line 122) | void FindContactPoints(
function TargetReachFalloff (line 194) | float TargetReachFalloff(
function CorrectHipsY (line 222) | void CorrectHipsY(
function SmoothChannels (line 265) | void SmoothChannels(
function CorrectHipsXZ (line 296) | void CorrectHipsXZ(
function CorrectRotationsForBone (line 368) | void CorrectRotationsForBone(
function CorrectJointRotations (line 452) | void CorrectJointRotations(
function DoEffectorIK (line 488) | void DoEffectorIK(
function DoContactIK (line 608) | void DoContactIK(
FILE: MotionCorrection/src/cpp/AnimProcessing/Utility.h
function namespace (line 13) | namespace Animation
FILE: MotionCorrection/src/cpp/BindingsPython.cpp
function strip_nan_inf (line 21) | float strip_nan_inf(float x) noexcept
function correct_motion (line 28) | void correct_motion(
function PYBIND11_MODULE (line 361) | PYBIND11_MODULE(_motion_correction, m) {
FILE: MotionCorrection/src/cpp/Math/Constants.h
function namespace (line 12) | namespace Math
FILE: MotionCorrection/src/cpp/Math/Matrix.cpp
function CheckForZeroScaleInRow (line 14) | static bool CheckForZeroScaleInRow(float scale, const Vector& row)
function ExtractAndRemoveScalingAndShear (line 29) | static bool ExtractAndRemoveScalingAndShear(Matrix& matrix, Vector& scal...
type Math (line 166) | namespace Math
function EulerAngles (line 232) | EulerAngles Matrix::ToEulerAngles() const
function Vector (line 266) | Vector Matrix::GetScale() const
function Matrix (line 281) | Matrix& Matrix::SetScale(const Vector& newScale)
function Matrix (line 295) | Matrix& Matrix::RemoveScale()
FILE: MotionCorrection/src/cpp/Math/Matrix.h
type class (line 11) | enum class
FILE: MotionCorrection/src/cpp/Math/Quaternion.cpp
type Math (line 9) | namespace Math
function EulerAngles (line 14) | EulerAngles Quaternion::ToEulerAngles() const
function Quaternion (line 19) | Quaternion Quaternion::LookRotation(const Vector& forward, const Vecto...
FILE: MotionCorrection/src/cpp/Math/Quaternion.h
function namespace (line 10) | namespace Math
FILE: MotionCorrection/src/cpp/Math/SIMD.h
function namespace (line 11) | namespace SIMD
FILE: MotionCorrection/src/cpp/Math/Scalar.h
function namespace (line 20) | namespace Math
FILE: MotionCorrection/src/cpp/Math/Transform.cpp
type Math (line 8) | namespace Math
FILE: MotionCorrection/src/cpp/Math/Types.h
type NoInit_t (line 10) | enum NoInit_t { NoInit }
type ZeroInit_t (line 11) | enum ZeroInit_t { ZeroInit }
type IdentityInit_t (line 12) | enum IdentityInit_t { IdentityInit }
function Axis (line 14) | enum class Axis : uint8_t
function Int2 (line 62) | inline Int2 operator/( int32_t const& rhs ) const { return Int2( m_x / r...
type Int3 (line 74) | struct Int3
function const (line 89) | inline int32_t const& operator[]( uint32_t i ) const { return ( (int32_t...
function operator (line 91) | inline bool operator==( Int3 const rhs ) const { return m_x == rhs.m_x &...
function operator (line 92) | inline bool operator!=( Int3 const rhs ) const { return m_x != rhs.m_x |...
function Int3 (line 97) | inline Int3 operator/( Int3 const& rhs ) const { return Int3( m_x / rhs....
function Int3 (line 108) | inline Int3 operator/( int32_t const& rhs ) const { return Int3( m_x / r...
type Int4 (line 120) | struct Int4
function const (line 135) | inline int32_t const& operator[]( uint32_t i ) const { return ( (int32_t...
function operator (line 137) | inline bool operator==( Int4 const rhs ) const { return m_x == rhs.m_x &...
function operator (line 138) | inline bool operator!=( Int4 const rhs ) const { return m_x != rhs.m_x |...
function Int4 (line 143) | inline Int4 operator/( int32_t const& rhs ) const { return Int4( m_x / r...
function Int4 (line 154) | inline Int4 operator/( Int4 const& rhs ) const { return Int4( m_x / rhs....
type Float2 (line 166) | struct Float2
function const (line 187) | inline float const& operator[]( uint32_t i ) const { return ( (float*) t...
function Float2 (line 197) | inline Float2 operator/( Float2 const& rhs ) const { return Float2( m_x ...
function Float2 (line 202) | inline Float2 operator/( float const& rhs ) const { return Float2( m_x /...
type Float3 (line 217) | struct Float3
function const (line 241) | inline float const& operator[]( uint32_t i ) const { return ( (float*) t...
function Float3 (line 253) | inline Float3 operator/( Float3 const& rhs ) const { return Float3( m_x ...
function Float3 (line 258) | inline Float3 operator/( float const& rhs ) const { return Float3( m_x /...
type Float4 (line 273) | struct Float4
function const (line 298) | float const& operator[]( uint32_t i ) const { return ( (float*) this )[i...
function Float4 (line 311) | inline Float4 operator/( Float4 const& rhs ) const { return Float4( m_x ...
function Float4 (line 316) | inline Float4 operator/( float const& rhs ) const { return Float4( m_x /...
function Int2 (line 331) | inline Int2::Int2( Float2 const& v )
function Int3 (line 337) | inline Int3::Int3( Float3 const& v )
function Float2 (line 344) | inline Float2::Float2( Float3 const& v )
function Float2 (line 350) | inline Float2::Float2( Float4 const& v )
type Degrees (line 364) | struct Degrees
type Degrees (line 366) | struct Degrees
function operator (line 375) | operator Radians() const;
function Degrees (line 384) | inline Degrees operator/( Degrees const& rhs ) const { return Degrees( m...
function Degrees (line 394) | inline Degrees operator/( float const& rhs ) const { return Degrees( m_v...
function Degrees (line 404) | inline Degrees operator/( int32_t const& rhs ) const { return Degrees( m...
function Degrees (line 414) | inline Degrees operator/( uint32_t const& rhs ) const { return Degrees( ...
function operator (line 422) | inline bool operator<( float const& rhs ) const { return m_value < rhs; }
function operator (line 423) | inline bool operator>=( float const& rhs ) const { return m_value >= rhs; }
function operator (line 424) | inline bool operator<=( float const& rhs ) const { return m_value <= rhs; }
function operator (line 426) | inline bool operator>( Degrees const& rhs ) const { return m_value > rhs...
function operator (line 427) | inline bool operator<( Degrees const& rhs ) const { return m_value < rhs...
function operator (line 428) | inline bool operator>=( Degrees const& rhs ) const { return m_value >= r...
function operator (line 429) | inline bool operator<=( Degrees const& rhs ) const { return m_value <= r...
function operator (line 436) | inline bool operator==( float const& v ) const { return Math::IsNearEqua...
function operator (line 437) | inline bool operator!=( float const& v ) const { return !Math::IsNearEqu...
function operator (line 439) | inline bool operator==( Degrees const& rhs ) const { return m_value == ...
function operator (line 440) | inline bool operator!=( Degrees const& rhs ) const { return m_value != ...
function Clamp (line 445) | inline void Clamp( Degrees min, Degrees max )
function Clamp360 (line 451) | inline void Clamp360()
function Degrees (line 457) | inline Degrees GetClamped360() const
function Degrees (line 478) | inline Degrees GetClamped180() const
function Degrees (line 497) | inline Degrees GetClampedPositive360() const
function Radians (line 534) | inline Radians operator/( Radians const& rhs ) const { return Radians( m...
function Radians (line 544) | inline Radians operator/( float const& rhs ) const { return Radians( m_v...
function Radians (line 554) | inline Radians operator/( int32_t const& rhs ) const { return Radians( m...
function Radians (line 564) | inline Radians operator/( uint32_t const& rhs ) const { return Radians( ...
function operator (line 572) | inline bool operator<( float const& rhs ) const { return m_value < rhs; }
function operator (line 573) | inline bool operator>=( float const& rhs ) const { return m_value >= rhs; }
function operator (line 574) | inline bool operator<=( float const& rhs ) const { return m_value <= rhs; }
function operator (line 576) | inline bool operator>( Radians const& rhs ) const { return m_value > rhs...
function operator (line 577) | inline bool operator<( Radians const& rhs ) const { return m_value < rhs...
function operator (line 578) | inline bool operator>=( Radians const& rhs ) const { return m_value >= r...
function operator (line 579) | inline bool operator<=( Radians const& rhs ) const { return m_value <= r...
function operator (line 586) | inline bool operator==( float const& v ) const { return Math::IsNearEqua...
function operator (line 587) | inline bool operator!=( float const& v ) const { return !Math::IsNearEqu...
function operator (line 589) | inline bool operator==( Radians const& rhs ) const { return m_value == r...
function operator (line 590) | inline bool operator!=( Radians const& rhs ) const { return m_value != r...
function Clamp (line 595) | inline void Clamp( Radians min, Radians max )
function Clamp360 (line 601) | inline void Clamp360()
function Radians (line 607) | inline Radians GetClamped360() const
function Radians (line 625) | inline Radians GetClampedToPositive360() const
function Radians (line 646) | inline Radians GetClamped180() const
function Flip (line 670) | inline void Flip()
function Radians (line 678) | inline Radians GetFlipped() const
function rhs (line 704) | inline bool Degrees::operator>( Radians const& rhs ) const { return m_va...
function rhs (line 705) | inline bool Degrees::operator<( Radians const& rhs ) const { return m_va...
function rhs (line 706) | inline bool Degrees::operator>=( Radians const& rhs ) const { return m_v...
function rhs (line 707) | inline bool Degrees::operator<=( Radians const& rhs ) const { return m_v...
function rhs (line 709) | inline bool Degrees::operator==( Radians const& rhs ) const { return Mat...
function rhs (line 710) | inline bool Degrees::operator!=( Radians const& rhs ) const { return !Ma...
function Radians (line 712) | inline Radians::Radians( Degrees const& degrees )
function rhs (line 716) | inline bool Radians::operator>( Degrees const& rhs ) const { return m_va...
function rhs (line 717) | inline bool Radians::operator<( Degrees const& rhs ) const { return m_va...
function rhs (line 718) | inline bool Radians::operator>=( Degrees const& rhs ) const { return m_v...
function rhs (line 719) | inline bool Radians::operator<=( Degrees const& rhs ) const { return m_v...
function rhs (line 721) | inline bool Radians::operator==( Degrees const& rhs ) const { return Mat...
function rhs (line 722) | inline bool Radians::operator!=( Degrees const& rhs ) const { return !Ma...
function GetClamped (line 724) | struct EulerAngles
function other (line 775) | inline bool operator==( EulerAngles const& other ) const { return m_x ==...
function other (line 776) | inline bool operator!=( EulerAngles const& other ) const { return m_x !=...
function Radians (line 778) | inline Radians& operator[]( uint32_t i ) { return ( (Radians*) this )[i]; }
function Radians (line 779) | inline Radians const& operator[]( uint32_t i ) const { return ( (Radians...
type AxisAngle (line 790) | struct AxisAngle
FILE: MotionCorrection/src/cpp/Math/Vector.cpp
type Math (line 9) | namespace Math
function Vector (line 72) | Vector Vector::SLerp(const Vector& from, const Vector& to, float t)
FILE: MotionCorrection/src/cpp/Math/Vector.h
function namespace (line 14) | namespace Math
FILE: benchmark/create_benchmark.py
function download_benchmark (line 30) | def download_benchmark(dest: Path) -> Path:
function discover_seed_motion_folders (line 43) | def discover_seed_motion_folders(root: Path) -> list[Path]:
function constraints_and_motion_from_seed (line 56) | def constraints_and_motion_from_seed(folder: str, dataset_folder: str, f...
function main (line 131) | def main():
FILE: benchmark/embed_folder.py
function discover_motion_folders (line 22) | def discover_motion_folders(root: Path) -> list[Path]:
function _load_posed_joints (line 34) | def _load_posed_joints(npz_path: Path, device: str) -> torch.Tensor:
function main (line 48) | def main():
FILE: benchmark/evaluate_folder.py
function discover_motion_folders (line 42) | def discover_motion_folders(root: Path) -> list[tuple[Path, Path]]:
function group_by_parent (line 55) | def group_by_parent(examples: list[tuple[Path, Path]]) -> list[list[tupl...
function _to_scalar (line 66) | def _to_scalar(t: torch.Tensor) -> float:
function _to_p95 (line 70) | def _to_p95(t: torch.Tensor) -> float:
function _per_sample_metrics_from_saved (line 76) | def _per_sample_metrics_from_saved(metrics_list: list, n: int) -> list[d...
function _load_pair_embeddings (line 87) | def _load_pair_embeddings(
function _load_npz_motion (line 112) | def _load_npz_motion(
function _run_eval_on_group (line 134) | def _run_eval_on_group(
function _write_json (line 254) | def _write_json(path: Path, payload: dict[str, Any]) -> None:
function main (line 259) | def main():
FILE: benchmark/generate_eval.py
function parse_args (line 26) | def parse_args():
function discover_example_folders (line 82) | def discover_example_folders(root: Path) -> list[tuple[Path, Path]]:
function copy_source_files (line 98) | def copy_source_files(src_dir: Path, out_dir: Path) -> None:
class EvalExampleDataset (line 107) | class EvalExampleDataset(Dataset):
method __init__ (line 112) | def __init__(
method __len__ (line 124) | def __len__(self) -> int:
method __getitem__ (line 127) | def __getitem__(self, idx: int) -> dict[str, Any]:
function collate_examples (line 150) | def collate_examples(batch: list[dict]) -> dict[str, Any]:
function group_by_parent (line 162) | def group_by_parent(
function _slice_output_at (line 179) | def _slice_output_at(output: dict[str, Any], index: int) -> dict[str, Any]:
function _crop_output (line 192) | def _crop_output(output: dict[str, Any], num_frames: int) -> dict[str, A...
function main (line 205) | def main():
FILE: benchmark/parse_folder.py
function _discover_sample_dirs (line 41) | def _discover_sample_dirs(root: Path) -> list[Path]:
function _discover_testcase_dirs (line 50) | def _discover_testcase_dirs(root: Path) -> list[Path]:
function _expected_result_path (line 55) | def _expected_result_path(testcase_dir: Path) -> Path:
function _parse_testcase_key (line 59) | def _parse_testcase_key(root: Path, testcase_dir: Path) -> tuple[str, str]:
function _accumulate_weighted (line 77) | def _accumulate_weighted(
function _to_averages (line 89) | def _to_averages(
function _load_result_row (line 99) | def _load_result_row(
function _table_value (line 131) | def _table_value(val: float | None) -> float | str | None:
function _build_tables (line 140) | def _build_tables(
function _fmt_md (line 235) | def _fmt_md(val: float | None, decimals: int) -> str:
function _print_tf_formatted_md (line 244) | def _print_tf_formatted_md(
function _print_c_formatted_md (line 285) | def _print_c_formatted_md(
function _print_formatted_gt_method_md (line 333) | def _print_formatted_gt_method_md(
function _fmt (line 354) | def _fmt(val: float | None, decimals: int, width: int) -> str:
function _print_grouped_rows (line 361) | def _print_grouped_rows(
function _print_tf_formatted (line 379) | def _print_tf_formatted(
function _print_c_formatted (line 449) | def _print_c_formatted(
function _print_formatted_gt_method (line 520) | def _print_formatted_gt_method(
function _build_summary (line 545) | def _build_summary(root: Path) -> dict[str, Any]:
function main (line 667) | def main() -> None:
FILE: docs/source/conf.py
class Mock (line 56) | class Mock:
method __init__ (line 59) | def __init__(self, *args, **kwargs):
method __call__ (line 62) | def __call__(self, *args, **kwargs):
method __getattr__ (line 65) | def __getattr__(self, name):
method __getitem__ (line 78) | def __getitem__(self, name):
method __iter__ (line 81) | def __iter__(self):
method __or__ (line 84) | def __or__(self, other):
method __ror__ (line 87) | def __ror__(self, other):
function setup (line 197) | def setup(app):
FILE: kimodo/assets.py
function skeleton_asset_path (line 14) | def skeleton_asset_path(*parts: str) -> Path:
function demo_asset_path (line 18) | def demo_asset_path(*parts: str) -> Path:
FILE: kimodo/constraints.py
function _convert_constraint_local_rots_to_skeleton (line 17) | def _convert_constraint_local_rots_to_skeleton(local_rot_mats: Tensor, s...
function create_pairs (line 38) | def create_pairs(tensor_A: Tensor, tensor_B: Tensor) -> Tensor:
function compute_global_heading (line 50) | def compute_global_heading(global_joints_positions: Tensor, skeleton: Sk...
function _tensor_to (line 57) | def _tensor_to(
class Root2DConstraintSet (line 75) | class Root2DConstraintSet:
method __init__ (line 81) | def __init__(
method update_constraints (line 112) | def update_constraints(self, data_dict: dict, index_dict: dict) -> None:
method crop_move (line 123) | def crop_move(self, start: int, end: int) -> "Root2DConstraintSet":
method get_save_info (line 139) | def get_save_info(self) -> dict:
method to (line 151) | def to(
method from_dict (line 165) | def from_dict(cls, skeleton: SkeletonBase, dico: dict) -> "Root2DConst...
class FullBodyConstraintSet (line 182) | class FullBodyConstraintSet:
method __init__ (line 187) | def __init__(
method update_constraints (line 233) | def update_constraints(self, data_dict: dict, index_dict: dict) -> None:
method crop_move (line 261) | def crop_move(self, start: int, end: int) -> "FullBodyConstraintSet":
method get_save_info (line 272) | def get_save_info(self) -> dict:
method to (line 288) | def to(
method from_dict (line 304) | def from_dict(cls, skeleton: SkeletonBase, dico: dict) -> "FullBodyCon...
class EndEffectorConstraintSet (line 328) | class EndEffectorConstraintSet:
method __init__ (line 333) | def __init__(
method update_constraints (line 387) | def update_constraints(self, data_dict: dict, index_dict: dict) -> None:
method crop_move (line 429) | def crop_move(self, start: int, end: int) -> "EndEffectorConstraintSet":
method get_save_info (line 447) | def get_save_info(self) -> dict:
method to (line 468) | def to(
method from_dict (line 486) | def from_dict(cls, skeleton: SkeletonBase, dico: dict) -> "EndEffector...
class LeftHandConstraintSet (line 515) | class LeftHandConstraintSet(EndEffectorConstraintSet):
method __init__ (line 521) | def __init__(self, *args, **kwargs: dict):
class RightHandConstraintSet (line 525) | class RightHandConstraintSet(EndEffectorConstraintSet):
method __init__ (line 531) | def __init__(self, *args, **kwargs: dict):
class LeftFootConstraintSet (line 535) | class LeftFootConstraintSet(EndEffectorConstraintSet):
method __init__ (line 541) | def __init__(self, *args, **kwargs: dict):
class RightFootConstraintSet (line 545) | class RightFootConstraintSet(EndEffectorConstraintSet):
method __init__ (line 551) | def __init__(self, *args, **kwargs: dict):
function load_constraints_lst (line 566) | def load_constraints_lst(
function save_constraints_lst (line 595) | def save_constraints_lst(path: str, constraints_lst: list) -> list | None:
FILE: kimodo/demo/__init__.py
function main (line 13) | def main() -> None:
FILE: kimodo/demo/app.py
class Demo (line 55) | class Demo:
method __init__ (line 56) | def __init__(self, default_model_name: str = DEFAULT_MODEL):
method ensure_examples_layout (line 106) | def ensure_examples_layout(self) -> None:
method get_examples_base_dir (line 124) | def get_examples_base_dir(self, model_name: str, absolute: bool = True...
method load_model (line 127) | def load_model(self, model_name: str) -> ModelBundle:
method prewarm_embedding_cache (line 161) | def prewarm_embedding_cache(self, model_name: str, model: object) -> N...
method build_constraint_tracks (line 189) | def build_constraint_tracks(
method set_timeline_defaults (line 210) | def set_timeline_defaults(self, timeline, model_fps: float) -> None:
method _apply_constraint_overlay_visibility (line 223) | def _apply_constraint_overlay_visibility(self, session: ClientSession)...
method set_constraint_tracks_visible (line 229) | def set_constraint_tracks_visible(self, session: ClientSession, visibl...
method _cleanup_session_for_client (line 272) | def _cleanup_session_for_client(self, client_id: int) -> None:
method _setup_demo_for_client (line 279) | def _setup_demo_for_client(self, client: viser.ClientHandle) -> None:
method on_client_connect (line 347) | def on_client_connect(self, client: viser.ClientHandle) -> None:
method setup_scene (line 365) | def setup_scene(self, client: viser.ClientHandle) -> None:
method on_client_disconnect (line 398) | def on_client_disconnect(self, client: viser.ClientHandle) -> None:
method set_start_direction_visible (line 408) | def set_start_direction_visible(self, client_id: int, visible: bool) -...
method client_active (line 414) | def client_active(self, client_id: int) -> bool:
method add_character_motion (line 417) | def add_character_motion(
method clear_motions (line 486) | def clear_motions(self, client_id: int) -> None:
method compute_model_constraints_lst (line 494) | def compute_model_constraints_lst(
method check_cuda_health (line 502) | def check_cuda_health(self) -> bool:
method _trigger_restart (line 521) | def _trigger_restart(self) -> None:
method generate (line 530) | def generate(
method set_frame (line 582) | def set_frame(self, client_id: int, frame_idx: int, update_timeline: b...
method run (line 595) | def run(self) -> None:
method configure_theme (line 629) | def configure_theme(
FILE: kimodo/demo/embedding_cache.py
class CacheStats (line 24) | class CacheStats:
class EmbeddingCache (line 30) | class EmbeddingCache:
method __init__ (line 33) | def __init__(
method _model_dir (line 56) | def _model_dir(self) -> str:
method _index_path (line 59) | def _index_path(self) -> str:
method _prewarm_marker_path (line 62) | def _prewarm_marker_path(self, key: str) -> str:
method has_prewarm_marker (line 65) | def has_prewarm_marker(self, key: str) -> bool:
method write_prewarm_marker (line 68) | def write_prewarm_marker(self, key: str, *, prompt_count: int) -> None:
method _load_index (line 76) | def _load_index(self) -> None:
method _save_index (line 88) | def _save_index(self) -> None:
method _make_key (line 95) | def _make_key(self, text: str) -> str:
method _entry_path (line 99) | def _entry_path(self, key: str) -> str:
method _mem_get (line 102) | def _mem_get(self, key: str) -> Optional[np.ndarray]:
method _mem_put (line 108) | def _mem_put(self, key: str, value: np.ndarray) -> None:
method _disk_load (line 114) | def _disk_load(self, key: str) -> Optional[np.ndarray]:
method _disk_save (line 123) | def _disk_save(self, key: str, value: np.ndarray) -> None:
method _maybe_use_session_cache (line 132) | def _maybe_use_session_cache(self, texts: list[str]):
method _update_session_cache (line 140) | def _update_session_cache(self, texts: list[str], tensor: torch.Tensor...
method get_or_encode (line 148) | def get_or_encode(self, texts: Iterable[str], encoder):
class CachedTextEncoder (line 217) | class CachedTextEncoder:
method __init__ (line 220) | def __init__(self, encoder, *, model_name: str, base_dir: Optional[str...
method __call__ (line 226) | def __call__(self, texts):
method prewarm (line 229) | def prewarm(self, texts) -> None:
method to (line 239) | def to(self, device=None, dtype=None):
method session_context (line 245) | def session_context(self, session):
method __getattr__ (line 252) | def __getattr__(self, name):
FILE: kimodo/demo/generation.py
function compute_model_constraints_lst (line 24) | def compute_model_constraints_lst(
function generate (line 132) | def generate(
FILE: kimodo/demo/queue_manager.py
class UserQueue (line 23) | class UserQueue:
method __init__ (line 26) | def __init__(self, max_active: int, max_minutes: float) -> None:
method try_activate (line 34) | def try_activate(self, client_id: int) -> bool:
method enqueue (line 45) | def enqueue(self, client_id: int) -> None:
method remove (line 50) | def remove(self, client_id: int) -> bool:
method promote_next (line 62) | def promote_next(self) -> int | None:
method get_queue_position (line 74) | def get_queue_position(self, client_id: int) -> tuple[int, int] | None:
method get_estimated_wait_seconds (line 82) | def get_estimated_wait_seconds(self, client_id: int) -> float:
method is_active (line 99) | def is_active(self, client_id: int) -> bool:
method was_active (line 103) | def was_active(self, client_id: int) -> bool:
function _format_wait (line 108) | def _format_wait(seconds: float) -> str:
function _queue_modal_markdown (line 115) | def _queue_modal_markdown(position: int, total: int, estimated_wait_sec:...
function _welcome_modal_markdown (line 134) | def _welcome_modal_markdown() -> str:
function _expiry_modal_markdown (line 145) | def _expiry_modal_markdown() -> str:
class QueueManager (line 156) | class QueueManager:
method __init__ (line 159) | def __init__(
method _queue_modal_refresh_loop (line 184) | def _queue_modal_refresh_loop(self) -> None:
method on_client_connect (line 189) | def on_client_connect(self, client: viser.ClientHandle) -> None:
method on_client_disconnect (line 207) | def on_client_disconnect(self, client_id: int) -> None:
method _show_queue_modal (line 222) | def _show_queue_modal(self, client: viser.ClientHandle) -> None:
method _show_quick_start_modal (line 238) | def _show_quick_start_modal(self, client: viser.ClientHandle) -> None:
method _show_welcome_modal (line 249) | def _show_welcome_modal(self, client: viser.ClientHandle) -> None:
method _update_all_queue_modals (line 267) | def _update_all_queue_modals(self) -> None:
method _promote_next_user (line 281) | def _promote_next_user(self) -> None:
method _start_session_timer (line 307) | def _start_session_timer(self, client_id: int) -> None:
method _on_session_expired (line 317) | def _on_session_expired(self, client_id: int) -> None:
FILE: kimodo/demo/state.py
class ModelBundle (line 22) | class ModelBundle:
class ClientSession (line 30) | class ClientSession:
FILE: kimodo/demo/ui.py
function extract_intervals_and_singles (line 49) | def extract_intervals_and_singles(t: torch.Tensor):
function create_gui (line 76) | def create_gui(
FILE: kimodo/exports/bvh.py
function _strip_end_site_blocks (line 20) | def _strip_end_site_blocks(bvh_text: str) -> str:
function _coerce_batch (line 49) | def _coerce_batch(name: str, x: torch.Tensor, *, expected_ndim: int) -> ...
function motion_to_bvh (line 62) | def motion_to_bvh(
function motion_to_bvh_bytes (line 214) | def motion_to_bvh_bytes(
function save_motion_bvh (line 235) | def save_motion_bvh(
function read_bvh_frame_time_seconds (line 251) | def read_bvh_frame_time_seconds(path: Union[str, Path]) -> float:
function bvh_to_kimodo_motion (line 261) | def bvh_to_kimodo_motion(
FILE: kimodo/exports/motion_convert_lib.py
function convert_motion_files (line 28) | def convert_motion_files(
function _validate_output_extension (line 147) | def _validate_output_extension(to_fmt: str, output_path: str) -> None:
FILE: kimodo/exports/motion_formats.py
function infer_npz_kind (line 17) | def infer_npz_kind(path: str) -> NpzMotionKind:
function infer_source_format_from_path (line 31) | def infer_source_format_from_path(path: str) -> MotionSourceFormat:
function infer_target_format_from_path (line 43) | def infer_target_format_from_path(path: str, from_fmt: MotionSourceForma...
function resolve_source_fps (line 63) | def resolve_source_fps(
FILE: kimodo/exports/motion_io.py
function _quaternion_slerp (line 26) | def _quaternion_slerp(q0: torch.Tensor, q1: torch.Tensor, t: torch.Tenso...
function resample_motion_dict_to_kimodo_fps (line 42) | def resample_motion_dict_to_kimodo_fps(
function warn_kimodo_npz_framerate (line 99) | def warn_kimodo_npz_framerate(source_fps: float, t_before: int, t_after:...
function _coerce_time_local_root (line 111) | def _coerce_time_local_root(
function complete_motion_dict (line 133) | def complete_motion_dict(
function motion_dict_to_numpy (line 189) | def motion_dict_to_numpy(d: Dict[str, Any]) -> Dict[str, np.ndarray]:
function save_kimodo_npz (line 202) | def save_kimodo_npz(path: str, motion_dict: Dict[str, Any]) -> None:
function load_kimodo_npz (line 207) | def load_kimodo_npz(path: str) -> Dict[str, np.ndarray]:
function load_g1_csv (line 213) | def load_g1_csv(
function load_amass_npz (line 236) | def load_amass_npz(
function load_kimodo_npz_as_torch (line 256) | def load_kimodo_npz_as_torch(
function save_kimodo_npz_at_target_fps (line 308) | def save_kimodo_npz_at_target_fps(
function kimodo_npz_to_bytes (line 324) | def kimodo_npz_to_bytes(motion_dict: Dict[str, Any]) -> bytes:
function g1_csv_to_bytes (line 333) | def g1_csv_to_bytes(motion_dict: Dict[str, Any], skeleton: SkeletonBase,...
function amass_npz_to_bytes (line 350) | def amass_npz_to_bytes(motion_dict: Dict[str, Any], skeleton: SkeletonBa...
function _read_amass_source_fps (line 365) | def _read_amass_source_fps(path: str) -> float:
function load_motion_file (line 373) | def load_motion_file(
FILE: kimodo/exports/mujoco.py
class MujocoQposConverter (line 27) | class MujocoQposConverter:
method __new__ (line 42) | def __new__(
method __init__ (line 53) | def __init__(
method _prepare_transforms (line 71) | def _prepare_transforms(self):
method dict_to_qpos (line 215) | def dict_to_qpos(
method qpos_to_motion_dict (line 249) | def qpos_to_motion_dict(
method save_csv (line 329) | def save_csv(self, qpos: torch.Tensor | np.ndarray, csv_path):
method _local_rots_to_joint_dofs (line 346) | def _local_rots_to_joint_dofs(
method _local_rots_to_joint_dofs_axis_angle (line 360) | def _local_rots_to_joint_dofs_axis_angle(
method _local_rots_f2q_to_joint_dofs (line 379) | def _local_rots_f2q_to_joint_dofs(self, local_rot_mats_f2q: torch.Tens...
method _clamp_to_limits (line 384) | def _clamp_to_limits(self, joint_dofs: torch.Tensor) -> torch.Tensor:
method _clamp_joint_dofs (line 394) | def _clamp_joint_dofs(self, joint_dofs: torch.Tensor, rest_dofs: torch...
method _joint_dofs_to_local_rot_mats (line 404) | def _joint_dofs_to_local_rot_mats(
method project_to_real_robot_rotations (line 432) | def project_to_real_robot_rotations(
method to_qpos (line 483) | def to_qpos(
function apply_g1_real_robot_projection (line 547) | def apply_g1_real_robot_projection(
FILE: kimodo/exports/smplx.py
function kimodo_y_up_to_amass_coord_rotation_matrix (line 17) | def kimodo_y_up_to_amass_coord_rotation_matrix() -> np.ndarray:
function get_amass_parameters (line 42) | def get_amass_parameters(
function amass_arrays_to_kimodo_motion (line 74) | def amass_arrays_to_kimodo_motion(
function amass_npz_to_kimodo_motion (line 142) | def amass_npz_to_kimodo_motion(npz_path: str, skeleton, source_fps: Opti...
class AMASSConverter (line 162) | class AMASSConverter:
method __init__ (line 163) | def __init__(
method convert_save_npz (line 198) | def convert_save_npz(self, output: dict, npz_path, z_up=True):
method save_npz (line 214) | def save_npz(self, trans, root_orient, pose_body, base_output, npz_path):
FILE: kimodo/geometry.py
function angle_to_Y_rotation_matrix (line 9) | def angle_to_Y_rotation_matrix(angle: torch.Tensor) -> torch.Tensor:
function matrix_to_cont6d (line 21) | def matrix_to_cont6d(matrix: torch.Tensor) -> torch.Tensor:
function cont6d_to_matrix (line 30) | def cont6d_to_matrix(cont6d: torch.Tensor) -> torch.Tensor:
function axis_angle_to_matrix (line 53) | def axis_angle_to_matrix(axis_angle: torch.Tensor) -> torch.Tensor:
function matrix_to_axis_angle (line 80) | def matrix_to_axis_angle(R: torch.Tensor) -> torch.Tensor:
function quaternion_to_axis_angle (line 93) | def quaternion_to_axis_angle(quat: torch.Tensor) -> torch.Tensor:
function _sqrt_positive_part (line 139) | def _sqrt_positive_part(x: torch.Tensor) -> torch.Tensor:
function matrix_to_quaternion (line 144) | def matrix_to_quaternion(matrix: torch.Tensor) -> torch.Tensor:
function quaternion_to_matrix (line 190) | def quaternion_to_matrix(quaternions: torch.Tensor) -> torch.Tensor:
FILE: kimodo/meta.py
function load_prompts_from_meta (line 13) | def load_prompts_from_meta(meta_path: str, **kwargs):
function parse_prompts_from_meta (line 32) | def parse_prompts_from_meta(
FILE: kimodo/metrics/base.py
class Metric (line 13) | class Metric:
method __init__ (line 17) | def __init__(self, **kwargs):
method __call__ (line 20) | def __call__(self, *args, **kwargs):
method _compute (line 28) | def _compute(self, **kwargs):
method clear (line 32) | def clear(self):
method aggregate (line 36) | def aggregate(self):
function compute_metrics (line 47) | def compute_metrics(metrics_list: List[Metric], metrics_in: Dict) -> Dict:
function aggregate_metrics (line 55) | def aggregate_metrics(metrics_list: List[Metric]) -> Dict:
function clear_metrics (line 63) | def clear_metrics(metrics_list: List[Metric]) -> None:
FILE: kimodo/metrics/constraints.py
class ContraintFollow (line 23) | class ContraintFollow(Metric):
method __init__ (line 26) | def __init__(
method _compute (line 37) | def _compute(
FILE: kimodo/metrics/foot_skate.py
function get_four_contacts (line 20) | def get_four_contacts(fidx: list):
class FootSkateFromHeight (line 31) | class FootSkateFromHeight(Metric):
method __init__ (line 34) | def __init__(
method _compute (line 47) | def _compute(
class FootSkateFromContacts (line 80) | class FootSkateFromContacts(Metric):
method __init__ (line 83) | def __init__(
method _compute (line 94) | def _compute(
class FootSkateRatio (line 136) | class FootSkateRatio(Metric):
method __init__ (line 142) | def __init__(
method _compute (line 158) | def _compute(
class FootContactConsistency (line 196) | class FootContactConsistency(Metric):
method __init__ (line 203) | def __init__(
method _compute (line 219) | def _compute(
FILE: kimodo/metrics/tmr.py
function get_score_matrix_unit (line 21) | def get_score_matrix_unit(x, y):
function get_scores_unit (line 27) | def get_scores_unit(x, y):
function compute_tmr_per_sample_retrieval (line 33) | def compute_tmr_per_sample_retrieval(
class TMR_Metric (line 65) | class TMR_Metric(Metric):
method __init__ (line 66) | def __init__(
method clear (line 78) | def clear(self):
method _compute (line 84) | def _compute(
method aggregate (line 139) | def aggregate(self):
class TMR_EmbeddingMetric (line 224) | class TMR_EmbeddingMetric(Metric):
method __init__ (line 230) | def __init__(self, ranks_rounding: int = 2, **kwargs):
method clear (line 234) | def clear(self):
method _compute (line 240) | def _compute(
method aggregate (line 265) | def aggregate(self):
function compute_tmr_retrieval_metrics (line 328) | def compute_tmr_retrieval_metrics(
function all_contrastive_metrics (line 395) | def all_contrastive_metrics(sims, emb=None, threshold=None, rounding=2, ...
function contrastive_metrics (line 415) | def contrastive_metrics(
function break_ties_average (line 463) | def break_ties_average(sorted_dists, gt_dists):
function calculate_activation_statistics (line 480) | def calculate_activation_statistics(activations):
function calculate_frechet_distance (line 493) | def calculate_frechet_distance(mu1, sigma1, mu2, sigma2, eps=1e-6):
FILE: kimodo/model/backbone.py
function pad_x_and_mask_to_fixed_size (line 19) | def pad_x_and_mask_to_fixed_size(x: Tensor, mask: Tensor, size: int):
class TransformerEncoderBlockConfig (line 61) | class TransformerEncoderBlockConfig:
class TransformerEncoderBlock (line 101) | class TransformerEncoderBlock(nn.Module):
method __init__ (line 103) | def __init__(self, conf):
method forward (line 136) | def forward(
class PositionalEncoding (line 235) | class PositionalEncoding(nn.Module):
method __init__ (line 238) | def __init__(
method forward (line 270) | def forward(self, x: torch.Tensor) -> torch.Tensor:
class TimestepEmbedder (line 283) | class TimestepEmbedder(nn.Module):
method __init__ (line 286) | def __init__(self, latent_dim: int, sequence_pos_encoder: PositionalEn...
method forward (line 303) | def forward(self, timesteps: torch.Tensor) -> torch.Tensor:
FILE: kimodo/model/cfg.py
class ClassifierFreeGuidedModel (line 13) | class ClassifierFreeGuidedModel(nn.Module):
method __init__ (line 16) | def __init__(self, model: nn.Module, cfg_type: Optional[str] = "separa...
method forward (line 24) | def forward(
FILE: kimodo/model/common.py
function get_env_var (line 9) | def get_env_var(name: str, default=None):
function resolve_target (line 14) | def resolve_target(target: str):
function materialize_value (line 21) | def materialize_value(value):
function instantiate_from_dict (line 33) | def instantiate_from_dict(node, overrides=None):
FILE: kimodo/model/diffusion.py
function get_beta_schedule (line 12) | def get_beta_schedule(
class Diffusion (line 29) | class Diffusion(torch.nn.Module):
method __init__ (line 32) | def __init__(self, num_base_steps: int):
method extra_repr (line 43) | def extra_repr(self) -> str:
method device (line 47) | def device(self):
method space_timesteps (line 50) | def space_timesteps(self, num_denoising_steps: int) -> Tuple[torch.Ten...
method calc_diffusion_vars (line 60) | def calc_diffusion_vars(self, use_timesteps: torch.Tensor) -> None:
method q_sample (line 96) | def q_sample(
class DDIMSampler (line 113) | class DDIMSampler(nn.Module):
method __init__ (line 116) | def __init__(self, diffusion: Diffusion):
method __call__ (line 120) | def __call__(
FILE: kimodo/model/kimodo_model.py
class Kimodo (line 25) | class Kimodo(nn.Module):
method __init__ (line 28) | def __init__(
method output_skeleton (line 61) | def output_skeleton(self):
method train (line 67) | def train(self, mode: bool):
method eval (line 71) | def eval(self):
method denoising_step (line 75) | def denoising_step(
method _multiprompt (line 123) | def _multiprompt(
method __call__ (line 380) | def __call__(
method _generate (line 562) | def _generate(
FILE: kimodo/model/llm2vec/llm2vec.py
function batch_to_device (line 64) | def batch_to_device(batch, target_device: device):
class LLM2Vec (line 72) | class LLM2Vec(nn.Module):
method __init__ (line 73) | def __init__(
method _get_model_class (line 92) | def _get_model_class(cls, config_class_name, enable_bidirectional):
method from_pretrained (line 115) | def from_pretrained(
method prepare_for_tokenization (line 172) | def prepare_for_tokenization(self, text):
method tokenize (line 201) | def tokenize(self, texts):
method _skip_instruction (line 240) | def _skip_instruction(self, sentence_feature):
method forward (line 244) | def forward(self, sentence_feature: Dict[str, Tensor]):
method get_pooling (line 253) | def get_pooling(self, features, last_hidden_states): # All models pad...
method _convert_to_str (line 278) | def _convert_to_str(self, instruction, text):
method encode (line 305) | def encode(
method save (line 405) | def save(self, output_path, merge_before_save=False, save_config=True):
method _encode (line 427) | def _encode(
method _text_length (line 452) | def _text_length(self, text: Union[List[int], List[List[int]]]):
method resize_token_embeddings (line 469) | def resize_token_embeddings(
method gradient_checkpointing_enable (line 476) | def gradient_checkpointing_enable(self, gradient_checkpointing_kwargs=...
FILE: kimodo/model/llm2vec/llm2vec_wrapper.py
class LLM2VecEncoder (line 13) | class LLM2VecEncoder:
method __init__ (line 16) | def __init__(
method to (line 53) | def to(self, device: torch.device):
method eval (line 58) | def eval(self):
method get_device (line 62) | def get_device(self):
method __call__ (line 65) | def __call__(self, text: list[str] | str):
FILE: kimodo/model/llm2vec/models/attn_mask_utils.py
function _prepare_4d_causal_attention_mask (line 28) | def _prepare_4d_causal_attention_mask(
function _prepare_4d_causal_attention_mask_for_sdpa (line 89) | def _prepare_4d_causal_attention_mask_for_sdpa(
FILE: kimodo/model/llm2vec/models/bidirectional_llama.py
class ModifiedLlamaAttention (line 59) | class ModifiedLlamaAttention(LlamaAttention):
method __init__ (line 60) | def __init__(self, *args, **kwargs):
class ModifiedLlamaDecoderLayer (line 84) | class ModifiedLlamaDecoderLayer(LlamaDecoderLayer):
method __init__ (line 85) | def __init__(self, config: LlamaConfig, layer_idx: int):
class LlamaBiModel (line 99) | class LlamaBiModel(LlamaModel):
method __init__ (line 102) | def __init__(self, config: LlamaConfig):
method _update_causal_mask (line 122) | def _update_causal_mask(
class LlamaBiForMNTP (line 204) | class LlamaBiForMNTP(LlamaForCausalLM):
method __init__ (line 205) | def __init__(self, config):
method get_model_for_peft (line 215) | def get_model_for_peft(self):
method set_model_for_peft (line 219) | def set_model_for_peft(self, model: PeftModel):
method save_peft_model (line 223) | def save_peft_model(self, path):
FILE: kimodo/model/llm2vec/models/utils.py
function is_transformers_attn_greater_or_equal_4_43_1 (line 28) | def is_transformers_attn_greater_or_equal_4_43_1():
FILE: kimodo/model/load_model.py
function _resolve_hf_model_path (line 37) | def _resolve_hf_model_path(modelname: str) -> Path:
function _build_api_text_encoder_conf (line 61) | def _build_api_text_encoder_conf(text_encoder_url: str) -> dict:
function _build_local_text_encoder_conf (line 68) | def _build_local_text_encoder_conf(text_encoder_fp32: bool = False) -> d...
function _select_text_encoder_conf (line 83) | def _select_text_encoder_conf(text_encoder_url: str, text_encoder_fp32: ...
function load_model (line 108) | def load_model(
FILE: kimodo/model/loading.py
function get_env_var (line 24) | def get_env_var(name: str, default: Optional[str] = None) -> Optional[str]:
function instantiate_from_dict (line 29) | def instantiate_from_dict(
function load_checkpoint_state_dict (line 44) | def load_checkpoint_state_dict(ckpt_path: Union[str, Path]) -> dict:
FILE: kimodo/model/registry.py
class ModelInfo (line 33) | class ModelInfo:
method dataset_ui_label (line 45) | def dataset_ui_label(self) -> str:
function _parse_repo_id (line 49) | def _parse_repo_id(repo_id: str) -> Optional[ModelInfo]:
function _version_tuple (line 78) | def _version_tuple(v: str) -> tuple[int, ...]:
function _version_key (line 87) | def _version_key(info: ModelInfo) -> tuple[int, ...]:
function _build_registry (line 91) | def _build_registry() -> tuple[list[ModelInfo], dict[str, str], list[str]]:
function get_skeleton_display_name (line 163) | def get_skeleton_display_name(skeleton_key: str) -> str:
function get_skeleton_key_from_display_name (line 168) | def get_skeleton_key_from_display_name(display_name: str) -> Optional[str]:
function get_skeleton_display_names_for_dataset (line 176) | def get_skeleton_display_names_for_dataset(dataset_ui_label: str, family...
function get_short_key (line 185) | def get_short_key(repo_id: str) -> Optional[str]:
function get_model_info (line 193) | def get_model_info(short_key: str) -> Optional[ModelInfo]:
function get_short_key_from_display_name (line 208) | def get_short_key_from_display_name(display_name: str) -> Optional[str]:
function get_models_for_demo (line 216) | def get_models_for_demo() -> list[ModelInfo]:
function get_datasets (line 221) | def get_datasets(family: Optional[str] = None) -> list[str]:
function get_skeletons_for_dataset (line 235) | def get_skeletons_for_dataset(dataset_ui_label: str, family: Optional[st...
function get_versions_for_dataset_skeleton (line 253) | def get_versions_for_dataset_skeleton(dataset_ui_label: str, skeleton: s...
function get_models_for_dataset_skeleton (line 267) | def get_models_for_dataset_skeleton(
function resolve_to_short_key (line 283) | def resolve_to_short_key(dataset_ui_label: str, skeleton: str, version: ...
function _normalize_family (line 304) | def _normalize_family(s: str) -> Optional[str]:
function _normalize_dataset (line 309) | def _normalize_dataset(s: str) -> Optional[str]:
function _normalize_skeleton (line 314) | def _normalize_skeleton(s: str) -> Optional[str]:
function _get_latest_for_family_skeleton_dataset (line 319) | def _get_latest_for_family_skeleton_dataset(family: str, skeleton: str, ...
function kimodo_short_key_for_skeleton_dataset (line 329) | def kimodo_short_key_for_skeleton_dataset(skeleton: str, dataset: str) -...
function registry_skeleton_for_joint_count (line 336) | def registry_skeleton_for_joint_count(nb_joints: int) -> str:
function resolve_model_name (line 359) | def resolve_model_name(name: Optional[str], default_family: Optional[str...
FILE: kimodo/model/text_encoder_api.py
class TextEncoderAPI (line 18) | class TextEncoderAPI:
method __init__ (line 21) | def __init__(self, url: str):
method _create_np_random_name (line 26) | def _create_np_random_name(self):
method to (line 31) | def to(self, device=None, dtype=None):
method __call__ (line 38) | def __call__(self, texts):
FILE: kimodo/model/tmr.py
class PositionalEncoding (line 21) | class PositionalEncoding(nn.Module):
method __init__ (line 24) | def __init__(self, d_model, dropout=0.1, max_len=5000, batch_first=Fal...
method forward (line 44) | def forward(self, x: Tensor) -> Tensor:
function load_ckpt (line 52) | def load_ckpt(self, ckpt_path):
class ACTORStyleEncoder (line 58) | class ACTORStyleEncoder(nn.Module):
method __init__ (line 61) | def __init__(
method forward (line 111) | def forward(self, x_dict: Dict) -> Tensor:
class TMR (line 132) | class TMR(nn.Module):
method from_args (line 139) | def from_args(
method __init__ (line 189) | def __init__(
method full_text_encoder (line 224) | def full_text_encoder(self, texts: list[str]):
method _find_encoder (line 240) | def _find_encoder(self, inputs, modality):
method _encode (line 267) | def _encode(
method encode_motion (line 308) | def encode_motion(
method encode_text (line 347) | def encode_text(
method encode_raw_text (line 363) | def encode_raw_text(
FILE: kimodo/model/twostage_denoiser.py
class TwostageDenoiser (line 15) | class TwostageDenoiser(nn.Module):
method __init__ (line 18) | def __init__(
method load_ckpt (line 66) | def load_ckpt(self, ckpt_path: str) -> None:
method forward (line 73) | def forward(
FILE: kimodo/motion_rep/conditioning.py
function build_condition_dicts (line 10) | def build_condition_dicts(constraints_lst: list):
function get_unique_index_and_data (line 18) | def get_unique_index_and_data(indices_lst, data):
FILE: kimodo/motion_rep/feature_utils.py
function diff_angles (line 15) | def diff_angles(angles: torch.Tensor, fps: float) -> torch.Tensor:
function compute_vel_xyz (line 39) | def compute_vel_xyz(
function compute_vel_angle (line 76) | def compute_vel_angle(
function compute_heading_angle (line 112) | def compute_heading_angle(posed_joints: torch.Tensor, skeleton: Skeleton...
function length_to_mask (line 129) | def length_to_mask(
class RotateFeatures (line 165) | class RotateFeatures:
method __init__ (line 168) | def __init__(self, angle: torch.Tensor):
method rotate_positions (line 188) | def rotate_positions(self, positions: torch.Tensor):
method rotate_2d_positions (line 192) | def rotate_2d_positions(self, positions_2d: torch.Tensor):
method rotate_rotations (line 196) | def rotate_rotations(self, rotations: torch.Tensor):
method rotate_6d_rotations (line 210) | def rotate_6d_rotations(self, rotations_6d: torch.Tensor):
FILE: kimodo/motion_rep/feet.py
function foot_detect_from_pos_and_vel (line 11) | def foot_detect_from_pos_and_vel(
FILE: kimodo/motion_rep/reps/base.py
function _require_split_stats_layout (line 19) | def _require_split_stats_layout(stats_path: str) -> None:
class MotionRepBase (line 36) | class MotionRepBase:
method __init__ (line 47) | def __init__(
method get_root_pos (line 85) | def get_root_pos(self, features: torch.Tensor, fallback_to_smooth: boo...
method global_root_to_local_root (line 114) | def global_root_to_local_root(
method get_root_heading_angle (line 159) | def get_root_heading_angle(self, features: torch.Tensor) -> torch.Tensor:
method rotate_to (line 166) | def rotate_to(
method rotate_to_zero (line 183) | def rotate_to_zero(
method randomize_first_heading (line 193) | def randomize_first_heading(
method translate_2d_to (line 207) | def translate_2d_to(
method translate_2d_to_zero (line 223) | def translate_2d_to_zero(
method canonicalize (line 233) | def canonicalize(self, features: torch.Tensor, normalized: bool = False):
method normalize (line 243) | def normalize(self, features):
method unnormalize (line 247) | def unnormalize(self, features):
method create_conditions_from_constraints (line 251) | def create_conditions_from_constraints(
method create_conditions_from_constraints_batched (line 262) | def create_conditions_from_constraints_batched(
FILE: kimodo/motion_rep/reps/kimodo_motionrep.py
class KimodoMotionRep (line 23) | class KimodoMotionRep(MotionRepBase):
method __init__ (line 26) | def __init__(
method __call__ (line 51) | def __call__(
method rotate (line 114) | def rotate(self, features: torch.Tensor, angle: torch.Tensor):
method translate_2d (line 148) | def translate_2d(
method inverse (line 167) | def inverse(
method create_conditions (line 222) | def create_conditions(
FILE: kimodo/motion_rep/reps/tmr_motionrep.py
class TMRMotionRep (line 17) | class TMRMotionRep(MotionRepBase):
method __init__ (line 29) | def __init__(
method __call__ (line 53) | def __call__(
method rotate (line 133) | def rotate(self, features: torch.Tensor, angle: torch.Tensor):
method translate_2d (line 167) | def translate_2d(
method inverse (line 186) | def inverse(
FILE: kimodo/motion_rep/smooth_root.py
class TrajectorySmoother (line 15) | class TrajectorySmoother:
method __init__ (line 22) | def __init__(
method smooth (line 89) | def smooth(self, targets, x0):
method x_update (line 112) | def x_update(self, x, z, u, x_t):
method z_update (line 119) | def z_update(self, z, x, z_t, u):
method u_update (line 137) | def u_update(self, u, x, z):
function smooth_signal (line 142) | def smooth_signal(x, margins, pos_weight=0, alpha_overrelax=1.8, admm_it...
function get_smooth_root_pos (line 202) | def get_smooth_root_pos(hip_translations):
FILE: kimodo/motion_rep/stats.py
class Stats (line 15) | class Stats(torch.nn.Module):
method __init__ (line 22) | def __init__(
method sliced (line 34) | def sliced(self, indices):
method load (line 43) | def load(self):
method register_from_tensors (line 60) | def register_from_tensors(self, mean: torch.Tensor, std: torch.Tensor):
method normalize (line 65) | def normalize(self, data: torch.Tensor) -> torch.Tensor:
method unnormalize (line 72) | def unnormalize(self, data: torch.Tensor) -> torch.Tensor:
method is_loaded (line 79) | def is_loaded(self):
method get_dim (line 83) | def get_dim(self):
method save (line 87) | def save(
method __eq__ (line 112) | def __eq__(self, other):
method __hash__ (line 116) | def __hash__(self):
method __repr__ (line 122) | def __repr__(self):
FILE: kimodo/postprocess.py
function extract_input_motion_from_constraints (line 27) | def extract_input_motion_from_constraints(
function create_working_rig_from_skeleton (line 117) | def create_working_rig_from_skeleton(
function post_process_motion (line 186) | def post_process_motion(
FILE: kimodo/sanitize.py
function sanitize_text (line 6) | def sanitize_text(text: str, paragraph: bool = True) -> str:
function sanitize_texts (line 65) | def sanitize_texts(texts: list[str]) -> list[str]:
FILE: kimodo/scripts/generate.py
function parse_args (line 20) | def parse_args():
function get_texts_and_num_frames_from_prompt (line 131) | def get_texts_and_num_frames_from_prompt(prompt: str, duration: str, fps...
function _single_file_path (line 152) | def _single_file_path(path: str, ext: str) -> str:
function _output_dir_and_path (line 165) | def _output_dir_and_path(path: str, default_base: str, ext: str):
function resolve_cfg_kwargs (line 177) | def resolve_cfg_kwargs(args: argparse.Namespace, meta: Optional[Dict[str...
function get_generation_inputs (line 239) | def get_generation_inputs(args, fps: float):
function main (line 276) | def main():
FILE: kimodo/scripts/gradio_theme.py
function get_gradio_theme (line 7) | def get_gradio_theme(remove_gradio_footer=False):
FILE: kimodo/scripts/lock_requirements.py
function _run (line 33) | def _run(cmd: list[str]) -> None:
function _ensure_uv (line 38) | def _ensure_uv() -> None:
function _parse_req_name (line 49) | def _parse_req_name(line: str) -> str:
function _iter_blocks (line 58) | def _iter_blocks(lines: list[str]) -> Iterable[list[str]]:
function _should_omit (line 88) | def _should_omit(req_line: str) -> bool:
function filter_lockfile (line 98) | def filter_lockfile(path: Path) -> None:
function main (line 129) | def main() -> None:
FILE: kimodo/scripts/motion_convert.py
function run_convert (line 17) | def run_convert(
function build_argparser (line 40) | def build_argparser() -> argparse.ArgumentParser:
function main (line 92) | def main(argv: list[str] | None = None) -> int:
FILE: kimodo/scripts/run_text_encoder_server.py
class DemoWrapper (line 35) | class DemoWrapper:
method __init__ (line 36) | def __init__(self, text_encoder, tmp_folder):
method __call__ (line 40) | def __call__(self, text, filename, progress=gr.Progress()):
function _get_env (line 56) | def _get_env(name: str, default):
function _build_text_encoder (line 60) | def _build_text_encoder(name: str, fp32: bool = False):
function parse_args (line 71) | def parse_args():
function main (line 91) | def main():
FILE: kimodo/skeleton/base.py
class SkeletonBase (line 20) | class SkeletonBase(torch.nn.Module):
method __init__ (line 38) | def __init__(
method expand_joint_names (line 135) | def expand_joint_names(self, joint_names):
method expand_joint_names_batched (line 175) | def expand_joint_names_batched(self, joint_names):
method __repr__ (line 221) | def __repr__(self):
method device (line 227) | def device(self):
method fk (line 236) | def fk(self, local_joint_rots: torch.Tensor, root_positions: torch.Ten...
method to_standard_tpose (line 250) | def to_standard_tpose(self, local_rot_mats: torch.Tensor):
method from_standard_tpose (line 254) | def from_standard_tpose(self, local_rot_mats: torch.Tensor):
method global_rots_to_local_rots (line 258) | def global_rots_to_local_rots(self, global_joint_rots: torch.Tensor):
method get_skel_slice (line 262) | def get_skel_slice(self, skeleton: "SkeletonBase"):
FILE: kimodo/skeleton/bvh.py
class BvhNode (line 13) | class BvhNode:
method __init__ (line 16) | def __init__(self, value=[], parent=None):
method add_child (line 24) | def add_child(self, item):
method filter (line 29) | def filter(self, key):
method __iter__ (line 35) | def __iter__(self):
method __getitem__ (line 39) | def __getitem__(self, key):
method __repr__ (line 50) | def __repr__(self):
method name (line 54) | def name(self):
class Bvh (line 59) | class Bvh:
method __init__ (line 62) | def __init__(self, data: str, backend: Optional[str] = "graph"):
method build_data_array (line 82) | def build_data_array(self):
method tokenize (line 94) | def tokenize(self):
method search (line 123) | def search(self, *items):
method get_joints (line 142) | def get_joints(self):
method get_joints_names (line 154) | def get_joints_names(self):
method joint_direct_children (line 166) | def joint_direct_children(self, name):
method get_joint_index (line 171) | def get_joint_index(self, name):
method get_joint (line 175) | def get_joint(self, name):
method joint_offset (line 184) | def joint_offset(self, name, idx=[0, 1, 2]):
method joint_offset_rot (line 192) | def joint_offset_rot(self, name):
method joint_channels (line 196) | def joint_channels(self, name):
method get_joint_channels_index (line 204) | def get_joint_channels_index(self, joint_name):
method get_joint_channel_index (line 216) | def get_joint_channel_index(self, joint, channel):
method frame_joint_channel (line 225) | def frame_joint_channel(self, frame_index, joint, channel, value=None):
method frame_joint_channels (line 236) | def frame_joint_channels(self, frame_index, joint, channels, value=None):
method frames_joint_channels (line 254) | def frames_joint_channels(self, joint, channels, value=None):
method frames_joints_channels (line 275) | def frames_joints_channels(self, joint_names, channels):
method joint_parent (line 288) | def joint_parent(self, name):
method joint_parent_index (line 295) | def joint_parent_index(self, name):
method nframes (line 303) | def nframes(self):
method frame_time (line 311) | def frame_time(self):
class Bone (line 319) | class Bone:
method __init__ (line 322) | def __init__(self):
method __repr__ (line 345) | def __repr__(self):
class SkeletonBvh (line 349) | class SkeletonBvh:
method __init__ (line 352) | def __init__(self):
method get_bones_names (line 360) | def get_bones_names(self):
method get_parent_indices (line 364) | def get_parent_indices(self):
method get_neutral_joints (line 372) | def get_neutral_joints(self):
method load_from_bvh (line 380) | def load_from_bvh(self, fname, exclude_bones=None, spec_channels=None,...
method forward_bvh (line 456) | def forward_bvh(self, bone):
function load_bvh_animation (line 466) | def load_bvh_animation(
function parse_bvh_motion (line 539) | def parse_bvh_motion(file_path_input: str, parse_neutral_joints: bool = ...
FILE: kimodo/skeleton/definitions.py
class SOMASkeleton77 (line 14) | class SOMASkeleton77(SkeletonBase):
method relaxed_hands_rest_pose (line 167) | def relaxed_hands_rest_pose(self):
class SOMASkeleton30 (line 182) | class SOMASkeleton30(SkeletonBase):
method somaskel77 (line 240) | def somaskel77(self):
method to_SOMASkeleton77 (line 247) | def to_SOMASkeleton77(self, local_joint_rots_subset: torch.Tensor):
method from_SOMASkeleton77 (line 259) | def from_SOMASkeleton77(self, local_joint_rots_full: torch.Tensor) -> ...
method output_to_SOMASkeleton77 (line 264) | def output_to_SOMASkeleton77(self, output: dict) -> dict:
class G1Skeleton34 (line 286) | class G1Skeleton34(SkeletonBase):
class SMPLXSkeleton22 (line 338) | class SMPLXSkeleton22(SkeletonBase):
FILE: kimodo/skeleton/kinematics.py
function fk (line 15) | def fk(
function compute_idx_levels (line 76) | def compute_idx_levels(parents):
function batch_rigid_transform (line 98) | def batch_rigid_transform(rot_mats, joints, parents, root_idx):
function transform_mat (line 119) | def transform_mat(R, t):
function forward_kinematics (line 133) | def forward_kinematics(
FILE: kimodo/skeleton/registry.py
function build_skeleton (line 17) | def build_skeleton(nbjoints: int, assets_folder: str | Path = SKELETONS_...
FILE: kimodo/skeleton/transforms.py
function global_rots_to_local_rots (line 12) | def global_rots_to_local_rots(global_joint_rots: torch.Tensor, skeleton):
function change_tpose (line 43) | def change_tpose(local_rot_mats: torch.Tensor, global_rot_offsets: torch...
function to_standard_tpose (line 76) | def to_standard_tpose(local_rot_mats: torch.Tensor, skeleton):
function from_standard_tpose (line 92) | def from_standard_tpose(local_rot_mats: torch.Tensor, skeleton):
FILE: kimodo/tools.py
function validate (line 19) | def validate(validator, save_args: bool = False, super_init: bool = False):
function ensure_batched (line 60) | def ensure_batched(**spec: int) -> Callable[[Callable[P, R]], Callable[P...
function to_numpy (line 275) | def to_numpy(obj):
function to_torch (line 287) | def to_torch(obj, device=None, dtype=None):
function seed_everything (line 305) | def seed_everything(seed: int, deterministic: bool = False) -> None:
function load_json (line 316) | def load_json(path: Union[str, Path]) -> Any:
function save_json (line 341) | def save_json(path: Union[str, Path], data: Any) -> None:
FILE: kimodo/viz/constraint_ui.py
function update_interval (line 19) | def update_interval(interval_start, interval_end, start_frame_idx, end_f...
class ConstraintSet (line 46) | class ConstraintSet:
method __init__ (line 47) | def __init__(
method set_label_visibility (line 65) | def set_label_visibility(self, visible: bool) -> None:
method set_overlay_visibility (line 75) | def set_overlay_visibility(self, only_frame: Optional[int] = None) -> ...
method add_keyframe (line 83) | def add_keyframe(self, keyframe_id: str, frame_idx: int, pose_data: to...
method add_interval (line 93) | def add_interval(
method _add_interval_label (line 110) | def _add_interval_label(self, start_frame_idx: int, end_frame_idx: int):
method remove_keyframe (line 130) | def remove_keyframe(self, keyframe_id: str, frame_idx: int):
method remove_interval (line 139) | def remove_interval(self, interval_id: str, start_frame_idx: int, end_...
method _get_label_pos (line 149) | def _get_label_pos(self, frame_idx: int):
method _remove_interval_and_update_label (line 157) | def _remove_interval_and_update_label(self, interval_id: str, start_fr...
method get_constraint_info (line 201) | def get_constraint_info(self, device: Optional[str] = None):
method get_frame_idx (line 205) | def get_frame_idx(self):
method clear (line 209) | def clear(self, frame_idx: Optional[int] = None):
function build_constraint_set_table_markdown (line 218) | def build_constraint_set_table_markdown(constraint_list: List[Constraint...
class FullbodyKeyframeSet (line 234) | class FullbodyKeyframeSet(ConstraintSet):
method __init__ (line 235) | def __init__(
method add_keyframe (line 244) | def add_keyframe(
method add_interval (line 310) | def add_interval(
method remove_keyframe (line 339) | def remove_keyframe(self, keyframe_id: str, frame_idx: int):
method _get_label_pos (line 349) | def _get_label_pos(self, frame_idx: int):
method remove_interval (line 352) | def remove_interval(self, interval_id: str, start_frame_idx: int, end_...
method get_constraint_info (line 355) | def get_constraint_info(self, device: Optional[str] = None):
method clear (line 379) | def clear(self, frame_idx: Optional[int] = None):
method set_overlay_visibility (line 399) | def set_overlay_visibility(self, only_frame: Optional[int] = None) -> ...
class EEJointsKeyframeSet (line 411) | class EEJointsKeyframeSet(ConstraintSet):
method __init__ (line 412) | def __init__(
method create_scene_elements (line 424) | def create_scene_elements(
method add_keyframe (line 508) | def add_keyframe(
method add_interval (line 611) | def add_interval(
method remove_keyframe (line 651) | def remove_keyframe(self, keyframe_id: str, frame_idx: int):
method _get_label_pos (line 689) | def _get_label_pos(self, frame_idx: int):
method remove_interval (line 692) | def remove_interval(self, interval_id: str, start_frame_idx: int, end_...
method get_constraint_info (line 695) | def get_constraint_info(self, device: Optional[str] = None):
method clear (line 725) | def clear(self, frame_idx: Optional[int] = None, scene_elements_only: ...
method set_overlay_visibility (line 743) | def set_overlay_visibility(self, only_frame: Optional[int] = None) -> ...
class RootKeyframe2DSet (line 757) | class RootKeyframe2DSet(ConstraintSet):
method __init__ (line 758) | def __init__(
method add_keyframe (line 771) | def add_keyframe(
method add_interval (line 857) | def add_interval(
method set_smooth_path (line 901) | def set_smooth_path(self, smooth_path: bool):
method set_dense_path (line 906) | def set_dense_path(self, dense_path: bool):
method interpolate_path (line 927) | def interpolate_path(self, t: np.ndarray):
method update_line_segments (line 958) | def update_line_segments(self):
method remove_keyframe (line 975) | def remove_keyframe(self, keyframe_id: str, frame_idx: int):
method _get_label_pos (line 987) | def _get_label_pos(self, frame_idx: int):
method remove_interval (line 990) | def remove_interval(self, interval_id: str, start_frame_idx: int, end_...
method _get_sparse_constraint_info (line 996) | def _get_sparse_constraint_info(self):
method get_constraint_info (line 1013) | def get_constraint_info(self, device: Optional[str] = None):
method clear (line 1031) | def clear(self, frame_idx: Optional[int] = None):
method set_overlay_visibility (line 1060) | def set_overlay_visibility(self, only_frame: Optional[int] = None) -> ...
FILE: kimodo/viz/coords.py
function skew (line 8) | def skew(v: np.ndarray) -> np.ndarray:
function rotation_matrix_from_two_vec (line 14) | def rotation_matrix_from_two_vec(v_from: np.ndarray, v_to: np.ndarray, e...
FILE: kimodo/viz/g1_rig.py
function _get_g1_joint_axis_indices (line 66) | def _get_g1_joint_axis_indices() -> dict[str, int]:
function _get_g1_joint_limits (line 104) | def _get_g1_joint_limits() -> dict[str, tuple[float, float]]:
function get_g1_joint_f2q_data (line 163) | def get_g1_joint_f2q_data(
function _load_g1_mesh_data (line 212) | def _load_g1_mesh_data(
function _get_mesh_geometry_impl (line 257) | def _get_mesh_geometry_impl(
function _get_mesh_local_transforms_impl (line 281) | def _get_mesh_local_transforms_impl(
class G1MeshRig (line 335) | class G1MeshRig:
method __init__ (line 346) | def __init__(
method set_visibility (line 395) | def set_visibility(self, visible: bool) -> None:
method set_opacity (line 399) | def set_opacity(self, opacity: float) -> None:
method set_wireframe (line 403) | def set_wireframe(self, wireframe: bool) -> None:
method set_color (line 407) | def set_color(self, color: Tuple[int, int, int]) -> None:
method set_pose (line 412) | def set_pose(self, joints_pos: np.ndarray, joints_rot: np.ndarray) -> ...
method clear (line 427) | def clear(self) -> None:
FILE: kimodo/viz/gui.py
class GuiElements (line 11) | class GuiElements:
FILE: kimodo/viz/playback.py
class CharacterMotion (line 28) | class CharacterMotion:
method __init__ (line 29) | def __init__(
method precompute_mesh_info (line 67) | def precompute_mesh_info(self):
method set_frame (line 75) | def set_frame(self, idx: int):
method update_pose_at_frame (line 103) | def update_pose_at_frame(
method clear (line 172) | def clear(self):
method get_current_projected_root_pos (line 178) | def get_current_projected_root_pos(self) -> np.ndarray:
method get_projected_root_pos (line 184) | def get_projected_root_pos(self, start_frame_idx: int, end_frame_idx: ...
method set_projected_root_pos_path (line 213) | def set_projected_root_pos_path(
method get_joints_pos (line 257) | def get_joints_pos(self, start_frame_idx: int, end_frame_idx: int = No...
method get_joints_rot (line 283) | def get_joints_rot(self, start_frame_idx: int, end_frame_idx: int = No...
method get_current_joints_pos (line 309) | def get_current_joints_pos(self) -> torch.Tensor:
method get_current_joints_rot (line 312) | def get_current_joints_rot(self) -> torch.Tensor:
method add_root_translation_gizmo (line 315) | def add_root_translation_gizmo(
method add_joint_gizmos (line 427) | def add_joint_gizmos(
method clear_all_gizmos (line 706) | def clear_all_gizmos(self):
FILE: kimodo/viz/scene.py
class WaypointMesh (line 32) | class WaypointMesh:
method __init__ (line 33) | def __init__(
method update_position (line 89) | def update_position(self, position: np.ndarray, heading: Optional[np.n...
method clear (line 101) | def clear(self):
method set_visible (line 109) | def set_visible(self, visible: bool) -> None:
class SkeletonMesh (line 118) | class SkeletonMesh:
method __init__ (line 119) | def __init__(
method compute_single_pose (line 215) | def compute_single_pose(self, joints_pos: np.ndarray):
method precompute_mesh_info (line 247) | def precompute_mesh_info(self, joints_pos: torch.Tensor):
method update_mesh_info_cache (line 265) | def update_mesh_info_cache(self, joints_pos: torch.Tensor, frame_idx: ...
method set_pose (line 275) | def set_pose(
method set_visibility (line 308) | def set_visibility(self, visible: bool):
method get_pose (line 312) | def get_pose(self) -> np.ndarray:
method clear (line 315) | def clear(self):
class Character (line 332) | class Character:
method __init__ (line 333) | def __init__(
method change_theme (line 479) | def change_theme(self, is_dark_mode):
method set_skeleton_visibility (line 486) | def set_skeleton_visibility(self, visible: bool):
method set_show_foot_contacts (line 490) | def set_show_foot_contacts(self, show: bool, frame_idx: Optional[int] ...
method set_skinned_mesh_visibility (line 496) | def set_skinned_mesh_visibility(self, visible: bool):
method set_skinned_mesh_opacity (line 502) | def set_skinned_mesh_opacity(self, opacity: float):
method set_skinned_mesh_wireframe (line 508) | def set_skinned_mesh_wireframe(self, wireframe: bool):
method precompute_skinning (line 514) | def precompute_skinning(self, joints_pos: torch.Tensor, joints_rot: to...
method update_skinning_cache (line 536) | def update_skinning_cache(self, joints_pos: torch.Tensor, joints_rot: ...
method set_pose (line 544) | def set_pose(
method get_pose (line 572) | def get_pose(self) -> torch.Tensor:
method clear (line 575) | def clear(self):
FILE: kimodo/viz/smplx_skin.py
class SMPLXSkin (line 66) | class SMPLXSkin:
method __init__ (line 67) | def __init__(
method lbs (line 214) | def lbs(self, posed_transform, bind_vertices=None):
method skin (line 248) | def skin(self, joint_rotmat, joint_pos, rot_is_global=False):
FILE: kimodo/viz/soma_layer_skin.py
class SOMASkin (line 18) | class SOMASkin:
method __init__ (line 19) | def __init__(
method soma_model_pose (line 60) | def soma_model_pose(self, *args, **kwargs):
method skin (line 64) | def skin(self, joint_rotmat, joint_pos, rot_is_global=False):
FILE: kimodo/viz/soma_skin.py
class SOMASkin (line 22) | class SOMASkin:
method __init__ (line 23) | def __init__(self, skeleton):
method lbs (line 59) | def lbs(self, posed_transform):
method skin (line 82) | def skin(self, joint_rotmat, joint_pos, rot_is_global=False):
FILE: kimodo/viz/viser_utils.py
function load_example_cases (line 27) | def load_example_cases(examples_base_dir):
FILE: setup.py
class CMakeExtension (line 14) | class CMakeExtension(Extension):
method __init__ (line 15) | def __init__(self, name, sourcedir=""):
class CMakeBuild (line 20) | class CMakeBuild(build_ext):
method run (line 21) | def run(self):
method build_extension (line 30) | def build_extension(self, ext):
Condensed preview — 320 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,753K chars).
[
{
"path": ".gitignore",
"chars": 2083,
"preview": "# debugging files\ndebug/\nSMPLX_NEUTRAL.npz\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n#"
},
{
"path": ".pre-commit-config.yaml",
"chars": 1285,
"preview": "repos:\n # code formatting\n - repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v0.6.4\n hooks:\n - id:"
},
{
"path": "ATTRIBUTIONS.MD",
"chars": 2754,
"preview": "LLM2Vec MIT License https://github.com/McGill-NLP/llm2vec Copyright (c) 2024 McGill NLP\n\nPermission is hereby granted, f"
},
{
"path": "CHANGELOG.md",
"chars": 4978,
"preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
},
{
"path": "CONTRIBUTING.MD",
"chars": 2298,
"preview": "# How to Contribute\n\n## Code Reviews\n\nAll submissions require review. We use GitHub pull requests for this purpose. Cons"
},
{
"path": "Dockerfile",
"chars": 1950,
"preview": "FROM nvcr.io/nvidia/pytorch:24.10-py3\n\n# Avoid some interactive prompts + make pip quieter/reproducible-ish\nENV DEBIAN_F"
},
{
"path": "LICENSE",
"chars": 11387,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "MANIFEST.in",
"chars": 240,
"preview": "include setup.py\nrecursive-include kimodo/assets *\nrecursive-include MotionCorrection/src *.cpp *.h *.inl\nrecursive-incl"
},
{
"path": "MotionCorrection/.gitignore",
"chars": 857,
"preview": "# Python\r\n__pycache__/\r\n*.py[cod]\r\n*$py.class\r\n*.so\r\n*.egg\r\n*.egg-info/\r\ndist/\r\nbuild/\r\n*.whl\r\n.Python\r\ndevelop-eggs/\r\n."
},
{
"path": "MotionCorrection/CMakeLists.txt",
"chars": 3001,
"preview": "cmake_minimum_required(VERSION 3.15)\nproject(motion_correction)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUI"
},
{
"path": "MotionCorrection/MANIFEST.in",
"chars": 121,
"preview": "include CMakeLists.txt\ninclude test_example.py\nrecursive-include src *.cpp *.h *.inl\nrecursive-include python *.py *.dll"
},
{
"path": "MotionCorrection/README.md",
"chars": 884,
"preview": "# motion_correction\r\n\r\nStandalone `correct_motion` implementation packaged as a small C++ motion trajectory correction l"
},
{
"path": "MotionCorrection/python/motion_correction/__init__.py",
"chars": 34,
"preview": "from ._motion_correction import *\n"
},
{
"path": "MotionCorrection/python/motion_correction/motion_postprocess.py",
"chars": 4014,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "MotionCorrection/run_test.py",
"chars": 2779,
"preview": "#!/usr/bin/env python3\n\n# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserve"
},
{
"path": "MotionCorrection/setup.py",
"chars": 4486,
"preview": "#!/usr/bin/env python3\n\n# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserve"
},
{
"path": "MotionCorrection/src/cpp/AnimProcessing/InverseKinematics.cpp",
"chars": 6884,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/AnimProcessing/InverseKinematics.h",
"chars": 790,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/AnimProcessing/TrajectoryCorrector.cpp",
"chars": 14881,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/AnimProcessing/TrajectoryCorrector.h",
"chars": 1683,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/AnimProcessing/Utility.cpp",
"chars": 46388,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/AnimProcessing/Utility.h",
"chars": 1489,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/BindingsPython.cpp",
"chars": 13676,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Compiler.h",
"chars": 712,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Debug.h",
"chars": 390,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Constants.h",
"chars": 1181,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Matrix.cpp",
"chars": 9971,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Matrix.h",
"chars": 5306,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Matrix.inl",
"chars": 26947,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Quaternion.cpp",
"chars": 642,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Quaternion.h",
"chars": 5522,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Quaternion.inl",
"chars": 18924,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/SIMD.h",
"chars": 4986,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Scalar.h",
"chars": 5939,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Transform.cpp",
"chars": 464,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Transform.h",
"chars": 7849,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Transform.inl",
"chars": 16618,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Types.cpp",
"chars": 1710,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Types.h",
"chars": 36144,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Vector.cpp",
"chars": 4173,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Vector.h",
"chars": 15419,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Math/Vector.inl",
"chars": 74225,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "MotionCorrection/src/cpp/Platform.h",
"chars": 1363,
"preview": "/*\n * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n * SPDX-License-I"
},
{
"path": "README.md",
"chars": 19702,
"preview": "<p align=\"center\">\n <img src=\"./assets/banner.png\" alt=\"Banner\" width=\"100%\">\n <a href=\"LICENSE\"><img src=\"https://img"
},
{
"path": "benchmark/create_benchmark.py",
"chars": 6539,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "benchmark/embed_folder.py",
"chars": 5576,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "benchmark/evaluate_folder.py",
"chars": 13599,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "benchmark/generate_eval.py",
"chars": 13825,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "benchmark/parse_folder.py",
"chars": 26850,
"preview": "#!/usr/bin/env python3\n# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved"
},
{
"path": "docker-compose.yaml",
"chars": 2723,
"preview": "services:\n text-encoder:\n build:\n context: .\n dockerfile: Dockerfile\n image: kimodo:1.0\n container_n"
},
{
"path": "docker_requirements.in",
"chars": 1084,
"preview": "#\n# Human-maintained direct dependencies (top-level).\n# Use `uv` to compile this into a fully pinned `requirements.txt` "
},
{
"path": "docker_requirements.txt",
"chars": 6865,
"preview": "# This file was autogenerated by uv via the following command:\n# NOTE: `torch` (and its CUDA wheels) are intentionally o"
},
{
"path": "docs/.gitattributes",
"chars": 66,
"preview": "source/_static/quick_tour.mp4 filter=lfs diff=lfs merge=lfs -text\n"
},
{
"path": "docs/Makefile",
"chars": 541,
"preview": "# Minimal makefile for Sphinx documentation\n#\n\nSPHINXOPTS ?=\nSPHINXBUILD ?= sphinx-build\nSOURCEDIR = source\nBUI"
},
{
"path": "docs/README.md",
"chars": 496,
"preview": "# Documentation\n\n## Local build\n\nInstall doc dependencies:\n\n```bash\npip install -r docs/requirements.txt\n```\n\nBuild HTML"
},
{
"path": "docs/make.bat",
"chars": 276,
"preview": "@ECHO OFF\n\npushd %~dp0\n\nset SPHINXOPTS=\nset SPHINXBUILD=sphinx-build\nset SOURCEDIR=source\nset BUILDDIR=build\n\nif \"%1\" =="
},
{
"path": "docs/requirements.txt",
"chars": 81,
"preview": "sphinx>=7.0,<9.0\nnvidia-sphinx-theme\nsphinx-copybutton\nmyst-parser\nsphinx-design\n"
},
{
"path": "docs/source/_static/custom.css",
"chars": 1265,
"preview": ".hero {\n padding: 2.5rem 2rem;\n border-radius: 12px;\n background: linear-gradient(135deg, #0f1a0c 0%, #1c2b16 55%, #7"
},
{
"path": "docs/source/_templates/apidoc/module.rst.jinja",
"chars": 447,
"preview": "{%- if show_headings %}\n{{- [basename, \"module\"] | join(' ') | e | heading }}\n\n{% endif -%}\n.. automodule:: {{ qualname "
},
{
"path": "docs/source/_templates/apidoc/package.rst.jinja",
"chars": 1414,
"preview": "{%- set preferred_order = ['members', 'undoc-members', 'show-inheritance'] %}\n{%- macro automodule(modname, options) -%}"
},
{
"path": "docs/source/api_reference/_generated/kimodo.demo.rst",
"chars": 1220,
"preview": "kimodo.demo package\n===================\n\nSubmodules\n----------\n\nkimodo.demo.app module\n----------------------\n\n.. automo"
},
{
"path": "docs/source/api_reference/_generated/kimodo.exports.rst",
"chars": 1165,
"preview": "kimodo.exports package\n======================\n\nSubmodules\n----------\n\nkimodo.exports.bvh module\n------------------------"
},
{
"path": "docs/source/api_reference/_generated/kimodo.metrics.rst",
"chars": 810,
"preview": "kimodo.metrics package\n======================\n\nSubmodules\n----------\n\nkimodo.metrics.base module\n-----------------------"
},
{
"path": "docs/source/api_reference/_generated/kimodo.model.llm2vec.models.rst",
"chars": 869,
"preview": "kimodo.model.llm2vec.models package\n===================================\n\nSubmodules\n----------\n\nkimodo.model.llm2vec.mod"
},
{
"path": "docs/source/api_reference/_generated/kimodo.model.llm2vec.rst",
"chars": 665,
"preview": "kimodo.model.llm2vec package\n============================\n\nSubpackages\n-----------\n\n.. toctree::\n :maxdepth: 4\n\n kim"
},
{
"path": "docs/source/api_reference/_generated/kimodo.model.rst",
"chars": 1977,
"preview": "kimodo.model package\n====================\n\nSubpackages\n-----------\n\n.. toctree::\n :maxdepth: 4\n\n kimodo.model.llm2ve"
},
{
"path": "docs/source/api_reference/_generated/kimodo.motion_rep.reps.rst",
"chars": 797,
"preview": "kimodo.motion\\_rep.reps package\n===============================\n\nSubmodules\n----------\n\nkimodo.motion\\_rep.reps.base mod"
},
{
"path": "docs/source/api_reference/_generated/kimodo.motion_rep.rst",
"chars": 1145,
"preview": "kimodo.motion\\_rep package\n==========================\n\nSubpackages\n-----------\n\n.. toctree::\n :maxdepth: 4\n\n kimodo."
},
{
"path": "docs/source/api_reference/_generated/kimodo.rst",
"chars": 1288,
"preview": "kimodo package\n==============\n\nSubpackages\n-----------\n\n.. toctree::\n :maxdepth: 4\n\n kimodo.demo\n kimodo.exports\n "
},
{
"path": "docs/source/api_reference/_generated/kimodo.scripts.rst",
"chars": 1261,
"preview": "kimodo.scripts package\n======================\n\nSubmodules\n----------\n\nkimodo.scripts.generate module\n-------------------"
},
{
"path": "docs/source/api_reference/_generated/kimodo.skeleton.rst",
"chars": 1151,
"preview": "kimodo.skeleton package\n=======================\n\nSubmodules\n----------\n\nkimodo.skeleton.base module\n--------------------"
},
{
"path": "docs/source/api_reference/_generated/kimodo.viz.rst",
"chars": 1668,
"preview": "kimodo.viz package\n==================\n\nSubmodules\n----------\n\nkimodo.viz.constraint\\_ui module\n-------------------------"
},
{
"path": "docs/source/api_reference/_generated/modules.rst",
"chars": 55,
"preview": "kimodo\n======\n\n.. toctree::\n :maxdepth: 4\n\n kimodo\n"
},
{
"path": "docs/source/api_reference/constraints.rst",
"chars": 153,
"preview": "Constraints\n===========\n\nConstraint definitions and utilities.\n\n.. automodule:: kimodo.constraints\n :members:\n :undo"
},
{
"path": "docs/source/api_reference/exports.rst",
"chars": 329,
"preview": "Exports\n=======\n\nExport utilities for common formats.\n\n.. automodule:: kimodo.exports.bvh\n :members:\n :undoc-members"
},
{
"path": "docs/source/api_reference/index.rst",
"chars": 251,
"preview": "API Reference\n=============\n\nThis section contains the API documentation for Kimodo, organized by domain.\n\n.. toctree::\n"
},
{
"path": "docs/source/api_reference/model.rst",
"chars": 757,
"preview": "Model\n=====\n\nCore model architecture, diffusion logic, and text encoders.\n\n\nKimodo Model\n------------\n\n.. automodule:: k"
},
{
"path": "docs/source/api_reference/motion_rep.rst",
"chars": 1020,
"preview": "Motion Representation\n=====================\n\nMotion representation utilities and kinematics helpers.\n\nSkeleton\n--------\n"
},
{
"path": "docs/source/api_reference/post-processing.rst",
"chars": 140,
"preview": "Post-Processing Bindings\n========================\n\n.. automodule:: kimodo.postprocess\n :members:\n :undoc-members:\n "
},
{
"path": "docs/source/api_reference/utilities.rst",
"chars": 323,
"preview": "Utilities\n=========\n\nGeneral utilities used across the codebase.\n\n.. automodule:: kimodo.tools\n :members:\n :undoc-me"
},
{
"path": "docs/source/api_reference/viz.rst",
"chars": 363,
"preview": "Visualization\n=============\n\nVisualization helpers for rendering skeletons and meshes.\n\n.. automodule:: kimodo.viz.g1_ri"
},
{
"path": "docs/source/benchmark/introduction.md",
"chars": 9300,
"preview": "# Benchmark Introduction\n\nWe provide a benchmark to evaluate text-to-motion and constrained motion generation on a share"
},
{
"path": "docs/source/benchmark/metrics.md",
"chars": 13494,
"preview": "# Metrics\n\nThe benchmark evaluates generated motion along three axes:\n\n- **Motion quality** -- foot-skate and contact-co"
},
{
"path": "docs/source/benchmark/pipeline.md",
"chars": 12090,
"preview": "# Evaluation Pipeline\n\nThis page describes the full benchmark workflow, which uses scripts in the `benchmark` directory:"
},
{
"path": "docs/source/benchmark/results.md",
"chars": 8751,
"preview": "# Kimodo Results\n\nOn this page, we report the results for the latest Kimodo models on the benchmark test suite. These re"
},
{
"path": "docs/source/conf.py",
"chars": 4603,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "docs/source/getting_started/installation.md",
"chars": 3080,
"preview": "# Installation\n\n> Note: This project will download and install additional third-party open source software projects. Rev"
},
{
"path": "docs/source/getting_started/installation_docker.md",
"chars": 2199,
"preview": "# Installation With Docker\n\n> Note: the first time building and running with Docker can take several minutes, please be "
},
{
"path": "docs/source/getting_started/installation_smpl.md",
"chars": 1266,
"preview": "# Using Kimodo-SMPLX Model\n\nUsing the [Kimodo-SMPLX-RP-v1](https://huggingface.co/nvidia/Kimodo-SMPLX-RP-v1) model requi"
},
{
"path": "docs/source/getting_started/installation_virtual_env.md",
"chars": 1738,
"preview": "# Installation With Virtual Environment\n\n> Note: the repo was tested with Python 3.10+ and PyTorch 2.0+.\n\n## Create Envi"
},
{
"path": "docs/source/getting_started/quick_start.md",
"chars": 7483,
"preview": "# Quick Start\n\nThis page provides a quick introduction to motion generation with Kimodo. For detailed explanations, we r"
},
{
"path": "docs/source/index.md",
"chars": 2571,
"preview": "# Kimodo Documentation\n\n<div class=\"hero\">\n <div class=\"hero-title\">Kimodo</div>\n <div class=\"hero-subtitle\">\n Scal"
},
{
"path": "docs/source/interactive_demo/constraints.md",
"chars": 1632,
"preview": "# Constraints\n\nConstraints guide the motion at specific frames or intervals. To learn about the types of constraints det"
},
{
"path": "docs/source/interactive_demo/examples.md",
"chars": 1246,
"preview": "# Examples\n\nThe Examples Tab within the settings panel contains several examples that highlight the key capabilities and"
},
{
"path": "docs/source/interactive_demo/export_results.md",
"chars": 1447,
"preview": "# Saving/Loading\n\nThe Load/Save and Exports panels allow saving generated results and load in previously generated resul"
},
{
"path": "docs/source/interactive_demo/generation.md",
"chars": 1206,
"preview": "# Generation\n\nThe most important panel is the \"Generate\" which allows you to call Kimodo to generate one or more motions"
},
{
"path": "docs/source/interactive_demo/index.md",
"chars": 1947,
"preview": "# Interactive Demo\n\nThe web-based interactive demo provides an intuitive interface for generating motions with any of th"
},
{
"path": "docs/source/interactive_demo/launching.md",
"chars": 2412,
"preview": "# Running the Demo\n\nAfter following the installation [instructions](../getting_started/installation.md), the demo can be"
},
{
"path": "docs/source/interactive_demo/model_selection.md",
"chars": 600,
"preview": "# Model Selection\n\nModel selection allows choosing between the Kimodo models detailed in the [quick start guide](../gett"
},
{
"path": "docs/source/interactive_demo/ui_overview.md",
"chars": 2143,
"preview": "# UI Overview\n\nThis page gives an overview of each of the main elements of the demo UI and how to use them.\n\n is a publicly"
},
{
"path": "kimodo/__init__.py",
"chars": 357,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/01_single_text_prompt/meta.json",
"chars": 255,
"preview": "{\n \"text\": \"A person walking forward quickly stumbles but maintains their balance\",\n \"duration\": 5.0,\n \"num_samples\":"
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/02_multi_text_ee_constraint/constraints.json",
"chars": 17038,
"preview": "[\n {\n \"type\": \"left-hand\",\n \"frame_indices\": [\n 40,\n 155\n ],\n \"local_joints_rot\": [\n [\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/02_multi_text_ee_constraint/meta.json",
"chars": 336,
"preview": "{\n \"texts\": [\n \"A person walks forward while carrying a box\",\n \"A person sets a box down onto the ground\"\n ],\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/03_full_body_keyframes/constraints.json",
"chars": 12702,
"preview": "[\n {\n \"type\": \"fullbody\",\n \"frame_indices\": [\n 59,\n 106,\n 148\n ],\n \"local_joints_rot\": [\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/03_full_body_keyframes/meta.json",
"chars": 244,
"preview": "{\n \"text\": \"A person walking forward picks up something off the ground\",\n \"duration\": 5.0,\n \"num_samples\": 1,\n \"seed"
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/04_ee_constraint/constraints.json",
"chars": 29831,
"preview": "[\n {\n \"type\": \"right-hand\",\n \"frame_indices\": [\n 129,\n 93,\n 0\n ],\n \"local_joints_rot\": [\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/04_ee_constraint/meta.json",
"chars": 273,
"preview": "{\n \"text\": \"A person walks diagonally to the left and waves at someone on their right\",\n \"duration\": 4.966666666666667"
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/05_root_path/constraints.json",
"chars": 15065,
"preview": "[\n {\n \"type\": \"root2d\",\n \"frame_indices\": [\n 0,\n 1,\n 2,\n 3,\n 4,\n 5,\n 6,\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/05_root_path/meta.json",
"chars": 292,
"preview": "{\n \"text\": \"Initially standing still and calm, the person then starts jogging in a counterclockwise arc.\",\n \"duration\""
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/06_root_waypoints/constraints.json",
"chars": 426,
"preview": "[\n {\n \"type\": \"root2d\",\n \"frame_indices\": [\n 0,\n 87,\n 169,\n 240\n ],\n \"smooth_root_2d\": "
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/06_root_waypoints/meta.json",
"chars": 268,
"preview": "{\n \"text\": \"A person is walking while carrying a small object in their left hand\",\n \"duration\": 8.033333333333333,\n \""
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/07_text_terrain/meta.json",
"chars": 223,
"preview": "{\n \"text\": \"A person begins walking up the stairs\",\n \"duration\": 3.5,\n \"num_samples\": 1,\n \"seed\": 44,\n \"diffusion_s"
},
{
"path": "kimodo/assets/demo/examples/kimodo-g1-rp/08_text_object/meta.json",
"chars": 277,
"preview": "{\n \"text\": \"A person picks up an object from low on their left side and places it up high\",\n \"duration\": 5.03333333333"
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/01_single_text_prompt/meta.json",
"chars": 257,
"preview": "{\n \"text\": \"A person runs forward and then leaps over an obstacle in front of them.\",\n \"duration\": 5.0,\n \"num_samples"
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/02_multi_text_prompt/meta.json",
"chars": 352,
"preview": "{\n \"texts\": [\n \"A person is walking forward casually.\",\n \"A person turns to the right and starts sneakily moving "
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/03_full_body_keyframes/constraints.json",
"chars": 7456,
"preview": "[\n {\n \"type\": \"fullbody\",\n \"frame_indices\": [\n 79,\n 134\n ],\n \"local_joints_rot\": [\n [\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/03_full_body_keyframes/meta.json",
"chars": 247,
"preview": "{\n \"text\": \"A person walks forward and picks something up from the ground\",\n \"duration\": 5.0,\n \"num_samples\": 1,\n \"s"
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/04_ee_constraint/constraints.json",
"chars": 29877,
"preview": "[\n {\n \"type\": \"right-foot\",\n \"frame_indices\": [\n 28,\n 94\n ],\n \"local_joints_rot\": [\n [\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/04_ee_constraint/meta.json",
"chars": 290,
"preview": "{\n \"text\": \"A person picks up an object in front of them with two hands and places it to the left side\",\n \"duration\": "
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/05_root_path/constraints.json",
"chars": 24807,
"preview": "[\n {\n \"type\": \"root2d\",\n \"frame_indices\": [\n 0,\n 1,\n 2,\n 3,\n 4,\n 5,\n 6,\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/05_root_path/meta.json",
"chars": 230,
"preview": "{\n \"text\": \"A person is casually walking forward slowly\",\n \"duration\": 10.0,\n \"num_samples\": 1,\n \"seed\": 42,\n \"diff"
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/06_root_waypoints/constraints.json",
"chars": 326,
"preview": "[\n {\n \"type\": \"root2d\",\n \"frame_indices\": [\n 0,\n 90,\n 180\n ],\n \"smooth_root_2d\": [\n [\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/06_root_waypoints/meta.json",
"chars": 253,
"preview": "{\n \"text\": \"A person is doing a hip hop dance while moving around\",\n \"duration\": 6.033333333333333,\n \"num_samples\": 1"
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/07_mixed_constraints/constraints.json",
"chars": 16785,
"preview": "[\n {\n \"type\": \"fullbody\",\n \"frame_indices\": [\n 108\n ],\n \"local_joints_rot\": [\n [\n [\n "
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/07_mixed_constraints/meta.json",
"chars": 272,
"preview": "{\n \"text\": \"A person walking backward points to the right side with their right hand\",\n \"duration\": 5.066666666666666,"
},
{
"path": "kimodo/assets/demo/examples/kimodo-soma-rp/08_stylized_text/meta.json",
"chars": 287,
"preview": "{\n \"text\": \"A zombie with their left arm extended forward walks with an uneven gait at a slow pace.\",\n \"duration\": 4.0"
},
{
"path": "kimodo/assets/skeletons/g1skel34/xml/g1.xml",
"chars": 31881,
"preview": "<mujoco model=\"g1\">\n <compiler angle=\"radian\" meshdir=\"../meshes/g1\"/>\n\n <default>\n <default class=\"g1\">\n "
},
{
"path": "kimodo/assets/skeletons/somaskel77/somaskel77_standard_tpose.bvh",
"chars": 15702,
"preview": "HIERARCHY\nROOT Root\n{\n OFFSET 0.0 0.0 0.0\n CHANNELS 6 Xposition Yposition Zposition Zrotation Yrotation Xrotation\n JO"
},
{
"path": "kimodo/assets.py",
"chars": 603,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/constraints.py",
"chars": 25446,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/demo/__init__.py",
"chars": 763,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/demo/__main__.py",
"chars": 253,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/demo/app.py",
"chars": 27300,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/demo/config.py",
"chars": 5428,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/demo/embedding_cache.py",
"chars": 8884,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/demo/generation.py",
"chars": 8516,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/demo/queue_manager.py",
"chars": 12512,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/demo/state.py",
"chars": 1995,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/demo/ui.py",
"chars": 148376,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/exports/__init__.py",
"chars": 1905,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/exports/bvh.py",
"chars": 11235,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/exports/motion_convert_lib.py",
"chars": 6369,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/exports/motion_formats.py",
"chars": 2820,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/exports/motion_io.py",
"chars": 17798,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/exports/mujoco.py",
"chars": 27304,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/exports/smplx.py",
"chars": 9716,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/geometry.py",
"chars": 6948,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/meta.py",
"chars": 2882,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/metrics/__init__.py",
"chars": 991,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/metrics/base.py",
"chars": 2187,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/metrics/constraints.py",
"chars": 3364,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/metrics/foot_skate.py",
"chars": 8546,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/metrics/tmr.py",
"chars": 20081,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/__init__.py",
"chars": 831,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/backbone.py",
"chars": 10933,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/cfg.py",
"chars": 6025,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/common.py",
"chars": 1765,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/diffusion.py",
"chars": 5541,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/kimodo_model.py",
"chars": 25540,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/llm2vec/README.md",
"chars": 207,
"preview": "This is a patched version of the original [LLM2Vec](https://github.com/McGill-NLP/llm2vec) codebase so that `McGill-NLP/"
},
{
"path": "kimodo/model/llm2vec/__init__.py",
"chars": 314,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/llm2vec/llm2vec.py",
"chars": 19654,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2024 McGill NLP\n# SPDX-License-Identifier: MIT\n#\n# Permission is hereby granted,"
},
{
"path": "kimodo/model/llm2vec/llm2vec_wrapper.py",
"chars": 3286,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/llm2vec/models/__init__.py",
"chars": 262,
"preview": "# from .bidirectional_gemma import GemmaBiForMNTP, GemmaBiModel\n# from .bidirectional_llama import LlamaBiForMNTP, Llama"
},
{
"path": "kimodo/model/llm2vec/models/attn_mask_utils.py",
"chars": 8760,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2024 McGill NLP\n# SPDX-License-Identifier: MIT\n#\n# Permission is hereby granted,"
},
{
"path": "kimodo/model/llm2vec/models/bidirectional_llama.py",
"chars": 9515,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2024 McGill NLP\n# SPDX-License-Identifier: MIT\n#\n# Permission is hereby granted,"
},
{
"path": "kimodo/model/llm2vec/models/utils.py",
"chars": 1490,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2024 McGill NLP\n# SPDX-License-Identifier: MIT\n#\n# Permission is hereby granted,"
},
{
"path": "kimodo/model/load_model.py",
"chars": 8486,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/loading.py",
"chars": 2463,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/registry.py",
"chars": 17953,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/text_encoder_api.py",
"chars": 2199,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/tmr.py",
"chars": 12508,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/model/twostage_denoiser.py",
"chars": 5643,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/__init__.py",
"chars": 319,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/conditioning.py",
"chars": 1106,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/feature_utils.py",
"chars": 7910,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/feet.py",
"chars": 2052,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/reps/__init__.py",
"chars": 403,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/reps/base.py",
"chars": 12133,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/reps/kimodo_motionrep.py",
"chars": 13184,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/reps/tmr_motionrep.py",
"chars": 8903,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/smooth_root.py",
"chars": 7917,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/motion_rep/stats.py",
"chars": 4540,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/postprocess.py",
"chars": 15093,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/sanitize.py",
"chars": 2733,
"preview": "# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n# SPDX-License-Identi"
},
{
"path": "kimodo/scripts/__init__.py",
"chars": 0,
"preview": ""
}
]
// ... and 120 more files (download for full content)
About this extraction
This page contains the full source code of the nv-tlabs/kimodo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 320 files (1.6 MB), approximately 431.0k tokens, and a symbol index with 874 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.