指针事件未在反应三纤维中触发
Pointer events not firing in react-three-fiber
我正在尝试使用 GLTFJSX 将指针事件添加到在 react-three-fiber 中加载的 GLTF 文件。但是,指针事件没有触发,我不明白为什么。
我已经尝试将相同的事件添加到其他类似的代码沙箱中,而且它起作用了——那么为什么它在这个例子中不起作用,如果我做的基本上是一样的?
https://codesandbox.io/s/hopeful-brook-h8rhs?file=/src/App.js
- 预期行为:当您将鼠标悬停在模型上或单击它时,它应该被记录到控制台。
- 实际行为:只有
onPointerMissed
事件会触发。
有时,onPointerOver
和 onPointerOut
事件确实有效。这似乎随机起作用 — 有时它起作用,但大多数时候它不起作用。
我是不是遗漏了什么明显的东西?
编辑
更改为mesh
时,指针事件起作用。所以这个问题与 skinnedMesh
没有检测到指针事件直接相关。
问题是SkinnedMesh
修改了显卡(GPU)中的顶点位置,所以JavaScript端在执行hit-test时不知道顶点已经移动(也称为光线投射)。看看下面的截图:
网格:
当您使用 Mesh
时,顶点显示在 geometry.attributes.position
指示的位置。形状很小而且很远,但是您的鼠标事件按预期工作。
蒙皮网格:
当您使用 SkinnedMesh
时,顶点在 GPU 中被平移得更近,但光线投射计算仍然使用原始 geometry.attributes.position
坐标来执行命中测试。这就是为什么您只能在红色框内非常小的区域内获得预期的鼠标事件。
解决方案:
解决方案因您的用例而异,但您可以执行以下任一操作:
- 使用
Mesh
,并更新 mesh.position
属性 使其更靠近相机。
- 如果你需要
SkinnedMesh
,尽量保持骨骼位移足够小,这样它们的蒙皮位置就不会偏离它们原来的位置太远。
- 您可以创建一个不可见的“点击框”,然后将鼠标事件添加到其中。这是大多数游戏开发人员使用的方法,因为它可以更快地针对非常简单的几何图形计算命中测试:
var hitGeom = new THREE.BoxBufferGeometry(1, 1, 1);
var hitMat = new THREE.MeshBasicMaterial({visible: false});
// ...
<mesh geometry={hitGeom} material={hitMat}>
我正在尝试使用 GLTFJSX 将指针事件添加到在 react-three-fiber 中加载的 GLTF 文件。但是,指针事件没有触发,我不明白为什么。
我已经尝试将相同的事件添加到其他类似的代码沙箱中,而且它起作用了——那么为什么它在这个例子中不起作用,如果我做的基本上是一样的?
https://codesandbox.io/s/hopeful-brook-h8rhs?file=/src/App.js
- 预期行为:当您将鼠标悬停在模型上或单击它时,它应该被记录到控制台。
- 实际行为:只有
onPointerMissed
事件会触发。
有时,onPointerOver
和 onPointerOut
事件确实有效。这似乎随机起作用 — 有时它起作用,但大多数时候它不起作用。
我是不是遗漏了什么明显的东西?
编辑
更改为mesh
时,指针事件起作用。所以这个问题与 skinnedMesh
没有检测到指针事件直接相关。
问题是SkinnedMesh
修改了显卡(GPU)中的顶点位置,所以JavaScript端在执行hit-test时不知道顶点已经移动(也称为光线投射)。看看下面的截图:
网格:
当您使用 Mesh
时,顶点显示在 geometry.attributes.position
指示的位置。形状很小而且很远,但是您的鼠标事件按预期工作。
蒙皮网格:
当您使用 SkinnedMesh
时,顶点在 GPU 中被平移得更近,但光线投射计算仍然使用原始 geometry.attributes.position
坐标来执行命中测试。这就是为什么您只能在红色框内非常小的区域内获得预期的鼠标事件。
解决方案:
解决方案因您的用例而异,但您可以执行以下任一操作:
- 使用
Mesh
,并更新mesh.position
属性 使其更靠近相机。 - 如果你需要
SkinnedMesh
,尽量保持骨骼位移足够小,这样它们的蒙皮位置就不会偏离它们原来的位置太远。 - 您可以创建一个不可见的“点击框”,然后将鼠标事件添加到其中。这是大多数游戏开发人员使用的方法,因为它可以更快地针对非常简单的几何图形计算命中测试:
var hitGeom = new THREE.BoxBufferGeometry(1, 1, 1);
var hitMat = new THREE.MeshBasicMaterial({visible: false});
// ...
<mesh geometry={hitGeom} material={hitMat}>