Skip to content

Look At Mouse

Working Example

<>

Description

The example takes the current mouse position on the screen and causes all Box components to look at that position.

See the useFrame function in ./src/Box.jsx. The current mouse position is factored against the viewport height and width, then the ref uses its Object3D.lookAt() method to look at a position somewhere between the components current position and the cameras position.

Also see that the cameras own Object3D.lookAt() method is also used in the useFrame in ./src/App.jsx to keep the center of the scene centered in the viewport.

./src/App.jsx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { Canvas, useThree, useFrame } from '@react-three/fiber'
import Box from './Box'
import { Stats } from '@react-three/drei'
import { Vector3 } from 'three'

function Rig() {
  const { camera, mouse } = useThree()
  const vec = new Vector3()

  return useFrame(() => {
    camera.position.lerp(vec.set(mouse.x, mouse.y, camera.position.z), 0.05)
    camera.lookAt(0, 0, 0)
  })
}

export default function App() {
  return (
    <Canvas camera={{ position: [0, 0, 6] }}>
      <directionalLight position={[0, 0, 1]} />
      {[...Array(5).keys()].map((i) => (
        <group key={i * 6}>
          <Box position={[-5, -3 + i * 1.5, 0]} text={'S'} />
          <Box position={[-3, -3 + i * 1.5, 0]} text={'B'} />
          <Box position={[-1, -3 + i * 1.5, 0]} text={'C'} />
          <Box position={[1, -3 + i * 1.5, 0]} text={'O'} />
          <Box position={[3, -3 + i * 1.5, 0]} text={'D'} />
          <Box position={[5, -3 + i * 1.5, 0]} text={'E'} />
        </group>
      ))}
      <Rig />
      <Stats />
    </Canvas>
  )
}

./src/Box.jsx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { useRef, useState, useMemo } from 'react'
import { useFrame } from '@react-three/fiber'
import { Color } from 'three'
import { Text } from '@react-three/drei'

export default function Box({ text, ...props }) {
  const ref = useRef()
  const black = useMemo(() => new Color('black'), [])
  const lime = useMemo(() => new Color('lime'), [])
  const [hovered, setHovered] = useState(false)

  useFrame(({ mouse, viewport }) => {
    const x = (mouse.x * viewport.width) / 2.5
    const y = (mouse.y * viewport.height) / 2.5
    ref.current.lookAt(x, y, 1)
    ref.current.material.color.lerp(hovered ? lime : black, 0.05)
  })

  return (
    <mesh
      {...props}
      ref={ref}
      onPointerOver={() => setHovered(true)}
      onPointerOut={() => setHovered(false)}
    >
      <boxGeometry />
      <meshStandardMaterial color={lime} />
      <Text fontSize={0.5} position-z={0.501}>
        {text}
      </Text>
      {props.children}
    </mesh>
  )
}
Object3D.lookAt threejs.org

GitHub Branch

git clone https://github.com/Sean-Bradley/React-Three-Fiber-Boilerplate.git
cd React-Three-Fiber-Boilerplate
git checkout lookAtMouse
npm install
npm start

Comments