Split out of #322 (p6-s8) · governed by ADR-0013.
Problem
p6-s8 imports a glTF/GLB as a prop, but an imported model's textures are
discarded. props::PropPart carries positions, normals, indices and a single
flat linear-RGB color — no UVs, no texture reference
(core/include/roadmaker/assets/prop_library.hpp:40-46). So the importer decodes
the primitive's baseColorTexture, averages it, multiplies by
baseColorFactor, and stores that one colour, warning per primitive as it goes.
A user importing a patterned chair gets a chair in roughly the right colour. That
is honest, and it is the decision ADR-0013 records — but it is not the feature.
Why it was not done in p6-s8
Because PropPart is not the only thing in the way. Every consumer of a prop
model assumes flat colour:
editor/src/viewport/viewport_widget.cpp:625 — all props draw with one
shared material_for(SurfaceKind::Untextured, {}).
editor/src/render/scene_builder.cpp:245-249 — a batch converts each part to
RenderMeshData once, colour only; RenderMeshData does have a uvs field
(editor/src/render/renderer.hpp:115-120), so the renderer is not the blocker.
core/src/io/gltf_exporter.cpp — one glTF material per (model_id, part.name)
via mesh_export_common.hpp:130, flat colour.
core/src/io/usd_exporter.cpp:63-71 — its own local MaterialDef{color3, roughness}.
Doing it properly is a change to the kernel representation, the instanced upload
path, and both exporters — which crosses the export byte-identity surface.
That is its own sprint, not a rider on an import sprint.
Scope
PropPart gains std::vector<double> uvs and an optional base-colour image
(owned by the model, so props::model()'s pointer contract is unchanged).
- The importer stops flattening: it keeps UVs and the decoded image, and the
warning this issue is cited from disappears.
ScenePropBatch carries the material; the viewport uploads it once per batch
(the sign-face path at viewport_widget.cpp:179-197 is the precedent for a
runtime-generated texture) and stops sharing one untextured material.
- The glTF exporter embeds the image; the USD exporter emits a
UsdUVTexture.
- Existing bundled props have no UVs and must keep exporting byte-identically
— that is the regression gate, not a nice-to-have.
Acceptance
- A textured GLB imports, renders with its texture, and exports with it to both
.glb and .usda.
- Every bundled prop's
.glb and .usda output is byte-identical to before.
- No import warning about flattening remains.
Split out of #322 (
p6-s8) · governed by ADR-0013.Problem
p6-s8imports a glTF/GLB as a prop, but an imported model's textures arediscarded.
props::PropPartcarries positions, normals, indices and a singleflat linear-RGB
color— no UVs, no texture reference(
core/include/roadmaker/assets/prop_library.hpp:40-46). So the importer decodesthe primitive's
baseColorTexture, averages it, multiplies bybaseColorFactor, and stores that one colour, warning per primitive as it goes.A user importing a patterned chair gets a chair in roughly the right colour. That
is honest, and it is the decision ADR-0013 records — but it is not the feature.
Why it was not done in
p6-s8Because
PropPartis not the only thing in the way. Every consumer of a propmodel assumes flat colour:
editor/src/viewport/viewport_widget.cpp:625— all props draw with oneshared
material_for(SurfaceKind::Untextured, {}).editor/src/render/scene_builder.cpp:245-249— a batch converts each part toRenderMeshDataonce, colour only;RenderMeshDatadoes have auvsfield(
editor/src/render/renderer.hpp:115-120), so the renderer is not the blocker.core/src/io/gltf_exporter.cpp— one glTF material per(model_id, part.name)via
mesh_export_common.hpp:130, flat colour.core/src/io/usd_exporter.cpp:63-71— its own localMaterialDef{color3, roughness}.Doing it properly is a change to the kernel representation, the instanced upload
path, and both exporters — which crosses the export byte-identity surface.
That is its own sprint, not a rider on an import sprint.
Scope
PropPartgainsstd::vector<double> uvsand an optional base-colour image(owned by the model, so
props::model()'s pointer contract is unchanged).warning this issue is cited from disappears.
ScenePropBatchcarries the material; the viewport uploads it once per batch(the sign-face path at
viewport_widget.cpp:179-197is the precedent for aruntime-generated texture) and stops sharing one untextured material.
UsdUVTexture.— that is the regression gate, not a nice-to-have.
Acceptance
.glband.usda..glband.usdaoutput is byte-identical to before.