1

I'm trying to pin a drei Html element to the top left corner. I'm struggeling with getting it to stay in the same location when rotating or moving the camera. This is my current attempt:

  const { mouse2D, mouse3D, normal, plane } = useMemo(() => {
    return {
      mouse2D: new THREE.Vector2(),
      mouse3D: new THREE.Vector3(),
      normal: new THREE.Vector3(),
      plane: new THREE.Plane(),
    };
  }, []);

  const { width, height } = useWindowDimensions();

  useFrame(({camera, raycaster, size}) => {
    mouse2D.set(((0.02 * width) / size.width) * 2 - 1, ((-0.02 * height) / size.height) * 2 + 1);
    raycaster.setFromCamera(mouse2D, camera);
    camera.getWorldDirection(normal).negate();
    plane.setFromNormalAndCoplanarPoint(normal, mouse3D);
    raycaster.ray.intersectPlane(plane, mouse3D);
  });

  return <Html position={[mouse3D.x, mouse3D.y, mouse3D.z]}>stuff</Html>;

The Html position updates correctly on window resize but it doesn't update on camera rotation or camera moving. Anyone got any idea how to solve this?

Timmotoo
  • 71
  • 2
  • 6

1 Answers1

0

If anyone is interested this is my current solution:

const { viewport } = useThree();

const groupRef = useRef<THREE.Group>(null!);
  useEffect(() => {
    const groupRefCopy = groupRef.current;
    camera.add(groupRefCopy);
    return () => {
      camera.remove(groupRefCopy);
    };
  }, [camera, groupRef.current]);

  return (
    <group ref={groupRef} position={[-viewport.width / 3.5, viewport.height / 3.8, -5]} rotation={[0, 0, 0]}>
      <Html style={{ opacity: show ? 1 : 0, width: menuWidth, userSelect: "none", pointerEvents: show? "auto" : "none" }}>
         {...}
      </Html>
    </group>
  );

3.5 and 3.8 works very well for my scene. If anyone knows how to get these constants dynamically from 3JS, please comment!

Timmotoo
  • 71
  • 2
  • 6