# InstancedMesh2 - Easy handling and frustum culling

**URL:** <https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622>\
**Category:** Discussion\
**Created:** [November 27, 2023, 3:11pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622 "2023-11-27T15:11:21Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [November 27, 2023, 3:11pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/1 "2023-11-27T15:11:21Z")

</div>

## Library posted here:

> [@Three.ez/InstancedMesh2 - Enhanced InstancedMesh with frustum culling, fast raycasting (BVH), sorting, visibility management, LOD, skinning and more](https://discourse.threejs.org/t/three-ez-instancedmesh2-enhanced-instancedmesh-with-frustum-culling-fast-raycasting-bvh-sorting-visibility-management-and-more/69344):
>
> Three.ez - InstancedMesh2 Simplify your three.js application development with three.ez! [three-ez-banner] [[Discord]](https://discord.gg/MVTwrdX3JM)[[npm]](https://www.npmjs.com/package/@three.ez/instanced-mesh)[[Stars]](https://github.com/three-ez/instanced-mesh)[[BundlePhobia]](https://bundlephobia.com/package/@three.ez/instanced-mesh)[[Quality Gate Status]](https://sonarcloud.io/summary/new_code?id=agargaro_instanced-mesh)[[DeepScan grade]](https://deepscan.io/dashboard#view=project&tid=21196&pid=27990&bid=896898) InstancedMesh2 is an alternative version of InstancedMesh with enhanced features for performance and usability: [Per-instance frustum culling](#per-instance-frustum-culling): skip rendering for out-of-view instances. [Sorting](#sorting): reduce overdraw and manage transparent objects efficiently. [Spatial indexing (dynamic BVH)](#spatial-indexing-dynamic-bvh): spe…

…

Hi, I have been working on an extension to `InstancedMesh` for a couple of days now.

## InstancedMesh2

I have created my own `InstancedMesh2` class that extends `InstancedMesh`, which manages an array of `InstancedEntity`, itself a class that is similar to `Object3D` that allows you to manage the position, scale, rotation and **visibility**.  
Visibility is managed by swapping the element you wish to hide with the last one in instanceMatrix array, and decreasing the count by 1.  
_ **This allows the hidden element not to actually be rendered.** _

This approach uses more memory but:

1. it simplifies object transformations
2. it allows hiding all instances that are not in the camera frustum (I am working on this with good results, using a custom octree and other optimisations, even if i want to try BVH)
3. it allows the easy creation of an `InstancedLOD` (which I am working on, also with good results)

I tried using an InstancedMesh2 with a count of 2kk, using low poly geometry.  
In a favourable scenario, with static objects and camera, thanks to the frustum control, it was possible to hide 85% of the instances. Frustum check needs to be done after each camera transformation (still considering static objects).

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/2/1/212c5e2da20c096ab10d88897caa1bad57bb4392.jpeg)

## How to use it

```javascript
const monkeys = new InstancedMesh2(geometry, material, count, {
  behaviour: CullingDynamic,
  onInstanceCreation: (obj, index) => {
    obj.position.random();
    obj.scale.setScalar(2);
    obj.quaternion.random();
  }
});

scene.add(monkeys);

// How to handle instances
monkeys.instances[0].visible = false;
monkeys.instances[1].rotateOnWorldAxis(xAxis, Math.PI);
monkeys.instances[1].updateMatrix();
monkeys.instances[2].position.x += 10;
monkeys.instances[2].scale.multiplyScalar(2);
monkeys.instances[2].updateMatrix();

```

## Live Example (no frustum check)

> **[Instanced2 Basic Example (deprecated) - StackBlitz](https://stackblitz.com/edit/instancedmesh2-basic?file=src%2Fmain.ts)**
>
> A Vite TypeScript project based on @three.ez/main, three, @types/three, typescript and vite

I will make all my work public and usable by anyone, as packages with only three.js as peer dependency, and would love to receive advice.

I thank @DolphinIQ for the advice 🙂

Currently a similar version without visibility management, but with interaction events is already available in my **[three.ez](https://discourse.threejs.org/t/three-ez-library-for-events-drag-drop-binding-focus-management-smart-rendering-tweening-and-more/56007)** library.

In future posts I will explain how I plan to optimise visibility management according to the frustum of the camera and perhaps how I would like to manage `InstancedLOD`.

# Post edit:

Many things have changed since I created the post.  
The library now works more smartly: it uses an `InstancedBufferAttribute` to handle indexes to render while all instances data is stored in `DataTexture`.

## Package released

> **[GitHub - agargaro/instanced-mesh: Enhanced InstancedMesh with frustum culling, fast...](https://github.com/agargaro/instanced-mesh)**
>
> Enhanced InstancedMesh with frustum culling, fast raycasting (using a BVH), sorting, visibility, LOD, skinning and more.

[https://www.npmjs.com/package/@three.ez/instanced-mesh](https://www.npmjs.com/package/@three.ez/instanced-mesh)

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [November 27, 2023, 11:13pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/2 "2023-11-27T23:13:31Z")

</div>

> [@agargaro](#):
>
> Visibility is managed by swapping the element you wish to hide with the last one in instanceMatrix array, and decreasing the count by 1.  
> _ **This allows the hidden element not to actually be rendered.** _

Would this change the order of meshes?

- Apart from the matrices, other instance data should also be changed (e.g. colors and any custom attributes).
- In some cases I have instanced mesh accompanied by a parallel array of additional non-graphical instance data (mapped 1-to-1 to the instances data). Exchanging instances would break this mapping.

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [November 28, 2023, 12:11am UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/3 "2023-11-28T00:11:58Z")

</div>

Great observations, as usual 🙂

> [@PavelBoytchev](#):
>
> Would this change the order of meshes?

No, the **instances** array will remain the same.  
There is an internal, invisible to the user, handling of the **instanceMatrix** and **instanceColor** indexes.

```javascript
instancedMesh.instances[0].visible = false;
// instancedMesh.instances[0] is still the same element.

```

> [@PavelBoytchev](#):
>
> Apart from the matrices, other instance data should also be changed (e.g. colors and any custom attributes).

Both matrices and colors (if present) are currently swapped.  
Custom attributes may be swapped with a utility.

> [@PavelBoytchev](#):
>
> In some cases I have instanced mesh accompanied by a parallel array of additional non-graphical instance data (mapped 1-to-1 to the instances data). Exchanging instances would break this mapping.

This is even simpler.  
You don’t need an array, but to add the data to the instance.

```javascript
class Entity extends InstancedEntity {
  customData = 10;

  constructor(parent: InstancedMesh2, index: number) {
    super(parent, index);
    // set position, scale, quaternion.
  }
}

const myInstancedMesh = new InstancedMesh2(geometry, material, 1000, Entity);
myInstancedMesh.instances[0].customData = 15;

```

Do you think something can be improved?

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [November 28, 2023, 9:56am UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/4 "2023-11-28T09:56:36Z")

</div>

> [@agargaro](#):
>
> Both matrices and colors (if present) are currently swapped.  
> Custom attributes may be swapped with a utility.

Hm. Does it mean that matrices and colors are swapped internally, but the user must swap all other `THREE.InstancedBufferAttribute` arrays?

> [@agargaro](#):
>
> Do you think something can be improved?

Does it have cloning? (De-)Serialization?

Any plans to make `BatchedMesh2` over the expected `BatchedMesh`?

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [November 28, 2023, 2:24pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/5 "2023-11-28T14:24:04Z")

</div>

> [@PavelBoytchev](#):
>
> Hm. Does it mean that matrices and colors are swapped internally, but the user must swap all other `THREE.InstancedBufferAttribute` arrays?

You are right. It should be possible to swap also `InstancedBufferAttributes` without the user doing it manually.

However, geometry can no longer be shared (only if has custom attributes) and `InstancedBufferAttributes` with `meshPerAttribute` greater than 1 would not be compatible.

> [@PavelBoytchev](#):
>
> Does it have cloning? (De-)Serialization?

Right, they are methods that must be there, but I will include them at the end.

> [@PavelBoytchev](#):
>
> Any plans to make `BatchedMesh2` over the expected `BatchedMesh`?

I’m waiting for r159, but if you think it would be useful, I’ll gladly do it.

> <https://github.com/mrdoob/three.js/issues/27203>
>
> \### Description
> 
> Right now you can render a number of geometries with a single m…aterial using a BatchedMesh but you may want to swap materials of an individual mesh for things like selection, highlighting, etc. Right now that means creating and maintaining a completely different BatchedMesh which is slower and takes more memory. Instead it would be best if two BatchedMeshes could share geometry and potentially transform data so they can both specify different materials and visibility arrays.
> 
> \### Solution
> 
> I'm not exactly sure of some of the options here - but one solution is to add a "BatchedBufferGeometry" object that BatchedMesh references and stores all the geometry, draw ranges, etc. The BatchedMesh would still bookkeep the multidraw buffers, etc:
> 
> \`\`\`js
> const mesh1 = new BatchedMesh( maxGeometryCount, maxVertexCount, maxIndexCount, material1 );
> const index = mesh1.geometry.addGeometry( ... );
> mesh1.setMatrixAt( ... );
> 
> const mesh2 = new BatchedMesh( mesh1.geometry, material2 );
> 
> mesh1.setVisibilityAt( 0, false );
> mesh1.setVisibilityAt( 1, true );
> scene.add( mesh1, mesh2 );
> \`\`\`
> 
> \### Alternatives
> 
> Instead the end user could just use something like a proxy or wrapper class that forwards all common information between the BatchedMeshes while reimplementing all needed:
> 
> \`\`\`js
> const mesh1 = new BatchedMesh( ... );
> const mesh2 = new BatchedMeshWrapper( mesh1 );
> \`\`\`
> 
> Or - possibly the better approach - BatchedMesh could support different and arbitrary material properties and textures but this can get complicated. It's possible this would be best done with node materials in the future.
> 
> \### Additional context
> 
> User mentioned this need in three-mesh-bvh: https://github.com/gkjohnson/three-mesh-bvh/issues/513

I saw this issue on `BatchedMesh` and I have the impression that we are doing similar work… I’d love to talk to him.  
`InstancedMesh2` already allows you to share entities with other `InstancedMesh2` (useful for `InstancedLOD`, but needs improvements).

```javascript
  // this is still working in progress, will be easier to use
  const lod = new InstancedLOD(count)
  lod.addLevel(new THREE.IcosahedronGeometry(1.5, 16), material, 0.5);
  lod.addLevel(new THREE.IcosahedronGeometry(1.5, 8), material, 3);
  lod.addLevel(new THREE.IcosahedronGeometry(1.5, 4), material, 10);
  lod.addLevel(new THREE.IcosahedronGeometry(1.5, 2), material, 20);
  lod.addLevel(new THREE.IcosahedronGeometry(1.5, 1), material, 50);
 
  for (let i = 0; i < lod.count; i++) {
    lod._sharedData[i].position.random().multiplyScalar(1000).subScalar(500);
    lod.updateInstancedMatrix(i);
  }

```

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [November 28, 2023, 2:37pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/6 "2023-11-28T14:37:36Z")

</div>

Small experiment with `InstancedLOD` and 2kk meshes.  
This is also a favourable scenario, where 88% of the meshes were hidden thanks to the frustum control  
The goal is to try to have similar results by calling up a continuous update of distance and visibility calculation, although I don’t think it will be possible, even if @gkjohnson made me believe in magic with **three-mesh-bvh** 🥰

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/b/d/bde8d1e388aa29ab796144419f798074faa06f88.jpeg)

Little memory problem:  
 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/e/5/e52c686ea65e91d3fcc9f169f47a934e82d025d8.png)

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [December 3, 2023, 10:12am UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/7 "2023-12-03T10:12:33Z")

</div>

> [@PavelBoytchev](#):
>
> Hm. Does it mean that matrices and colors are swapped internally, but the user must swap all other `THREE.InstancedBufferAttribute` arrays?

I have prepared an example where it automatically swaps `InstancedBufferAttribute`.  
In addition, I added the possibility of passing a callback executed for all instances.

```javascript
const monkeys = new InstancedMesh2(geometry, material, 20000, (obj, index) => {
    obj.position.x += index * 5 - 20;
    obj.scale.setScalar(2);
    obj.updateMatrix();
});

```

> **[Instanced2 Custom attribute - StackBlitz](https://stackblitz.com/edit/instancedmesh2-attribute?file=src%2Fmain.ts)**
>
> A Vite TypeScript project based on @three.ez/main, three, @types/three, typescript and vite

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/5/1/512fe5eb0eb1fc1149e3d2c0c5099f60221747a9.jpeg)

Thank you very much for the advice 😃

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [December 10, 2023, 5:08pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/8 "2023-12-10T17:08:37Z")

</div>

Small update:

I wrote an algorithm to minimise the swaps made in the array to manage visibility, and implemented a first test of frustum culling.

Can you please tell me if this example (50k animated meshes) runs at 60 fps on your computers?

> **[InstancedMesh2 frustum culling - StackBlitz](https://stackblitz.com/edit/instancedmesh2-frustum-culling?file=src%2FInstancedMesh2.ts,src%2FInstancedEntity.ts,src%2Fmain.ts)**
>
> A Vite TypeScript project based on @three.ez/main, three, @types/three, typescript and vite

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/2/6/2636add8eb5eef5f439d2288e83960b5ce134769.jpeg)

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [December 10, 2023, 5:14pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/9 "2023-12-10T17:14:12Z")

</div>

Oscillates in the range of 60-62 fps.

![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/a/0/a0e77a210d1c4bf8ca3e7efdc03cf61180228b7b.png)

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [December 10, 2023, 5:19pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/10 "2023-12-10T17:19:02Z")

</div>

Thank you 🙂 Do you think this is an acceptable result? (I don’t know your monitor refresh rate 😂)

Currently a check is made on all meshes if they are inside the frustum (like BatchedMesh i think).  
This is only useful if all meshes are animated every frame, otherwise there will be a flag indicating that the scene is static and in that case I can optimise a lot thanks to a hierarchical control.

And it will also be possible to optimise this example with an InstancedLOD ofc.

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [December 10, 2023, 8:43pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/11 "2023-12-10T20:43:41Z")

</div>

The result looks nice, however … I don’t know what is acceptable. For every person it means something different (my card can reach 144 fps for simple scenes, and 60 fps for your demo).

Such performance tests are good for developers, but are not indicative for the end user … I mean, I have had many cases, when something looks fast on a demo page, but performance is notably worse when applied on a real page (with other objects, various materials, animations, effects, etc).

**Edit:**

Here is something strange. When I fly towards the most distant Suzanne, the others go outside the frustum. I expect this should increase the fps if frustum culling is active. But even when I end up with just one Suzanne, the fps is barely increased by 10% to 66 fps.

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/a/f/af8e6332d4097e9d57b7672ba2e77b012a8192a2.png)

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [December 10, 2023, 8:53pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/12 "2023-12-10T20:53:59Z")

</div>

> [@PavelBoytchev](#):
>
> Here is something strange. When I fly towards the most distant Suzanne, the others go outside the frustum. I expect this should increase the fps if frustum culling is active. But even when I end up with just one Suzanne, the fps is barely increased by 10% to 66 fps.

Probably in this case the slowness is caused by animating 50k meshes every frame.

Here is an example without animation, this one I hope doesn’t go below 144…

> **[InstancedMesh2 frustum culling no animation - StackBlitz](https://stackblitz.com/edit/instancedmesh2-frustum-culling-no-animation?file=src%2Fmain.ts)**
>
> A Vite TypeScript project based on @three.ez/main, three, @types/three, typescript and vite

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [December 10, 2023, 9:00pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/13 "2023-12-10T21:00:20Z")

</div>

Yes!

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/1/f/1f565bb01fbb2c4b5d1a617e48fa00e80c0fe74d.png)

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [December 10, 2023, 9:10pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/14 "2023-12-10T21:10:42Z")

</div>

Well this looks like a good result, thank you very much for your help! 🤩

In a few days I hope to publish some examples of the InstancedLOD class.

---

<div class="post-metadata">

**Author:** ![Harold](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/harold/32/32136_2.png) [@Harold](https://discourse.threejs.org/u/Harold)\
**Post date:** [December 10, 2023, 10:45pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/15 "2023-12-10T22:45:01Z")

</div>

![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/9/8/986571ea98d57899e0bb6a232bdfee61cb73a31f.png)

165 (my refresh rate) at 100.000 (animated) items on an RTX 2080ti.

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [December 10, 2023, 11:14pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/16 "2023-12-10T23:14:22Z")

</div>

Thanks for the test 🙂  
I think you also have a high-end cpu to generate all those frames.  
Updating 100k matrices for 165 frames is a heavy load for the cpu…

…

But it doesn’t really make sense to update the matrices of hidden objects… just like three.js does… I really need to improve this…

---

<div class="post-metadata">

**Author:** ![Harold](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/harold/32/32136_2.png) [@Harold](https://discourse.threejs.org/u/Harold)\
**Post date:** [December 10, 2023, 11:22pm UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/17 "2023-12-10T23:22:44Z")

</div>

Oh right, the CPU may have a role to play here. I’m running on an Intel I7 13700K.

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [December 11, 2023, 6:20am UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/18 "2023-12-11T06:20:15Z")

</div>

solid 144 fps on my gtx1080 when camera is in the center, and ~120 when zoomed out…

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [December 14, 2023, 12:00am UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/19 "2023-12-14T00:00:52Z")

</div>

Small update:

I optimised the update of the matrices… now only the visible instances matrices are updated.

> **[InstancedMesh2 - culling & animation - StackBlitz](https://stackblitz.com/edit/instancedmesh2-culling-animation?file=src%2Fmain.ts)**
>
> A Vite TypeScript project based on @three.ez/main, three, @types/three, typescript and vite

@PavelBoytchev Now you will probably make more fps even with animated instances 🙂

---

<div class="post-metadata">

**Author:** ![agargaro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/agargaro/32/35529_2.png) [@agargaro](https://discourse.threejs.org/u/agargaro)\
**Post date:** [February 13, 2024, 12:04am UTC](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622/20 "2024-02-13T00:04:27Z")

</div>

After a break, I resumed work on this class.

I implemented optimisations on static instancedMesh (without animations) using a bvh and Hierarchical Culling.  
There are still things to improve but it is a good start.

> **[InstancedMesh2 - culling with BVH - StackBlitz](https://stackblitz.com/edit/instancedmesh2-culling-with-bvh?file=src%2Fmain.ts)**
>
> A Vite TypeScript project based on @three.ez/main, three, @types/three, typescript and vite

Without a LOD the gpu works too hard, so that will be the next step.

Can someone test it and tell me the fps, to see if there is any improvement compared to the last example? Thank you.

[Next page](https://discourse.threejs.org/t/instancedmesh2-easy-handling-and-frustum-culling/58622.md?page=2)
