Cécile Lebleu
Cécile Lebleu

Reputation: 196

Pointer events not firing in react-three-fiber

I'm trying to add pointer events to a GLTF file loaded in react-three-fiber using GLTFJSX. However, the pointer events don't fire, and I can't figure out why.

I have tried adding the same events into other similar code sandboxes, and it works — so why wouldn't it work in this example, if I'm doing basically the same thing?

https://codesandbox.io/s/hopeful-brook-h8rhs?file=/src/App.js

Sometimes, the onPointerOver and onPointerOut events do work. This seems to work at random — sometimes it works, but most of the time it just doesn't.

Am I missing something obvious?

Edit

When changed to mesh, the pointer events work. So the issue is related directly to skinnedMesh not detecting pointer events.

Upvotes: 2

Views: 4136

Answers (1)

M -
M -

Reputation: 28472

The problem is that SkinnedMesh modifies the vertex positions in the graphics card (GPU), so the JavaScript side doesn't know that the vertices have been moved when performing the hit-test (also known as Raycasting). Take a look at the screenshots below:

Mesh:

When you use Mesh, the vertices show up where geometry.attributes.position indicates. The shape is small and far away, but your mouse-events work as expected. enter image description here

SkinnedMesh:

When you use SkinnedMesh, the vertices are translated in the GPU to be much closer, but the raycasting calculation still uses the original geometry.attributes.position coordinates to perform the hit-test. That's why you only get the expected mouse events in a very small area inside the red box. enter image description here

Solutions:

The solution varies based on your use-case but you could do any of the following:

  1. Use Mesh, and update the mesh.position property to move it closer to the camera.
  2. If you need SkinnedMesh, try to keep the skeleton displacements small enough so their skinned positions don't deviate far from their original positions.
  3. You could create an invisible "hitbox" and just add the mouse events to that. This is what most game developers use because it's faster to calculate hit-tests against a very simple geometry:
var hitGeom = new THREE.BoxBufferGeometry(1, 1, 1);
var hitMat = new THREE.MeshBasicMaterial({visible: false});
// ...
<mesh geometry={hitGeom} material={hitMat}>

Upvotes: 2

Related Questions