Found while implementing p6-s9 (#323); deliberately left out of that sprint
rather than widening its blast radius into the render and export paths. The
evidence is recorded on #323
(note 3).
The gap
Object::pitch and Object::roll (§13.1, Table 85) are parsed, written and
round-tripped correctly — and then silently ignored by the mesher and by
both exporters, for every prop in the product, not just for assembly parts.
The cause is one struct: mesh::ObjectInstance
(core/include/roadmaker/mesh/mesh.hpp:145-154) carries a position, a heading
about +Z, and one uniform scale. There is nowhere for a pitch or a roll to go,
so mesh_builder never reads them and the glTF and USD exporters never see them.
Why it is worth fixing rather than documenting
- A file authored elsewhere that leans a sign back 5° opens in RoadMaker looking
upright, saves back byte-identical, and the user never learns the viewport is
lying to them. Silent disagreement between what is stored and what is drawn is
exactly the class of bug the never-drop contract exists to prevent.
- It is the reason the bundled
signal_mast assembly ships its arm as
already-horizontal geometry rather than as an upright post rotated 90°
(p6-s9). A part that must lie down has to arrive lying down, which constrains
how every future assembly is authored.
Scope
- Widen
mesh::ObjectInstance to a full orientation (the minimal change is two
more angles; a 3×3 or a quaternion is the alternative — worth deciding rather
than defaulting).
- Read
@pitch/@roll in mesh_builder's object placement.
- Carry the orientation through the glTF and USD exporters, and through the
instanced render fast path (p6-s6) — the batched path is where a naive fix
regresses performance, so measure.
- The properties panel gains the two fields once they mean something.
- Once it lands,
props::AssemblyPart can gain dpitch/droll and the mast arm
can become an ordinary post with a rotation.
Acceptance
- A corpus file with a non-zero
@pitch on a prop renders leaning, and exports
leaning to both glTF and USD.
- The instanced path draws the same orientation as the non-instanced one.
- Round-trip stays byte-identical (this is a render/export fix, not a
persistence change — persistence already works).
Found while implementing p6-s9 (#323); deliberately left out of that sprint
rather than widening its blast radius into the render and export paths. The
evidence is recorded on #323
(note 3).
The gap
Object::pitchandObject::roll(§13.1, Table 85) are parsed, written andround-tripped correctly — and then silently ignored by the mesher and by
both exporters, for every prop in the product, not just for assembly parts.
The cause is one struct:
mesh::ObjectInstance(
core/include/roadmaker/mesh/mesh.hpp:145-154) carries a position, a headingabout +Z, and one uniform scale. There is nowhere for a pitch or a roll to go,
so
mesh_buildernever reads them and the glTF and USD exporters never see them.Why it is worth fixing rather than documenting
upright, saves back byte-identical, and the user never learns the viewport is
lying to them. Silent disagreement between what is stored and what is drawn is
exactly the class of bug the never-drop contract exists to prevent.
signal_mastassembly ships its arm asalready-horizontal geometry rather than as an upright post rotated 90°
(p6-s9). A part that must lie down has to arrive lying down, which constrains
how every future assembly is authored.
Scope
mesh::ObjectInstanceto a full orientation (the minimal change is twomore angles; a 3×3 or a quaternion is the alternative — worth deciding rather
than defaulting).
@pitch/@rollinmesh_builder's object placement.instanced render fast path (p6-s6) — the batched path is where a naive fix
regresses performance, so measure.
props::AssemblyPartcan gaindpitch/drolland the mast armcan become an ordinary post with a rotation.
Acceptance
@pitchon a prop renders leaning, and exportsleaning to both glTF and USD.
persistence change — persistence already works).