Add USD to Simularium converter#206
Conversation
Reads .usd/.usda/.usdc files and converts them to .simularium format with OBJ mesh geometry output. Supports animated transforms (position and rotation), mesh deduplication via geometry hashing, material color extraction, and centering/scaling. Key details: - Rotations are converted from USD degrees to radians for the viewer - OBJ meshes are normalized to unit sphere so viewer radius scaling works - Mesh deduplication avoids writing redundant OBJ files - Optional dependency: pip install simulariumio[usd]
Decompose(Z, Y, X) produced intrinsic ZYX angles which, when passed to
the viewer's THREE.js Euler('XYZ'), generated incorrect rotations (up to
1.24 quaternion error). Switched to Decompose(X, Y, Z) which uses the
same intrinsic XYZ convention as the viewer, eliminating barrel-roll
artifacts on animated meshes.
Also wrap Usd.Stage.Open in try/except for a clearer error on bad paths,
remove stale comments and unused imports from iteration.
…prove error handling Remove class-level type annotations not used by other converters, unused Tuple/MetaData/UnitData imports, redundant rotation comment, and replace verbose/inaccurate convention comments with concise versions. Wrap Usd.Stage.Open in try/except for a clearer error on invalid file paths.
interim17
left a comment
There was a problem hiding this comment.
Overall this is looking great! Thank you for your efforts.
A couple questions.
-
At first pass running with this, the USDascii test file converted into a simularium file with 340 time steps, and my conversion of USDbinary test data resulted in a single frame (looked like the last frame of the USDascii trajectory). Would you expect them to be the same? Possible user error on my end?
-
For CI would be good to add
usdto the array on line 26 of Justfile
|
There was a problem hiding this comment.
Thanks for writing all these tests! Would it be possible to add a test where trim_to_animation=True? That's one of the paths through your code that I'm not sure how to test locally, since I've never actually generated a usd file myself 😅
There was a problem hiding this comment.
Good thinking, I added two tests under TestUsdTrimToAnimation. The ascii fixture declares an end time code of 400 but the last keyed frame across all agents/ops is 340, so the tests verify that trim_to_animation=True produces 340 frames (vs. 400 untrimmed) and that the kept frames contain identical positions/rotations to the untrimmed run (i.e. we're only dropping the held tail, not altering animation data).
ascibisz
left a comment
There was a problem hiding this comment.
Everything looks good to me! I was able to convert the test files to simularium file format using your converter without issue and the output files looked and behaved as I expected, nicely done
Time estimate or Size
Small: ~1 hour to review. New self-contained module with no changes to existing code paths.
Problem
There is no way to convert USD (Universal Scene Description) files into the .simularium format. USD is a widely used interchange format exported by tools like Blender, Maya, and Houdini, and is a natural input for biological simulation visualization workflows.
Solution
Added a UsdConverter and UsdData class following the same patterns as existing converters (e.g. CellPackConverter). The converter:
Opens a USD stage and discovers all mesh geometry prims
Deduplicates meshes by geometry hash and normalizes them relative to their local origin (preserving pivot points set in DCC tools)
Extracts per-frame local transforms using Gf.Transform, decomposing rotation into intrinsic XYZ Euler angles compatible with the THREE.js viewer
Applies np.unwrap per-axis to remove Euler discontinuities
Supports optional animation trimming (trim_to_animation=True by default) to crop to the actual animated frame range
Supports display data overrides by name
Writes mesh geometry as .obj files alongside the .simularium output
Type of change
New feature (non-breaking change which adds functionality)
This change requires updated or new tests
Change summary:
Add USD converter for importing Universal Scene Description files
Fix USD rotation convention to match THREE.js Euler('XYZ') intrinsic order
Clean up USD converter: remove stale comments, unused imports, and improve error handling
Steps to Verify:
Install with USD support: pip install ".[usd]"
Run the test suite: pytest simulariumio/tests/converters/test_usd_converter.py
Convert a USD file manually:
from simulariumio.usd import UsdConverter, UsdData
converter = UsdConverter(UsdData(usd_file_path="my_file.usd"))
converter.save("output")
Open output.simularium in the Simularium viewer at simularium.allencell.org
Verify agents appear with correct positions, rotations, and mesh shapes across frames
Keyfiles:
simulariumio/usd/usd_converter.py -> main converter logic
simulariumio/usd/usd_data.py -> input data container
simulariumio/tests/converters/test_usd_converter.py -> test suite