1

I'm trying to use Orbitcontrols in combination with react spring to animate my camera in React Three Fiber. This is my approach so far:

function Controls({ cameraData, duration }) {
  const [orbit, setOrbit] = useState(true);
  const [target, setTarget] = useState(cameraData.lookAt);
  const { gl, camera } = useThree();

  const springProps = useSpring({
    config: { duration: duration ? duration : 1000, easing: easings.easeCubic },
    from: {
      x: camera.position.x - 0.1,
      y: camera.position.y - 0.1,
      z: camera.position.z - 0.1,
      lookAtX: camera.lookAt.x - 0.1,
      lookAtY: camera.lookAt.y - 0.1,
      lookAtZ: camera.lookAt.z - 0.1,
    },
    to: {
      x: cameraData.position[0],
      y: cameraData.position[1],
      z: cameraData.position[2],
      lookAtX: cameraData.lookAt[0],
      lookAtY: cameraData.lookAt[1],
      lookAtZ: cameraData.lookAt[2],
    },
    onStart: (ya) => {
      setOrbit(false);
    },
    onRest: (ya) => {
      setOrbit(true);
      setTarget(cameraData.lookAt)
    },
  });

  useFrame((state, delta) => {
    if (!orbit) {
      camera.position.x = springProps.x.animation.values[0]._value;
      camera.position.y = springProps.y.animation.values[0]._value;
      camera.position.z = springProps.z.animation.values[0]._value;
      camera.lookAt(
        springProps.lookAtX.animation.values[0]._value,
        springProps.lookAtY.animation.values[0]._value,
        springProps.lookAtZ.animation.values[0]._value
      );
    }
  });

  return (
    <OrbitControls
      enabled={orbit}
      target={target}
      args={[camera, gl.domElement]}
    />
  );
}

I disable OrbitControls when my Spring starts. Everything works. But: When using OrbitControl my camera position changes. After that, when I start my Spring Animation the 'from' values are not updated.

For example I tween from x: 100 to x: 500. Then Rotate my Camera via OrbitControls to x: 700. When I start my next Spring Animation it animates starting from x: 500 instead of x: 700.

How can I update my from values.

Thanks in regard

tinytree
  • 1,009
  • 2
  • 12
  • 28

1 Answers1

2

It seems there are several conversations around not animating the camera such as the one found at https://github.com/pmndrs/react-three-fiber/discussions/505#discussioncomment-3120683 I post there an approach I did using someone else idea to animate the composition and make the illusion of a camera animation, that mindset shift can be the key for this use case.

Basically you have a wrapper that moves the entire composition to the focus of the screen to pretend the camera has moved.

The main part is the component below:

const AnimatedGroup = ({ children }: { children: React.ReactNode }) => {
  const [focusPoint, setFocusPoint] = useState({
    from: [0, -3, -100],
    to: [0, 0, 0],
  })
  const { position } = useSpring({
    position: focusPoint.to,
    from: { position: focusPoint.from },
  })
  const newPosition = position as unknown as Vector3

  const handleOnClick = (e: ThreeEvent<MouseEvent>) => {
    const objectPosition = e.object.position.toArray()
    const newFocusPoint = {
      from: [focusPoint.to[0], focusPoint.to[1], focusPoint.to[2]],
      to: [objectPosition[0] * -1, objectPosition[1], objectPosition[2] * -1],
    }
    if (!e.object.userData.pitstopVariant) return

    setFocusPoint(newFocusPoint)
  }

  return (
    <animated.group position={newPosition} onClick={handleOnClick}>
      {children}
    </animated.group>
  )
}
Alexis Duran
  • 620
  • 14
  • 28