# Sprite occlusion using raycaster - works but not performant

**URL:** <https://discourse.threejs.org/t/sprite-occlusion-using-raycaster-works-but-not-performant/68585>\
**Category:** Questions\
**Tags:** raycaster, three-mesh-bvh\
**Created:** [July 25, 2024, 8:44pm UTC](https://discourse.threejs.org/t/sprite-occlusion-using-raycaster-works-but-not-performant/68585 "2024-07-25T20:44:15Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![LeeMcA](https://avatars.discourse-cdn.com/v4/letter/l/ec9cab/32.png) [@LeeMcA](https://discourse.threejs.org/u/LeeMcA)\
**Post date:** [July 25, 2024, 8:44pm UTC](https://discourse.threejs.org/t/sprite-occlusion-using-raycaster-works-but-not-performant/68585/1 "2024-07-25T20:44:15Z")

</div>

I have a group, which contains a GLTF and a number of sprites. I want to know which sprites are occluded by the model on each frame that the camera moves.

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

I have this working but it’s not very performant. In the screenshot above you can see that 1 is not occluded but 2 and 3 are - so they have their opacity adjusted.

To achieve this I loop through each sprite (only the ones not frustrum culled) and raycast from the camera to the sprite. If the sprite is the first intersect then I class it as non-occluded:

```javascript
sprites.forEach((sprite) => {

  sprite.getWorldPosition(spriteWorldPosition);
  let vector = spriteWorldPosition.project(camera);

  raycaster.setFromCamera(new THREE.Vector2(vector.x, vector.y), camera);

  let intersects = raycaster.intersectObject(group, true);

  if (intersects.length > 0 && intersects[0].object === sprite) {
      // occluded = false;
  } else {
      // occluded = true;
  }

});

```

Is there something I can do to make this more performant?

I’ve tried using three-mesh-bvh but I don’t think I’m fully grasping it, as it seems to make no difference:

In the GLTF loader:

```javascript
mesh.traverse((child) => {
    if (child.isMesh) {
        const geometry = child.geometry;
        const bvh = new MeshBVH(geometry);
        geometry.boundsTree = bvh;
    }
});

```

And I’ve also set the following:

```javascript
THREE.Mesh.prototype.raycast = acceleratedRaycast;
const raycaster = new THREE.Raycaster();
raycaster.firstHitOnly = true;

```

Any help appreciated!

---

<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:** [July 25, 2024, 9:23pm UTC](https://discourse.threejs.org/t/sprite-occlusion-using-raycaster-works-but-not-performant/68585/2 "2024-07-25T21:23:11Z")

</div>

If you’re gonna be doing lots of raycasts per frame, I can hiiiighly recommend using three-mesh-bvh on your scene to accelerate the raycasts.  
Built in raycasting falls over when your meshes are even moderately dense and just throwing three-mesh-bvh at it makes raycasting basically instantaneous.

```javascript

import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast } from 'three-mesh-bvh';

// Add the extension functions
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
THREE.Mesh.prototype.raycast = acceleratedRaycast;

... and when you load your meshes:

mesh.geometry.computeBoundsTree();

```

And now you can go crazy(er) with the raycasting.  
(bvh imposes some limitations but its so worth it in terms of what it unlocks)

> **[GitHub - gkjohnson/three-mesh-bvh: A BVH implementation to speed up raycasting and...](https://github.com/gkjohnson/three-mesh-bvh)**
>
> A BVH implementation to speed up raycasting and enable spatial queries against three.js meshes.

---

<div class="post-metadata">

**Author:** ![LeeMcA](https://avatars.discourse-cdn.com/v4/letter/l/ec9cab/32.png) [@LeeMcA](https://discourse.threejs.org/u/LeeMcA)\
**Post date:** [July 25, 2024, 9:39pm UTC](https://discourse.threejs.org/t/sprite-occlusion-using-raycaster-works-but-not-performant/68585/3 "2024-07-25T21:39:13Z")

</div>

I might be being dumb here, but to get three-mesh-bvh working with a glTF would I do this?

```javascript
model.traverse((child) => {
    if (child.isMesh) {
        child.geometry.computeBoundsTree();
    }
});

```

As soon as I loop through the sprites and raycast for each one my framerate drops to 10-15 fps. So I think I’m probably missing something obvious.

---

<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:** [July 27, 2024, 5:55am UTC](https://discourse.threejs.org/t/sprite-occlusion-using-raycaster-works-but-not-performant/68585/4 "2024-07-27T05:55:00Z")

</div>

Would this idea work for you (no raycasting):  
[https://codepen.io/boytchev/pen/QWJOBrL](https://codepen.io/boytchev/pen/QWJOBrL)

The full discussion is here:

> [@A better method for rendering sprites semi-opaque when behind a model?](https://discourse.threejs.org/t/a-better-method-for-rendering-sprites-semi-opaque-when-behind-a-model/53694):
>
> I am looking to set sprites into a semi-opaque state when they’re behind a model. I have (a very slow) method which compares the distance from the camera to each sprite in the scene vs the distance from the camera to the model intersection (using the raycaster) to change the opacity of the sprites. If the sprite distance is shorter than the model distance, the sprite stays fully visible, otherwise the sprite is made sightly transparent because the model is closer in the line-of-sight. This meth…

---

<div class="post-metadata">

**Author:** ![drcmda](https://avatars.discourse-cdn.com/v4/letter/d/91b2a8/32.png) [@drcmda](https://discourse.threejs.org/u/drcmda)\
**Post date:** [July 27, 2024, 7:48am UTC](https://discourse.threejs.org/t/sprite-occlusion-using-raycaster-works-but-not-performant/68585/5 "2024-07-27T07:48:17Z")

</div>

nice trick, depthTest … how do people come up with these things!
