如何为路线跟踪场景设置动画

Mapboxで映画のようなルートアニメーションを作る

每个人都在 Mapbox 等上发推文。环法自行车赛你看过介绍每个阶段的动画视频吗?
平滑的摄像机移动、卫星图像和 3D 地形有助于让观众沉浸其中,并轻松了解运动员将克服的海拔差异和距离。

今天第17阶段@LeTour进入比利牛斯山脉,戏剧性地攀登到詹姆斯邦德电影《明日不死》中的一个高海拔机场。#TDF2022 皮c。山雀河这个 m/dhn F1X lv0

——地图盒(@Mapbox)2022 年 7 月 20 日

这一次,我将介绍制作这部动画所涉及的所有过程。
① 从高处扩大路线周围区域
② 用动画在地图上显示路线
③ 用相机跟随动画路线的尖端
④使相机平滑或缓慢旋转以创建视觉上更易于理解的场景
⑤ 导出视频

本视频中的方法可以在 Mapbox GL JS 文档中找到查询地形高程用作参考。它在 3D 地形上进行类似的路线跟踪,但没有精确的相机控制。

路线显示

GeoJSON 数据为了使玩家从编码的路线中移动动画,我们需要以小的增量更改线条的长度。

由于动画是静态图像的连续播放,因此挑战在于以编程方式构造每一帧,并与前一帧相比进行必要的更改。为此,请使用 window.requestAnimationFrame()。

更改线条的渐变属性以使线条随时间移动。

首先,通过将动画开始后经过的时间除以动画的预设时间来计算 animationPhase 值。这将为您从开始到结束的每一帧提供一个介于 0 和 1 之间的值。

然后用 setPaintProperty() 应用它。

const animationPhase = (currentTime - startTime) / duration;
...
map.setPaintProperty(
    "line",
    "line-gradient", [
        "step", ["line-progress"],
        "yellow",
        animationPhase,
        "rgba(0, 0, 0, 0)",
    ]
);

公式说“如果在当前进度点之前,将线上的每个点涂成黄色,如果在它之后,则将其涂成透明”。 animationPhase 每帧接近 1,因此每次调用此 setPaintProperty() 方法时,您都会看到另一小块笔画。

这是一个使用这种技术在三秒内逐渐移动简单的两点 LineString 的示例。

见笔行进动画示例克里斯·黄@chriswhong) 上代码笔.

运行相机

线条现在出现在每一帧。现在让我们让相机跟随。
这里草坪.js和 Mapbox GL JS 的三角函数免费相机 API是必须的。使用 turf.distance() 和 turf.along() 与 animationFrame 沿线的长度选择正确的点。

// アニメーションの前に、線の長さを計算します。
const pathDistance = turf.lineDistance(path);

...

// animationPhase に基づいて、パスに沿った距離を計算します。

const[lng, lat] = turf.along(path, pathDistance * animationPhase).geometry
    .coordinates;

控制相机
·位置
・海拔高度(你在哪里)
·沥青
・方向(你面向哪个方向?)
需要准备四个
在这个视频中,高度和俯仰是恒定的,所以我们只需要计算方位角和相机位置。
摄像机的方向与路线无关,它以恒定的速率变化以产生微妙的电影旋转效果。

const bearing = startBearing - animationPhase * 200.0;

如果你知道方位角、高度、俯仰角和你想看的点,你可以用三角函数来猜测相机的位置。

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
 };
 
 ...
 
 return newCameraPosition
}

注意:从经度到米的转换取决于纬度。上面的函数使用了每度 70km 的固定换算,这对法国来说已经足够准确了,但不是到处都可以。

这是一个解释在 computeCameraPosition() 中进行的计算的视觉效果。下图显示了你想在地面上看到的地方、高度、方位角和俯仰角。相机的新位置计算为相对于目标位置的 x 和 y 偏移量。

Mapboxで映画のようなルートアニメーションを作る
▲ 使用 GeoGebra 创建的 3D 图表(https://www.geogebra.org/3d/z8czvzzw)

平滑

在到目前为止我向您展示的代码中,相机直接跟随包含急转弯的路径。在这种情况下,相机聚焦在直线的尖端,动画是模糊的。
线性插值,也称为“relp”,可以通过防止相机运动在帧之间突然变化来平滑相机运动。

//https://codepen.io/ma77os/pen/OJPVrPを参照
function lerp(start, end, amt) {
 return (1 - amt) * start + amt * end
}

安德烈·马托斯先生这个例子是使用跳跃函数平滑圆的一个很好的例子。当您移动鼠标时,请注意圆圈如何平滑地跟随指针。 Mapbox 使用相同的 lerp 函数为路由动画添加了平滑度。

看笔LERP - 线性插值通过安德烈马托斯(@ma77os) 上代码笔.

放大地球

每个视频都以从高空飞入开始,包括在路线动画中的位置。Mapbox GL JS 有一个方便的 flyTo() 方法. flyTo() 的退出状态和 FreeCamera API 控件的启动状态之间很难无缝转换,所以我们不能在这里使用它。
相反,在初始地球视图和轨迹动画的开始视图之间转换相机我创建了一个自定义函数.

将先前的位置和新的线提示传递给 lerp 函数将为您提供“更平滑”的新位置。也就是说,你想看到的线条的尖端可能不在画面的中心,但随着时间的推移,它往往会向中心移动,除非移动太突然。

导出视频

导出视频,Mapbox GL JS使用示例中描述的技术.它使用 mp4-encoder javascript 库并在每次渲染 Mapbox GL JS 画布时保存一个帧。

function frame() {
  // スタブ時間を 16.6ms 増やす(60fps)。
 
  now += 1000 / 60;
 
  mapboxgl.setNow(now);
 
  const pixels = encoder.memory().subarray(ptr); // エンコーダのメモリにアクセスする

 
  gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels); // エンコーダにピクセルを読み込む
 
  encoder.encodeRGBPointer(); // フレームをエンコードする
}
 
map.on("render", frame); // フレーム単位の録画の設定

屏幕显示的大小由地图容器的 CSS 控制。对于 16:9 的视频,以 1280 像素 x 720 像素的尺寸显示。对于方形视频(Instagram 等使用),尺寸为 1080 像素 x 1080 像素。

后期制作

动画完成后,组装这些帧并下载为 mp4。最后,输出 mp4 是 CLI 工具的ffmpeg被压缩使用

% ffmpeg -i my_video.mp4 my_video_compressed.mp4

用于创建这些动画的代码在 GitHub 上mapbox/impact-tools 存储库,并且可以被引用和重用。使用 FreeCamera API,从您的 Mapbox GL JS 项目中导出高质量视频,并在 Twitter 上发布@mapbox标记和分享!

*这篇文章是Mapbox Inc. 博客是一篇翻译文章。


原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308628414.html

相关文章:

  • 2021-08-27
  • 2021-09-01
  • 2022-12-23
  • 2019-11-11
  • 2022-01-19
  • 2021-05-17
  • 2021-12-16
  • 2022-12-23
猜你喜欢
  • 2022-01-13
  • 2021-12-20
  • 2022-12-23
  • 2022-12-23
  • 2021-11-30
  • 2021-12-20
  • 2021-07-14
相关资源
相似解决方案