How a piece is laid out in the file, the ground and physics scene, OpenUSD compliance, and what the Primvaria contract writes on every piece.
OpenUSD layout
Z up, metres, kilograms. /World is the default prim.
/World
/Looks/<piece> UsdPreviewSurface + UsdUVTexture (textures/<piece>.png)
/Cloths/<piece> UsdGeom.Mesh, flat on the ground, laid out in rows
/PhysicsScene gravity (shared, see below)
/Ground the shared ground, its top face at z = 0 (CollisionAPI)
/GroundMaterial its physics material
Ground and physics scene (the same in every Primvaria project)
Every file with physics carries the same two prims, so that assets from different generators can share one scene and every engine gets the same floor:
| Prim | What it is |
|---|---|
/World/PhysicsScene |
gravity 9.81 m/s² along −Z |
/World/Ground |
a static box (UsdGeom.Cube, CollisionAPI), its top face at z = 0, 2 cm thick, covering the content with 0.5 m to spare on each side (1 m × 1 m at least), grey and rendered, no PhysX attributes (engines derive their contact offsets) |
/World/GroundMaterial |
its physics material: static friction 0.6, dynamic friction 0.5, restitution 0.1, a wooden or concrete floor |
The code is one file, ground.py, identical in Granulaire, Maillage, Filaire
and Quincaillerie; a test checks every generated file against it. The MuJoCo
checks and the Blender rigid-body checks take the ground's friction from the
file (Blender's cloth, in Maillage, has its own collision settings).
Each cloth mesh has subdivisionScheme = none, is double sided, and carries:
| Property | Content |
|---|---|
primvars:st |
texture coordinates (vertex) |
primvars:hem |
1 on the hemmed band along the edges, 0 elsewhere (vertex) |
primvars:pin |
1 on pinned vertices: the hoist corners of a flag (vertex) |
primvars:displayColor |
mean colour of the texture |
maillage:fabric, maillage:pattern, maillage:shape |
what the piece is |
maillage:arealDensity, maillage:mass, maillage:thickness, maillage:friction |
physical properties (SI units) |
maillage:nominalSize, maillage:size, maillage:cornerRadius |
retail and actual size (m) |
maillage:hemBendingFactor |
how much stiffer the hem is in bending |
maillage:tensileStiffness, maillage:bendingRigidity, maillage:poissonsRatio |
engine-neutral stiffness: N/m, N·m (see Engines) |
maillage:blender:* |
stiffness for Blender's cloth solver, for 1 cm edges (see Blender values) |
OpenUSD has no standard schema for cloth simulation (UsdPhysics covers
rigid bodies and joints), so these properties are custom attributes. Blender's
USD importer reads the geometry, UVs, material, texture and the hem and
pin primvars (as mesh attributes); the drape test reads the maillage:*
attributes with the OpenUSD bindings shipped with Blender.
OpenUSD compliance
python -m maillage.validate output/tea_towel
This runs every validator of OpenUSD's UsdValidation registry on each file,
the checks usdchecker runs: composition, stage metadata (meters, Z up),
geometry, material bindings, shaders, UsdPhysics rigid bodies and colliders.
Each file is checked once per variant, since a variant that is not selected is
not composed. The tests and CI require no error and no warning, on every
preset.
Primvaria contract
python -m maillage.conformance output/tea_towel
Maillage is part of Primvaria and follows its
mission and its
OpenUSD contract,
version 0, which the four generators share. Every piece is an asset any tool can find without knowing Maillage: a model of kind
component with assetInfo (name, identifier, version) and the attributes
primvaria:contract, primvaria:generator, primvaria:version,
primvaria:preset and primvaria:seed; /World is an assembly and /World/Cloths a group. The command above checks
the stage units, the model hierarchy and this identity; the tests and CI
require it on every preset.
What was drawn for each piece is in the file too, its ground truth:
primvaria:variation:aspects lists the aspects that were switched on
(size, cut, corners, fabric, color) and primvaria:variation:<name> holds each drawn value
(length_m, width_m, format_length_m, corner_radius_m, cut_amplitudes_m, cut_skew_deg, fabric, pattern, colors…). An aspect that is switched off is still recorded, at its
nominal value, and the other aspects keep their draws.
What was measured on each piece once generated is there as well, as
primvaria:measured:<name> (mass_kg, area_m2, perimeter_m, vertices, faces, edge_mean_mm, min_angle_deg…).
The pack's instances.csv is read back from the OpenUSD files, one row per
asset with the same names (variation:<name>, measured:<name>), and
manifest.json says what the pack is; both have the same shape in the four
generators, and the command above fails when the table and the files disagree.
Each piece also says what it is with OpenUSD's own semantic labels
(UsdSemantics.LabelsAPI), which renderers such as Isaac Sim turn into
segmentation masks: semantics:labels:class holds cloth and the preset (tea_towel), and
semantics:labels:instance the asset's name. The classes are a
column of instances.csv and are listed in manifest.json.