Changing number of instance for InstancedBufferGeometry

It’s related to Instancing Point Cloud, but I figured it might make sense to start a new topic here.
So with some help from @Mugen87 , I was able to instance point clouds, but another problem emerges: What it I would like to dynamically change the number of instances on the fly? i.e. I would like to change the length of instancedBufferAttribute? a live example is here: https://jsfiddle.net/mprj6bvg/3/ where it’s trying to add new instance on mouse down (but not working).

Thanks to @prisoner849, there is a working solution: https://jsfiddle.net/prisoner849/xfoLrnej/, basically setting the max instance count upfront, and always render that many instances:

var clickCounter = 0;
var maxInstances = 10;
...
    sumDisplacement = new Float32Array(maxInstances * 3);
    sumDisplacement.fill(0);
    sumDisplacement[0] = -2000; // x-coord for the first instance
...
    geometry.setAttribute('offset', new THREE.InstancedBufferAttribute(sumDisplacement, 3 ));
    geometry.maxInstancedCount = 1;
...
function onMouseDown() {
	
  clickCounter++;
  if (clickCounter < maxInstances){
    newPosition = newPosition + 2000;
    sumDisplacement[clickCounter * 3] = newPosition; // x-coord for current instance
    geometry.maxInstancedCount = clickCounter + 1; // how many instances will be drawn
    geometry.attributes.offset.needsUpdate = true;
  }
  
}

However, I’m a little concerned that would it be inefficient if the max count is large?
say the max possible number of instance is 1000, but usually we only need 1-50. Maybe In this way GPU would always have to process 1000 instances causing unnecessary performance lost?
Also, what if I don’t know the maximum possible number of instances at all?
Is it possible to change the length of the instanced buffer attribute?

Thanks again!

Buffer attributes or more precise the underlying array buffers are fixed length. So no, it’s not possible to resize them like ordinary arrays.

The normal approach is to create buffer attributes with sufficient length and then use BufferGeometry.setDrawRange() to tell the engine what range of data should be rendered. For instanced buffer geometry, you use InstancedBufferGeometry.maxInstancedCount to specify the amount of instances.

No, maxInstancedCount is directly mapped to instanceCount of the underlying WebGL API. This parameter defines how many instances the GPU should actually render.

Then you have to make a guess. Or completely re-create the geometry if necessary.

4 Likes

@Mugen87 Can I know a bit more about when will the _maxInstancedCount is being initialized?

I’m finding a way to initialize it upfront and send it into my pool to reuse and lower the instanced count later.

It happens during the first rendering of the geometry. When using InstancedBufferGeometry, create the buffers large enough and then use instanceCount to lower the number of drawn instances. The default value of instanceCount is Infinity (meaning the entire buffer is used for rendering).

:thinking: Hmm… A bit curious about the design decisions here.

Since the buffer size can’t be changed.

Why don’t we estimate the max instance count using the length of the buffer provided?

And having a dynamic instanceCount to scope the number of instances.

Instead of copying _maxInstanceCount from instanceCount on the fly.

It’s because InstancedBufferGeometry and InstancedMesh usage should match.

In general, you should always work with InstancedMesh if possible.

1 Like