react-three-fiber: 如何在<Canvas />中的任何地方捕获事件?

huangapple go评论75阅读模式
英文:

react-three-fiber: How to capture events ANYWHERE in <Canvas />?

问题

我正在尝试使用react-three-fiber创建一个3D体验,在这个体验中用户可以与3D画布的任何部分进行交互,包括与物体相交的画布上的点,以及射线上没有任何交点的点。

这意味着我不能使用内置在<mesh />等元素中的指针事件抽象,因为这些指针事件仅捕获与物体相交的点。

我尝试将处理程序附加到<Canvas onMouseDown={...} />,但是我无法从那里访问THREE的内部,因为由onMouseDown传递的event不包含它们,并且useThree钩子必须在树中更深层次才能访问THREE的React上下文。

所以我还尝试创建一个嵌套在<Canvas />内的组件(如下所示),在那里我可以使用useThree钩子:

<Canvas>
  <MouseHandler>
    ...
    <mesh />
    ...
  </MouseHandler>
</Canvas>

export function MouseHandler({ children }) {
   const { Camera } = useThree()
   return <Html><div onMouseDown={...}>{children}</div></Html>
}

...但是然后react-three-fiber会抱怨我在HTML对象内有THREE对象。

有没有其他方法可以解决这个问题的建议?

英文:

I'm trying to create a 3D experience using react-three-fiber where the user can interact with any part of the 3D canvas, including points on the canvas that both (a) intersect an object, and (b) where there is nothing intersecting the ray at all.

This means I can't use the pointer events abstractions built into &lt;mesh /&gt; etc., as those pointer events ONLY capture points that intersect objects.

I tried attaching handlers to the &lt;Canvas onMouseDown={...} /&gt;, however I'm unable to access the THREE internals from there as the event passed by onMouseDown does not contain them, and the useThree hook must be deeper in the tree to access the THREE react context.

So I also tried creating a component nested inside &lt;Canvas /&gt; (see below) where I'd be able to use the useThree hook:

&lt;Canvas&gt;
  &lt;MouseHandler&gt;
    ...
    &lt;mesh /&gt;
    ...
  &lt;/MouseHandler&gt;
&lt;/Canvas&gt;

export function MouseHandler({ children }) {
   const { Camera } = useThree()
   return &lt;Html&gt;&lt;div onMouseDown={...}&gt;{children}&lt;/div&gt;&lt;/Html&gt;
}

...but then react-three-fiber complains that I have THREE objects inside HTML objects.

Anyone have any suggestions on how else I might be able to solve this?

答案1

得分: 0

这似乎不是react-three-fiber通常支持的用例,所以我最终采取了以下方法来处理,使用React Refs从树的深层中提取我需要的三维对象的"指针"。

const threeRef = useRef()

<MouseHandler threeRef={threeRef}>
  <Canvas>
    <ThreeConnect threeRef={threeRef}>
      ...
      <mesh />
      ...
    </ThreeConnect>
  </Canvas>
</MouseHandler>

...

export function MouseHandler({ threeRef, children }) {
   const { Camera } = threeRef.current
   return <Html><div onMouseDown={...}>{children}</div></Html>
}

...

export default function ThreeConnect({ children, threeRef }) {
  const { scene, camera } = useThree()

  useEffect(() => {
    threeRef.current = {
      ...threeRef.current,
      camera,
      scene,
    }
  }, [scene, camera])

  return <>{children}</>
}

希望这对你有所帮助。

英文:

Doesn't feel like a common enough use case that react-three-fiber would ever support, so what I ended up doing was hack it like this, using React Refs to yank a "pointer" to the three objects I needed from deeper into the tree.

const threeRef = useRef()

&lt;MouseHandler threeRef={threeRef}&gt;
  &lt;Canvas&gt;
    &lt;ThreeConnect threeRef={threeRef}&gt;
      ...
      &lt;mesh /&gt;
      ...
    &lt;/ThreeConnect&gt;
  &lt;/Canvas&gt;
&lt;/MouseHandler&gt;

...

export function MouseHandler({ threeRef, children }) {
   const { Camera } = threeRef.current
   return &lt;Html&gt;&lt;div onMouseDown={...}&gt;{children}&lt;/div&gt;&lt;/Html&gt;
}

...

export default function ThreeConnect({ children, threeRef }) {
  const { scene, camera } = useThree()

  useEffect(() =&gt; {
    threeRef.current = {
      ...threeRef.current,
      camera,
      scene,
    }
  }, [scene, camera])

  return &lt;&gt;{children}&lt;/&gt;
}

答案2

得分: 0

你可以将行为附加到网格对象的onPointerMissed属性上,附加的处理程序将在画布上引发的与该网格不相交的事件时触发。

处理程序将接收到一个PointerEvent,其中有一个pointerId属性,但不会有一个eventObject属性。

因此,如果你可以在所有物体周围放置一个外部网格,并将行为附加到其opPointerMissed属性,那么你将处理场景中未被任何对象捕获的任何点击事件。

英文:

You can attach behavior to the onPointerMissed prop of a mesh object, and the attached handler will fire whenever an event is raised on that canvas that does not intersect with that mesh.

The handler will receive a PointerEvent, having a pointerId property, though it will not have an eventObject property.

So if you could somehow afford to have an outer mesh around everything, and attach behavior to its opPointerMissed prop, then you'd handle any click that wasn't caught by any of the objects in the scene.

答案3

得分: -1

需要在<mesh>中添加onMouseDown以捕获与对象相交的点。
并在<Canvas>中添加onPointerMissed以捕获未与任何对象相交的情况。

英文:

You need add onMouseDown in &lt;mesh&gt; for capture points that intersect objects.
And add onPointerMissed in &lt;Canvas&gt; for capture nothing intersecting.

huangapple
  • 本文由 发表于 2023年2月10日 10:59:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75406519.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定