Summary
A multi-material mesh binds only the first material's map_Kd for the whole model. From src/renderable/mesh.js:450:
"Per-material map_Kd textures are not switched at draw […] first material's map_Kd for the shared texture binding"
So an OBJ whose materials carry different textures — a crate with wood sides and a metal band, a character with separate skin and clothing maps — renders entirely in whichever texture happened to come first.
Why it matters
Multi-material OBJ/MTL is already advertised and half-implemented: each material's diffuse colour (Kd) is baked into vertexColors at construction and composes correctly, and the geometry already tracks a per-material index slice. It is only the texture binding that is collapsed. That asymmetry is the confusing part — colours vary per material, textures silently do not.
Proposal
The infrastructure is already there: draw one indexed range per material slice instead of one range for the whole mesh, binding that material's texture before each.
- Retained path: the slices are contiguous in the index buffer, so this is N
drawElements calls with an offset/count per slice rather than one — no extra geometry, no re-upload.
- Materials sharing a texture should coalesce into one range rather than forcing a draw per slice.
- The multi-texture batching the quad tier uses (up to eight textures selected per-vertex by a texture id) is a possible alternative that keeps it to a single draw, but it costs an attribute and complicates the mesh vertex layout — worth measuring against the simpler split before choosing.
Worth deciding explicitly
Whether the per-material sort order is honoured. Splitting the draw makes each material's geometry a separate call, which changes nothing for opaque depth-tested geometry but does become visible if alpha-blended materials are ever supported (#1516).
Acceptance
- A two-material OBJ with two distinct
map_Kd textures renders each material with its own texture, on both GPU backends.
- A single-material mesh issues exactly the same number of draw calls as today (no regression for the common case).
- Materials sharing one texture do not produce redundant draws.
References
src/renderable/mesh.js:440-540 (material resolution and the shared texture binding), src/video/webgl/batchers/mesh_batcher.js (applyMeshMaterial, drawRetainedMesh), src/video/webgpu/batchers/mesh_batcher.js.
Summary
A multi-material mesh binds only the first material's
map_Kdfor the whole model. Fromsrc/renderable/mesh.js:450:So an OBJ whose materials carry different textures — a crate with wood sides and a metal band, a character with separate skin and clothing maps — renders entirely in whichever texture happened to come first.
Why it matters
Multi-material OBJ/MTL is already advertised and half-implemented: each material's diffuse colour (
Kd) is baked intovertexColorsat construction and composes correctly, and the geometry already tracks a per-material index slice. It is only the texture binding that is collapsed. That asymmetry is the confusing part — colours vary per material, textures silently do not.Proposal
The infrastructure is already there: draw one indexed range per material slice instead of one range for the whole mesh, binding that material's texture before each.
drawElementscalls with an offset/count per slice rather than one — no extra geometry, no re-upload.Worth deciding explicitly
Whether the per-material sort order is honoured. Splitting the draw makes each material's geometry a separate call, which changes nothing for opaque depth-tested geometry but does become visible if alpha-blended materials are ever supported (#1516).
Acceptance
map_Kdtextures renders each material with its own texture, on both GPU backends.References
src/renderable/mesh.js:440-540(material resolution and the shared texture binding),src/video/webgl/batchers/mesh_batcher.js(applyMeshMaterial,drawRetainedMesh),src/video/webgpu/batchers/mesh_batcher.js.