Hello everyone!
I’m currently running some performance benchmarks between Three.js and Babylon.js for an interactive web simulator I’m building. My goal is to render a massive amount of objects (e.g., 100k to 200k cubes) and change the color of a specific instance dynamically when the user hovers over it with the mouse.
The Three.js Approach (Working perfectly): In Three.js, this was quite straightforward. I used an InstancedMesh alongside a Raycaster. I mapped an instanceColor buffer, and inside the render loop, I check for intersections. Once hit, I get the instanceId, update the specific RGB values in the float array, and flag needsUpdate = true. It works flawlessly and smoothly at 144fps on my RTX 4070 Ti.
The Babylon.js Struggle: I am trying to replicate this exact behavior using Thin Instances. Rendering 1.5 million static cubes is incredibly fast and matches the performance perfectly. However, I have completely failed to make the individual hover/color change work.
Here is what I have tried so far:
-
Setting
box.thinInstanceEnablePicking = trueandbox.isPickable = true. -
Initializing a dynamic color buffer:
box.thinInstanceSetBuffer("color", colorsArray, 4, false). -
Using
scene.pick()in the render loop to get thepickResult.thinInstanceIndex. -
Updating the color using
box.thinInstanceSetColorAt()(or updating the array directly and callingbox.thinInstanceBufferUpdated("color")). -
Trying different materials to ensure the color isn’t being overwritten by lighting (
StandardMaterialwith emissive white, andPBRMaterialwithunlit = true).
Despite my efforts, the individual instance color simply does not change on the screen.
For reference, here is the core logic of what works beautifully in Three.js:
// Three.js working logic
const raycaster = new THREE.Raycaster();
// ... setup InstancedMesh with instanceColor buffer ...
function animate() {
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(instancedMesh);
// Reset previous hovered color
if (hoveredId !== -1) {
colors[hoveredId * 3] = defaultR; // ... G and B
hoveredId = -1;
instancedMesh.instanceColor.needsUpdate = true;
}
// Set new hover color
if (intersects.length > 0) {
hoveredId = intersects[0].instanceId;
colors[hoveredId * 3] = hoverR; // ... G and B
instancedMesh.instanceColor.needsUpdate = true;
}
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Is there a fundamental architectural difference or a missing flag I am overlooking? What is the correct, performant “Babylon way” to achieve this real-time individual color update on hover for hundreds of thousands of thin instances?
Any help, insights, or a Playground example would be hugely appreciated! Thank you!