You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add mesh instancing — draw one geometry many times in a single draw call with per-instance data (transform, tint/color, maybe emissive) — via drawElementsInstanced / drawArraysInstanced (WebGL 2 core; ANGLE_instanced_arrays on WebGL 1).
Motivation
Many 3D scenes are the same mesh repeated: a city of identical buildings, a forest of trees, crowds, bullets, asteroids, coins, tiles-as-cubes. Today each repeat is its own Mesh with its own geometry that is re-projected, re-batched, and re-uploaded every frame — so cost scales with instances × vertices, even though the geometry is identical.
With instancing, the geometry is uploaded once and the GPU stamps out N copies from a small per-instance attribute buffer, so CPU cost scales with instances (a tiny per-instance record), not instances × vertices. This is how retained 3D engines (Three.js InstancedMesh, Babylon thin/instances, pixi3d InstancedModel, Cocos) draw thousands of repeated objects cheaply — a capability melonJS currently lacks entirely.
Concrete example: the night-city showcase builds ~500 buildings as unique geometry (~158k verts). With instancing, a handful of building prototypes drawn N times would collapse that to a few prototype geometries + a per-instance transform/color buffer — a large CPU + memory win, and it would scale to thousands of buildings.
Proposal
New API, e.g. InstancedMesh (a Mesh subclass or a dedicated renderable) that holds:
one shared geometry (vertices/uvs/indices/normals), and
a per-instance buffer of transforms (mat4 or compact TRS) + optional per-instance color/tint (and emissive, to compose with the Tier-2 material work).
API surface: addInstance(transform, { color?, emissive? }), setInstance(i, ...), removeInstance(i), instanceCount, with a dirty range so only changed instances re-upload.
Batcher: a dedicated instanced draw path that binds the shared geometry once, sets up instanced vertex attributes (vertexAttribDivisor), and issues drawElementsInstanced.
Shaders: a mesh/lit-mesh shader variant that reads the per-instance transform + color attributes and applies them before the camera view/projection.
Camera3d culling: cull per instance against the frustum and compact the visible set into the instance buffer (or upload all and let the GPU clip) — start simple (upload all), optimize later.
Scope / considerations
WebGL 2 has instancing in core; for WebGL 1 fall back to the ANGLE_instanced_arrays extension or to the non-instanced path if unavailable.
Per-instance transform as a mat4 = 4 vec4 attributes (4 attribute slots) — mind the attribute count limit; a compact TRS (pos + quat + scale) decoded in the shader is an alternative.
Compose with the 19.8 material features: per-instance emissive / tint is high value (e.g. the night-city's per-building glow becomes a per-instance attribute).
Context-loss: rebuild instanced buffers on ONCONTEXT_RESTORED.
Drawing N copies of one geometry issues onedrawElementsInstanced call (verifiable via GL spy), with CPU cost ~O(changed instances), not O(N × vertices).
A repeated-geometry scene (e.g. a re-worked night-city or a forest demo) renders far more objects at 60 fps than the equivalent unique-mesh scene.
Per-instance transform + color/emissive render correctly, under both unlit and lit paths.
WebGL 1 fallback path is correct (extension or non-instanced).
New example/showcase demonstrating it (forest / crowd / instanced city).
Summary
Add mesh instancing — draw one geometry many times in a single draw call with per-instance data (transform, tint/color, maybe emissive) — via
drawElementsInstanced/drawArraysInstanced(WebGL 2 core;ANGLE_instanced_arrayson WebGL 1).Motivation
Many 3D scenes are the same mesh repeated: a city of identical buildings, a forest of trees, crowds, bullets, asteroids, coins, tiles-as-cubes. Today each repeat is its own
Meshwith its own geometry that is re-projected, re-batched, and re-uploaded every frame — so cost scales withinstances × vertices, even though the geometry is identical.With instancing, the geometry is uploaded once and the GPU stamps out N copies from a small per-instance attribute buffer, so CPU cost scales with instances (a tiny per-instance record), not
instances × vertices. This is how retained 3D engines (Three.jsInstancedMesh, Babylon thin/instances, pixi3dInstancedModel, Cocos) draw thousands of repeated objects cheaply — a capability melonJS currently lacks entirely.Concrete example: the night-city showcase builds ~500 buildings as unique geometry (~158k verts). With instancing, a handful of building prototypes drawn N times would collapse that to a few prototype geometries + a per-instance transform/color buffer — a large CPU + memory win, and it would scale to thousands of buildings.
Proposal
InstancedMesh(aMeshsubclass or a dedicated renderable) that holds:addInstance(transform, { color?, emissive? }),setInstance(i, ...),removeInstance(i),instanceCount, with a dirty range so only changed instances re-upload.vertexAttribDivisor), and issuesdrawElementsInstanced.Scope / considerations
ANGLE_instanced_arraysextension or to the non-instanced path if unavailable.emissive/ tint is high value (e.g. the night-city's per-building glow becomes a per-instance attribute).ONCONTEXT_RESTORED.Acceptance criteria
drawElementsInstancedcall (verifiable via GL spy), with CPU cost ~O(changed instances), not O(N × vertices).References
src/renderable/mesh.js,src/video/webgl/batchers/mesh_batcher.js/lit_mesh_batcher.jssrc/video/webgl/batchers/batcher.js(draw call paths),src/video/buffer/*src/video/webgl/shaders/mesh.frag/mesh-lit.frag+.vertsrc/camera/camera3d.ts(per-instance frustum culling,queryVisible)InstancedMesh, pixi3dInstancedModel, Babylon instances