--- title: Thin Instances image: description: Learn how to leverage thin instances in your Babylon.js scenes. keywords: diving deeper, meshes, mesh transformation, instances, thin instances further-reading: - title: How To Use Instances url: /features/featuresDeepDive/mesh/copies/instances video-overview: video-content: - title: A Pirate Playset Part 1 - Thin Instances url: https://youtu.be/0DaSvI_n7Us --- ## How to use Thin Instances Starting with Babylon.js v4.2, thin instances are a feature of meshes. PG: As explained in [How To Use Instances](/features/featuresDeepDive/mesh/copies/instances), instances are an excellent way to use hardware-accelerated rendering to draw a huge number of identical meshes. However, regular instances still have a performance penalty on the JavaScript side because each instance is its own object (`InstancedMesh`): if you have 10000 instances in your scene, the engine must loop over all those objects to perform a number of operations (visibility checks, etc.). Thin instances don't create new objects, so you don't incur any penalty on the JavaScript side by having thousands of them. This performance increase does come with a cost: * either all thin instances are drawn (if the mesh is deemed visible) or none are. It's all or nothing. * adding / removing a thin instance is more costly than with `InstancedMesh` Thin instances should be used when you need a lot of static instances that you know won't change often, if at all. Think of the seats in a stadium, for example. 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: ```javascript 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. Note that `sphere` itself is not rendered. If you want to render it, use `thinInstanceAddSelf()`: ```javascript 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: ```javascript var matrix2 = BABYLON.Matrix.Translation(2, 1, 0); sphere.thinInstanceSetMatrixAt(idx2, matrix2); ``` Example: Those three methods take an additional `refresh` parameter (`true` by default) that allows you to block the buffer refresh mechanism to improve performance: if you must use those methods multiple times, pass `false` for all calls except 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 `doNotSyncBoundingInfo` to `true`). You can also refresh explicitly the bounding info by calling `thinInstanceRefreshBoundingInfo`. ## Custom attributes 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): ```typescript 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: ```typescript sphere.thinInstanceRegisterAttribute("color", 4); sphere.thinInstanceSetAttributeAt("color", 0, [1, 1, 0, 1, 1, 0, 0, 1]); ``` Example: You can get or set the number of thin instances to display through the `thinInstanceCount` property. 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 out of thin instance support, you can directly pass the pre-built buffer of matrices / custom attributes: ```typescript 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); ``` Example: If you have a lot of thin instances to create, this can be much faster than calling `thinInstanceAdd` / `thinInstanceSetAttributeAt`. You can also allocate a bigger buffer than what you really need at the start and use 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 `thinInstanceSetBuffer`. If you update the buffers you passed to `thinInstanceSetBuffer`, you must call `thinInstanceBufferUpdated` for the changes to take effect. However, for performance reasons, buffers are not updateable by default. If you plan to update a buffer later, you must make it updateable by passing **false** for the **static** flag (4th parameter of `thinInstanceSetBuffer`): ```javascript sphere.thinInstanceSetBuffer("matrix", bufferMatrices, 16, false); // matrix buffer is updateable sphere.thinInstanceSetBuffer("color", bufferColors, 4, true); // color buffer is not updateable ``` ## Support 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. Here's an example of thin instances picking: ## Limitations * 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 `sideOrientation` property properly for both mesh materials!). For example: ![Wrong rendering](/img/how_to/Mesh/thinInstancesWrongSideOrientation.webp) 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**): PG: ![Correct rendering](/img/how_to/Mesh/thinInstancesOkSideOrientation.webp) * 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 : ```javascript 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 :