How to use Thin Instances
Starting with Babylon.js v4.2, thin intances are a new feature of meshes.
As explained in How To Use Instances, instances are an excellent way to use hardware accelerated rendering to draw a huge number of identical meshes.
InstancedMesh): if you have 10000 instances in your scene, the engine must loop over all those objects to make a number of processing (visibility check, etc).
- all thin instances are always all drawn (if the mesh is deemed visible) or none. It's all or nothing.
- adding / removing a thin instance is more costly than with
Thin instances should be used when you need a lot of static instances that you know won't change often / at all. Think of the seats of a stadium, for eg.
So, regular instances may still be the way to go, depending on your scene: if you have a lot of objects scattered and only a few are visible in a frame, or if you must add/remove instances continuously, it may be better to use instances than thin instances.
Creating thin instances
A thin instance is represented by a position/rotation/scaling data packed into a matrix.
The easiest way to create a thin instance is by doing:
var matrix = BABYLON.Matrix.Translation(-2, 2, 0);var idx = sphere.thinInstanceAdd(matrix);
You can also pass an array of matrices to
thinInstanceAdd if you want to create multiple thin instances at once.
sphere itself is not rendered. If you want to render it, use
var idx2 = sphere.thinInstanceAddSelf();
These methods return an index that you can use to reference the thin instance.
For example, you can update a thin instance afterwards:
var matrix2 = BABYLON.Matrix.Translation(2, 1, 0);sphere.thinInstanceSetMatrixAt(idx2, matrix2);
Those 3 methods take an additional
refresh parameter (
true by default) that allows you to block the buffer refresh mechanism to save performances: if you must use those methods multiple times, pass
false for all calls except for the last one.
The bounding info of the mesh is recomputed each time you call these methods to encompass all the thin instances (except if you set
true). You can also refresh explicitely the bounding info by calling
As for regular instances, you can add custom attributes to thin instances.
To do so, register the attribute and set the value(s) for the thin instance(s):
sphere.thinInstanceRegisterAttribute("color", 4);sphere.thinInstanceSetAttributeAt("color", idx, [1, 1, 0, 1]);sphere.thinInstanceSetAttributeAt("color", idx2, [1, 0, 0, 1]);
As the thin instance indexes are really indexes into the underlying buffer, you can set the values for several thin instances at once:
sphere.thinInstanceRegisterAttribute("color", 4);sphere.thinInstanceSetAttributeAt("color", 0, [1, 1, 0, 1, 1, 0, 0, 1]);
You can get or set the number of thin instances to display through the
Note that you can't set a number that is higher than what the underlying buffer can handle!
Set the number to 0 to bypass the thin instance rendering and render the mesh as usual.
Faster thin instances
To get the most of the thin instance support, you can directly pass the pre-built buffer of matrices / custom attributes:
var matrix1 = BABYLON.Matrix.Translation(-2, 2, 0);var matrix2 = BABYLON.Matrix.IdentityReadOnly;var matrix3 = BABYLON.Matrix.Translation(2, 1, 0);var bufferMatrices = new Float32Array(16 * 3);matrix1.copyToArray(bufferMatrices, 0);matrix2.copyToArray(bufferMatrices, 16);matrix3.copyToArray(bufferMatrices, 32);var bufferColors = new Float32Array(3 * 4);bufferColors.set([1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1]);sphere.thinInstanceSetBuffer("matrix", bufferMatrices, 16);sphere.thinInstanceSetBuffer("color", bufferColors, 4);
If you have a lot of thin instances to create, it could be a lot faster than calling
thinInstanceSetAttributeAt. Also, you can allocate a bigger buffer than what you really need at start and play with the
thinInstanceCount property to adjust the number of instances to display during the course of your program.
Note that you don't need to call
thinInstanceRegisterAttribute if you set a custom attribute buffer by calling
If you update the buffers you passed to
thinInstanceSetBuffer, you must call
thinInstanceBufferUpdated for the changes to take effect.
To gain some performances, you can flag the buffers as static, meaning you won't change them later on. This way, the system can apply some optimizations to your buffers.
To do so, pass
true for the 4th parameter of
sphere.thinInstanceSetBuffer("matrix", bufferMatrices, 16, true);sphere.thinInstanceSetBuffer("color", bufferColors, 4, true);
Thin instances are supported for collisions, picking, rendering and shadows. However, for collisions, a single bounding info encompassing all the thin instances is used to check intersection: the check is not done for each thin instance separately.
- Thin instances with mixed positive and negative determinant matrices won't be rendered correctly. If you need thin instances with both positive and negative determinants, create two meshes and add the thin instances to one or the other (don't forget to set the
sideOrientationproperty properly for both mesh materials!).
The green and blue cubes are not rendered correctly because they have a -1 scale for the X direction, making the determinant of their matrix negative.
To correct the problem, create another mesh, add the green/blue instances to that mesh (and remove them from the first mesh!) and set the side orientation of the material of that mesh to be Clockwise (by default, it is Counter clockwise):
If you want to create a thin instance from a cloned mesh, you have to first make sure that you call clonedMesh.makeGeometryUnique().
When using motion blur, the engine needs to store world matrices of the previous frame to compute velocity. Usually, this part is taken care of internally, but in certain cases you may have to specify these matrices manually. You may in fact see weird blurring artifacts if you decide to change the world matrix buffer layout, like changing the number of matrices it contains, or using a different order. In that case, you will have to keep a second buffer, storing previous world matrices, and updating it by writing :
mesh.thinInstanceSetBuffer("previousMatrix", instancedPreviousBuffer, 16);
Here is an example of reordering world matrices inside the buffer in each frame, using a different start offset. Previous world matrices are stored and updated, to use motion blur correctly :Thin instances previous matrices motion blur