v150 · WebGPU

Per-Draw Materials

In a single render pass, call setImmediateData() before each draw to pass a material ID directly to the shader — no bind group swap, no buffer write. Click a shape to select it; the highlight flag travels as a second immediate.

Feature detection: checking…
Why this matters: The traditional approach to per-draw data (material, object ID, LOD level) requires either a storage buffer lookup or a bind group swap per draw call. Both have overhead. With immediates you call pass.setImmediateData(0, data) between draws — the data goes through the GPU's native push-constant path, which is designed for exactly this pattern.

Click a shape to select/deselect it. The selection state travels as an immediate.

No selection

// WGSL — read per-draw material from immediate address space
struct DrawData {
  materialId : u32,   // which material to use
  selected   : u32,   // 0=normal, 1=highlighted
  time       : f32,   // for animation
}
var<immediate> draw: DrawData;

const MATERIALS = array<vec3f, 6>(
  vec3f(0.85, 0.22, 0.22),  // 0 red
  vec3f(0.18, 0.72, 0.42),  // 1 emerald
  vec3f(0.15, 0.30, 0.90),  // 2 blue
  vec3f(0.90, 0.68, 0.10),  // 3 amber
  vec3f(0.55, 0.20, 0.88),  // 4 violet
  vec3f(0.10, 0.68, 0.86),  // 5 cyan
);

@fragment fn fs(...) -> @location(0) vec4f {
  var col = MATERIALS[draw.materialId % 6u];
  if draw.selected == 1u {
    col = col * 1.4 + vec3f(0.15);   // brighten on select
  }
  return vec4f(col, 1.0);
}

// ── JS: single render pass, six draw calls ──────────────────
const pass = encoder.beginRenderPass(descriptor);
pass.setPipeline(pipeline);

for (let i = 0; i < objects.length; i++) {
  const data = new ArrayBuffer(12);
  const dv = new DataView(data);
  dv.setUint32 (0, i,                   true); // materialId
  dv.setUint32 (4, selectedIdx === i ? 1 : 0, true); // selected
  dv.setFloat32(8, time,                true); // time

  pass.setImmediateData(0, data); // ← per-draw, no bind group swap
  pass.setVertexBuffer(0, vertexBuffers[i]);
  pass.draw(6);                   // two triangles (quad)
}
pass.end();

see also

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗