Issue 1:
Hi all,

while writing examples for grow3.js, I found out that adding objects gets increasingly slower with more objects already in the scene. It gets apparent at >>10k objects in a scene.

I tracked down the problem to this line in Scene.js:

if ( this.__objects.indexOf( object ) === - 1 ) {

Usually objects you try to add to a scene aren't already in it, so the indexOf() statement searches through the whole array every time an object is added to the scene. This means a quadratic increase in computation time depending on the overall number of objects n.

Scene.__objects seems to be used to prevent duplicate objects ending in __objectAdded. I'm not sure if this somewhat defensive code is needed - the objects aren't prevented to be added to the scene hierarchy anyway.

So my proposal would be to just remove the __objects array. I did this here. three.js examples seem to still work fine, performance while building scenes with many objects increases dramatically.

An alternative might be to have some flag to explicitly disable dupes-checking at runtime.

Finally some vague measurements (with my oldish Macbook) based on the webgl_performance.html example, by changing the number of objects (numbers = ms for initializing the scene):

500 nodes: 200ms (no __objects: 95ms)

20000 nodes: 1707ms (no __objects: 577ms)

40000 nodes: 7000ms (no __objects: 744ms)

If maintainers agree, I'd issue a pull request. Just didn't want to rush in, as this seems to apply to the very core of three.js...

Cheers!

Issue 2:
Summary of feature request

.addScaledVector but instead of adding a scaled vector, merging a transformed BufferGeometry

Description of feature request

For optimization purposes, I want to render a single buffer geometry instead of rendering each object in my scene separately

const geometry = THREE.BufferGeometryUtils.mergeBufferGeometries(this.children.map(child =>
child.geometry.clone().applyMatrix4(child.matrix) // The issue
));
this.add(new THREE.Mesh(geometry, this.children[0].material));
for (const child of this.children) {
child.visible = false;
}

(simplified code, not tested but should convey my point)

Unfortunately, the existing buffer geometry merge methods don't support transforming each merged vertex by a custom matrix. That means I have to clone each child's geometry and apply the matrix to the entire clone at once.

This is a waste of memory, and could be avoided with

BufferGeometry.merge(bufferGeometry, optionalMatrix)

BufferGeometryUtils.mergeBufferGeometries(bufferGeometries, optionalMatrices)

The 2nd option is slightly more awkward but is preferred because BufferGeometryUtils is lossless (doesn't require manual index argument)

If a matrix is passed in, each vertex being merged in should have it applied.

Note: I know I could get around this by pre-applyMatrix4-ing all my objects' geometries, but I don't want to do that...I want them to share a single, applyMatrix4'd buffer geometry instance.

Note 2: For my use case, each child's BufferGeometry is the same. A solution specific to my case is :

BufferGeometryUtils.stamp(bufferGeometry, matrices)

Which would take a single geometry and stamp it at multiple locations/rotations/scales defined by each matrix.

Three.js version

Dev

r114