Conversation
mesh2Prim divides lengths by 1000, so an exported file holds metres, but the stage never recorded that. USD then falls back to its default of centimetres and the geometry loads 100 times too small in every viewer. Declare metersPerUnit, and the z up axis that Geant4 uses, which was likewise left at the USD default of y. Meshes were written without a subdivision scheme. USD therefore treats each solid as the control cage of a smooth surface, rounding off its edges and pulling the surface inside the volume the solid describes. Set subdivisionScheme to none. Materials were defined at /Materials, beside the geometry root rather than below it, leaving the stage with two root prims. Move them under the geometry root and record that root as the default prim, so viewers know what to place. A ".usdz" suffix now writes a usdz package rather than a plain layer. usdz holds the layer and any textures in one file and is what viewers on phones and tablets read. Also apply MaterialBindingAPI before binding, which USD warns about otherwise, and remove two debug prints and a reshape whose result was discarded. Assisted-by: Generative AI
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #312 +/- ##
==========================================
+ Coverage 74.32% 74.73% +0.41%
==========================================
Files 157 157
Lines 22957 23001 +44
==========================================
+ Hits 17062 17190 +128
+ Misses 5895 5811 -84 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
gipert
marked this pull request as draft
September 13, 2026 14:41
gipert
force-pushed
the
usd-export-fixes
branch
from
September 13, 2026 15:51
0a35ca8 to
e64add7
Compare
A geometry written volume by volume gives a viewer one mesh and one material per volume. Viewers on phones and tablets compile a shader for every material they are handed, so a geometry of a few thousand volumes takes minutes to appear, or never does, even though the triangle count is one a phone draws easily. UsdViewer(mergeByMaterial=True) combines the volumes into one mesh per material when the file is saved. The meshes are read back from the stage, so placements are already resolved and the merged points are in world coordinates, instancing included. Volumes are grouped by the values their shaders carry rather than by material name: a material is defined per volume here, so grouping by name would merge nothing. The hierarchy, the volume names and the placements do not survive, so this is for viewing rather than for exchanging a geometry. The tests cover the stage metadata and the subdivision scheme, the usdz package, and that merging leaves fewer meshes holding the same faces in the same place. They need usd-core, so the test extra now pulls in the usd one, which the test workflow installs. Without that they would skip everywhere in CI. Assisted-by: Generative AI
gipert
force-pushed
the
usd-export-fixes
branch
from
September 13, 2026 15:57
e64add7 to
8580111
Compare
gipert
marked this pull request as ready for review
September 13, 2026 16:43
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Parts of this pull request were drafted with AI assistance.
What this fixes
mesh2Primdivides lengths by 1000, so an exported file holds metres, but the stage never recorded that. USD falls back to its default of centimetres, so every geometry pyg4ometry has exported to USD loads 100 times too small.metersPerUnitis now declared, along with the z up axis Geant4 uses, which was likewise left at the USD default of y.Meshes were written without a subdivision scheme, so USD treats each solid as the control cage of a smooth surface. Edges get rounded off and the surface is pulled inside the volume the solid describes.
subdivisionSchemeis now set tonone.Materials were defined at
/Materials, beside the geometry root rather than below it, leaving the stage with two root prims. They now go under the geometry root, and that root is recorded as the default prim so viewers know what to place.MaterialBindingAPIis applied before binding. Without it USD warns on every load that bindings were found on a prim that does not have the schema applied.What this adds
A
.usdzsuffix now writes a usdz package rather than a plain layer:usdz holds the layer and any textures in one file and is the format viewers on phones and tablets read, so this is what you need to show a geometry in augmented reality. Note that Apple's AR Quick Look assumes y is up and will lay a z up geometry on its side; the docs say so.
Behaviour change
Files written by this version are no longer the same size as before in viewers that honour
metersPerUnit. This is the point of the change: they are now the size the geometry says they are, where previously they were 100 times too small. Anything downstream that compensated for the old behaviour by scaling up will need that compensation removed.How it was tested
By exporting a box with a cylinder inside it and reading the file back:
metersPerUnitis 1,upAxisis Z, there is a single root prim with the default prim set, every mesh hassubdivisionScheme = noneand a bound material, a 100 mm cylinder reads back as 0.1, and the usdz package contains one uncompressed, 64 byte aligned entry with the intermediate layer cleaned up. The repository's pre-commit hooks pass.Not tested: the existing test suite has no USD coverage, and I have not added any, so this rests on the manual check above. The change has not been tried against a large real geometry through this code path, nor in
usdviewor Blender.Left alone
scaleFactor = 0.9999, applied cumulatively at each level of the hierarchy to avoid z-fighting, shrinks geometry progressively with nesting depth. That sits awkwardly with a file that now claims accurate units, but changing it alters output for existing users, so it seemed worth raising separately.Two further gaps, larger than this change: no normals are authored, so hard edges shade as though smooth, and deep hierarchies produce one mesh prim and one material per placement. The second matters for real time viewers, where the prim and material count, rather than the triangle count, is what stalls them.
Happy to split this into separate commits for the fixes and the usdz addition if you would prefer that.