Lerping camera and lookAt together with dynamic taret (React three fiber)

(I’ve asked this same question on stackOverflow, but just found this site & thought it might make more sense here. I hope that’s not against any rules. Original post here - Any answer gotten once place will be added/linked in the other.)

I am trying to transition camera.position and camera.lookAt smoothly between “zoomed out” and “zoomed in” views of individual, randomly placed objects.

The positioning works great. Lerping the lookAt(), however, doesn’t seem to be playing nicely with other solutions for traditional ThreeJS ( see @bovesan’s answer here) nor addressed by the relevant example on the react-three-fiber docs (link).

Zooming in past the z axis flips the camera around, and at the corners it’s wildly distored.

You can see my progress here : three-fiber-zoom-to-object - CodeSandbox

With the relevant bit of code being in App.js on line 63 :

 useFrame((state) => {
    const step = 0.05;

    // `focus` is a state variable that sends a Vec3 of the objects position
    zoom ? vec.set(focus.x, focus.y, focus.z + 0.2) : vec.set(0, 0, 5);

    // HERE, looking for a way to lerp camera lookAt in a way that can toggle.
    state.camera.lookAt(0, 0, 0);
    state.camera.position.lerp(vec, step);


I’ve spent hours looking for relevant examples/tutorials, but haven’t come up with much. I’m afraid I don’t have enough ThreeJs experience to be looking in the right direction, though, so any help in any direction would be most welcome.

Essentially you want to do the same as you have for the camera position but with a ghost object, you can lerp the position of the ghost object and do camera.lookAt(ghostObject.position.x, ghostObject.position.y, ghostObject.position.z) if that helps?

1 Like

I’d recommend using Yomutsu’s camera controls whenever you need to animate the camera. It’s an improved version of OrbitControls with functions for transitioning the camera.

You probably want to use setLookAt to animate to a new position:

controls.setLookAt( positionX, positionY, positionZ, targetX, targetY, targetZ, true)

Thank you @forerunrun ! This works great. I’m having a little difficulty figuring out how to create just a transparent material ( three-fiber-zoom-to-object - ghost solution - CodeSandbox ) but I’m sure that’ll end up being a much easier question. Thanks again.

1 Like

@looeee This looks super neat, but I’m afraid I don’t have the chops to use it with Three Fiber. Thank you for the recommend, though. That will definitely feature in future projects.

really there’s no big deal in using anything 3rd party for three in r3f: yomotsu camera-controls - CodeSandbox it’s the exact same thing, you only categorize it into side-effects and render-loop updates. you can optionally extend the jsx and “render” the control, or create it imperatively in a useMemo if you want.

function Controls() {
  const ref = useRef()
  const camera = useThree((state) => state.camera)
  const gl = useThree((state) => state.gl)
  useFrame((state, delta) => ref.current.update(delta))
  return <cameraControls ref={ref} args={[camera, gl.domElement]} />

<Controls />

For the record, that would work like this:

function Controls() {
  const camera = useThree((state) => state.camera)
  const gl = useThree((state) => state.gl)

  const controls = useMemo(() => {
     return new CameraControls(camera, gl.domElement);
   }, []);

  useFrame((state, delta) => controls.update(delta))

  return null;

<Controls />

Thanks @drcmda for the confirmation, and @looeee for the implementation! Please forgive the newbishness here, but I’m placing the <Controls /> in the <Canvas/> in the same way I had been doing with <OrbitControls/>, and am running up against a Cannot read property 'handlers' of undefined error. I’m assuming the request to change camera position should be inside the useFrame … is that correct? (Currently working off a fork of the original sandbox : Line 77 @ three-fiber-zoom-to-object - camera-controls solution - CodeSandbox )

Thank you for your help!

So … I’ve run in to a strange error with the ghost solution as well, and it has me absolutely perplexed : it works perfectly only after I’ve hotfixed the code. On initial load the lookatAt doesn’t work, but if I add something to the code - doesn’t matter what it is - it works beautifully. I’m afraid I don’t know enough about how Three is wired to know where to look for answers. Any nudges in any direction would be appreciated - thank you! ( Demo of the issue here : three-fiber-zoom-to-object - ghost solution - CodeSandbox )

you can’t do this:

function Foo() {
  function Bar() { ... }
  return <Bar />

i mean you can, but it makes no sense, Bar will be a new component every time Foo renders, so it will mount/unmount every time and loose its data. you even have hooks in there, they are futile. this usually leads to strange errors and race conditions. rule of thumb: never define a component in function scope.

Here’s the fixed version: three-fiber-zoom-to-object - camera-controls solution (forked) - CodeSandbox

ps. you’re not using instanced mesh correctly, you can’t just dump THREE.Mesh objects into THREE.InstancedMesh. this is how it works: Instances - CodeSandbox

1 Like

@drcmda Ah ha! Ok, your point re: nesting makes a lot of sense. (Things I should have realized years ago :roll_eyes:). Re: the instancing, I spent a lot of time with those examples (this little demo of mine was originally based off of Instanced vertex-colors - CodeSandbox ) but came away with only the roughest idea of what was actually going on under the hood. I’m clearly missing something essential there & will do some more research.

Also thanks for the improved example! This makes much more sense. Now the lookAt seems to work but the setPosition has gone all wonky - I’ll sit with it later today and see if I can figure out what’s going on.

i did took out some blob of code about position where i didn’t know what it was for. as for instanced-mesh, that’s a little bit harder to use but you get used to it once you understand this setMatrixAt stuff.

1 Like

For anyone happening upon this later on, you can find a working example here :

Solution : three-fiber-zoom-to-object - camera-controls solution - final - CodeSandbox

This is just a slight change on @drcmda 's implementation of camera-controls with normal lerping to move the camera. It’s not perfect (for one, the transition time in camera controls doesn’t seem to be editable, so there’s a weird swing-around thing that happens, when you’re zooming back out) but it definitely solves the problem. (Many thanks to @looeee and @forerunrun for additional help.)

1 Like