Hi,
I created a custom InstancedMesh to add/remove instances at runtime. This is how my implementation looks like:
import * as THREE from "three";
export class DynamicInstancedMesh extends THREE.InstancedMesh {
constructor(geometry, material, count, initialCapacity = count, capacityIncrement = 10) {
super(geometry, material, count);
this.bufferCapacity = initialCapacity < count ? count : initialCapacity;
this.bufferCapacityIncrement = capacityIncrement;
if (count < initialCapacity) {
this.updateCapacity();
}
}
updateCapacity() {
console.log("update capacity");
const matrixBuffer = new Float32Array(this.instanceMatrix.itemSize * this.bufferCapacity);
matrixBuffer.set(this.instanceMatrix.array);
this.instanceMatrix.count = this.bufferCapacity;
this.instanceMatrix.array = matrixBuffer;
if (this.instanceColor !== null) {
const colorBuffer = new Float32Array(this.instanceColor.itemSize * this.bufferCapacity);
colorBuffer.set(this.instanceColor.array);
this.instanceColor.count = this.bufferCapacity;
this.instanceColor.array = colorBuffer;
}
}
addInstance(matrix4) {
this.count++;
if (this.count > this.bufferCapacity) {
this.bufferCapacity += this.bufferCapacityIncrement;
this.updateCapacity();
}
this.instanceMatrix.array.set(matrix4.elements, this.instanceMatrix.itemSize * (this.count - 1));
}
removeInstance(i) {
if (i >= this.count) {
return false;
}
// matrix
const endMatrix = this.instanceMatrix.itemSize * this.count;
const lastMatrix = this.instanceMatrix.array.subarray(endMatrix - this.instanceMatrix.itemSize, endMatrix);
this.instanceMatrix.array.set(lastMatrix, i * this.instanceMatrix.itemSize);
// color
if (this.instanceColor !== null) {
const endColor = this.instanceColor.itemSize * this.count;
const lastColor = this.instanceColor.array.subarray(endColor - this.instanceColor.itemSize, endColor);
this.instanceColor.array.set(lastColor, i * this.instanceColor.itemSize);
}
this.count--;
return true;
}
setColorAt(index, color) {
if (this.instanceColor === null) {
this.instanceColor = new THREE.BufferAttribute(new Float32Array(this.bufferCapacity * 3), 3);
}
color.toArray(this.instanceColor.array, index * 3);
}
}
It works as expected at first. But as soon as I increase the capacity after the renderer is initialized I get an “WebGL: INVALID_VALUE: bufferSubData: buffer overflow” error.
The reason for that is that the WebGLAttributes uses a cached (fixed size) GL Buffer which will not increase automatically.
My idea was now to do that in my DynamicInstancedMesh class. But I couldn’t find a way to access the WebGLAttributes through the renderer.
So my two questions would be. Is that the right way to go at all? And if yes, how can I make it work?