BatchedMesh: Proposal
See original GitHub issueCurrently the APIs available for reducing draw calls include:
I think we might be able to solve some common difficulties with reducing draw calls, even where the objects to be rendered are not instances of the same thing. I’ve floated the idea in a couple of earlier comments (https://github.com/mrdoob/three.js/issues/19164#issuecomment-631237304, https://github.com/mrdoob/three.js/issues/18918#issuecomment-602395984) but wanted to open a separate issue for it.
Calling this BatchedMesh
for now, it’s meant to be a way of (1) merging, (2) rendering, and (3) updating a group of objects that would otherwise be drawn as separate Mesh instances. The objects must all be the same primitive type (i.e. triangles), must share a material, and must have compatible vertex attributes (e.g. if one has normals, they all have normals). With those requirements we could offer an API like:
// Create BatchedMesh with max vertex and triangle counts to support. If
// geometry is not indexed, maxTriangleCount is optional. The 'template'
// geometry could just be the first geometry we'll add later — it isn't stored,
// but is used to determine which vertex attributes to allocate.
const batchedMesh = new BatchedMesh( templateGeometry, material, maxVertexCount, maxTriangleCount );
// Append geometry, up to max vertex and triangle limit.
const id1 = batchedMesh.add( geometry1, matrix1 );
const id2 = batchedMesh.add( geometry2, matrix2 );
const id3 = batchedMesh.add( geometry3, matrix3 );
scene.add( batchedMesh );
renderer.render( scene, camera );
// Update object position dynamically. For small objects this may be cheaper than
// a separate draw call. For large objects, it may be better to draw the object
// separately than to update it with dynamic batching.
batchedMesh.setMatrixAt( id1, otherMatrix );
renderer.render( scene, camera );
This offers a few advantages over mergeBufferGeometries()
. First, you get an ID that lets you remove or modify each geometry later. Second, we can potentially do much faster raycasting (we know the bounding box and transform of each member geometry) and return that ID as a result. Third, we can do frustum culling (maybe?) by updating the index buffer.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:50
- Comments:60 (10 by maintainers)
Top GitHub Comments
Made a prototype.
Branch: https://github.com/mrdoob/three.js/compare/dev...takahirox:BatchedMesh?expand=1
Online demo: https://raw.githack.com/takahirox/three.js/BatchedMeshTest/examples/index.html#webgl_multidraw
https://user-images.githubusercontent.com/7637832/132141130-f84d2a3d-97d1-4c3f-b88b-46f0dba8ae65.mp4
40 fps (BatchedMesh) vs 30 fps (regular Mesh) on my Windows 10 Chrome.
Hi all! The devs of IFC.js here.
We would benefit greatly from this feature and are willing to invest resources into this. I don’t know the state and how much it would take to finish this, but if one/many people are willing to get paid for getting this done, you can count on us to finance it. 🙂