Search code examples
javascriptmapboxmapbox-gl-jsturfjslerp

Using Lerp Function To Make Smooth MapBox Camera Movements Using MapBox's FreeCameraApi


I'm following this tutorial tutorial for route animations.

So far I did everything like it's told there. Everything works same as in the tutorial. But only problem with my animation is smoothnes of camera movements.

If you go to the link and scroll down a bit you'll see title saying 'SMOOTHING THINGS OUT WITH LERP' which is the point I'm confused. Under this title showing two videos which is showing the difference lerp function make. Since I'm confused I couldn't added lerp function so my camera makes sharp movements.

I have array of coordinates for drawing the polyline but when I use the same coordinates camera makes annoying sharp movement. I should probably pass this coordinates through lerp function thus I'll get new positions for my camera which is makes smooth moves.

const targetRoute = [[6.56158, 46.05989],[6.56913, 46.05679], ...]

const routeDistance = turf.lineDistance(turf.lineString(targetRoute));

const alongRoute = turf.along(
turf.lineString(targetRoute),
routeDistance * phase
).geometry.coordinates;

// calculate the distance along the path based on the animationPhase
const[lng, lat] = turf.along(path, pathDistance * animationPhase).geometry
    .coordinates;

const bearing = -180 - animationPhase * 150.0;
const cameraAltitudr=2000

const computeCameraPosition = (
 pitch,
 bearing,
 targetPosition,
 altitude
) => {
 var bearingInRadian = bearing / 57.29;
 var pitchInRadian = (90 - pitch) / 57.29;
 
 var lngDiff =
   ((altitude / Math.tan(pitchInRadian)) *
     Math.sin(-bearingInRadian)) /
   70000; // ~70km/degree longitude
 var latDiff =
   ((altitude / Math.tan(pitchInRadian)) *
     Math.cos(-bearingInRadian)) /
   110000 // 110km/degree latitude
 
 var correctedLng = targetPosition.lng + lngDiff;
 var correctedLat = targetPosition.lat - latDiff;
 
 const newCameraPosition = {
   lng: correctedLng,
   lat: correctedLat
 };
 
 return newCameraPosition

    const camera = map.getFreeCameraOptions()
      // set the positionthe camera
      camera.position = mapboxgl.MercatorCoordinate.fromLngLat(
computeCameraPosition(76, bearing, alongRoute, cameraAltitude),
cameraAltitude
);
 
// tell the camera to look at a point along the route
camera.lookAtPoint({
lng: alongRoute[0],
lat: alongRoute[1]
});
 
map.setFreeCameraOptions(camera);

How can I add Lerp function to my animation?


Solution

  • I am the author of the tutorial above. If you look at this file in the source code, you will see the same computeCameraPosition() function but with the lerp function used to smooth the movement.

    // amazingly simple, via https://codepen.io/ma77os/pen/OJPVrP
    function lerp(start, end, amt) {
      return (1 - amt) * start + amt * end
    }
    
    const computeCameraPosition = (
      pitch,
      bearing,
      targetPosition,
      altitude,
      smooth = false
    ) => {
      var bearingInRadian = bearing / 57.29;
      var pitchInRadian = (90 - pitch) / 57.29;
    
      var lngDiff =
        ((altitude / Math.tan(pitchInRadian)) *
          Math.sin(-bearingInRadian)) /
        70000; // ~70km/degree longitude
      var latDiff =
        ((altitude / Math.tan(pitchInRadian)) *
          Math.cos(-bearingInRadian)) /
        110000 // 110km/degree latitude
    
      var correctedLng = targetPosition.lng + lngDiff;
      var correctedLat = targetPosition.lat - latDiff;
    
      const newCameraPosition = {
        lng: correctedLng,
        lat: correctedLat
      };
    
      if (smooth) {
        if (previousCameraPosition) {
          const SMOOTH_FACTOR = 0.95
          newCameraPosition.lng = lerp(newCameraPosition.lng, previousCameraPosition.lng, SMOOTH_FACTOR);
          newCameraPosition.lat = lerp(newCameraPosition.lat, previousCameraPosition.lat, SMOOTH_FACTOR);
        }
      }
    
      previousCameraPosition = newCameraPosition
    
      return newCameraPosition
    };