Skip to content

Mesh: bind per-material textures at draw for multi-material models #1573

Description

@obiot

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions