Remotion 中使用 CesiumJS 打造三维地图飞行运镜(Cesium Flyover)完整指南 Remotion 中使用 CesiumJS 打造三维地图飞行运镜Cesium Flyover完整指南【免费下载链接】remotion Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion本文面向想在 Remotion 中以「飞行模拟器」视角制作三维地图镜头的开发者。内容以packages/skills/skills/remotion-maps/techniques/cesium/这套经实际渲染验证的技术方案为核心完整覆盖 landscape自然地形与 city城市建筑双模式选型、API 凭证配置、飞行路径生成、逐帧相机数学以及无头浏览器渲染下的排障要点。读完你将掌握如何用 CesiumJS 1.143 MapTiler / Google Photorealistic 3D Tiles在 Remotion 中渲染出平滑、带过弯侧倾、无抖动卡顿的 3D 航拍运镜。方案定位两种运镜模式与数据选型该技术方案围绕两种截然不同的「飞行场景」抽象出同一套组件接口核心选型逻辑记录在 TECHNIQUE.md模式数据源适用题材landscapeMapTilerterrain-quantized-mesh-v2量化网格地形satellite-v2卫星影像山脉、峡谷、河流、海岸线与乡村路线cityGoogle Photorealistic 3D Tiles真实感 3D 瓦片城市、建筑与可辨识地标选型上有一个明确禁令城市飞行不要用 footprint extrusion建筑足迹拉伸挤出。原因在 3d-data-sources.md 中有专门论述OSM、Overture、矢量瓦片等建筑产品主要提供足迹轮廓、近似高度与可选的屋顶属性适合分析型或风格化地图却无法提供城市低空飞行镜头所需的「带贴图的真实建筑外观」做出来只会是粗糙的方块体。两个数据源的补充说明landscape模式下 MapTiler 同时供应影像与地形两层数据无需 Cesium ion tokencity模式则严禁在地表叠加 MapTiler 图层或保留 Cesium globe否则会出现重复/竞争的渲染表面。API 凭证与环境变量CesiumFlythrough组件在初始化时直接从环境变量读取密钥见 CesiumFlythrough.tsxconst MAPTILER_KEY process.env.REMOTION_MAPTILER_KEY; const GOOGLE_MAPS_API_KEY process.env.REMOTION_GOOGLE_MAPS_API_KEY;landscape 模式必须设置REMOTION_MAPTILER_KEY在 MapTiler 官网云控制台cloud.maptiler.com/account/keys/创建密钥。若缺失组件会在渲染时抛出Set REMOTION_MAPTILER_KEY. ...错误。city 模式必须设置REMOTION_GOOGLE_MAPS_API_KEY需要在一个启用结算billing-enabled的 Google Cloud 项目中开启Map Tiles API并把密钥限制到该 API 使用同时密钥的应用限制必须放行本地无头 Remotion 发起的请求否则瓦片请求会返回 403。官方对两种瓦片的调用都要求保留 provider attribution来源署名详见下文合规小节。快速接入组件 路径 JSON 两条 Composition接入只需要三类素材TECHNIQUE.md「Build the flight」一节复制 CesiumFlythrough.tsx、一份路径 JSON如 cesium-path.json / city-path.json以及 example-Root.tsx 进入你的 Remotion 项目或直接把组件 import 进来复用以[longitude, latitude][]的坐标数组提供相机航线只保留有意义的控制点不要手写几十个细微修正点pathSmoothingPasses{3}起步渲染完整视频前先渲染一帧中段画面做构图校验。example-Root.tsx展示了两种模式各自完整的 Composition 注册方式Composition idLandscapeFlyover component{CesiumFlythrough} defaultProps{{mode: landscape} satisfies CesiumFlythroughProps} durationInFrames{24 * 30} fps{30} width{1920} height{1080} / Composition idCityFlyover component{CesiumFlythrough} defaultProps{ { mode: city, path: cityPath as [number, number][], altitudeStart: 700, altitudeEnd: 500, lookAheadKm: 0.7, travelKm: 4.5, pitchFromNadir: 72, verticalExaggeration: 1, maximumScreenSpaceError: 6, } satisfies CesiumFlythroughProps } durationInFrames{18 * 30} fps{30} width{1920} height{1080} /城市示例的构图思路与 landscape 的差别直观地体现在参数上——TECHNIQUE.md强调城市相机通常比地形相机飞得更低示例中 altitudeStart/altitudeEnd 为 700→500 米而地形模式默认是 4600→4300 米lookAheadKm也更短以便在街区之间灵活转向CesiumFlythrough modecity path{cameraPath} pathSmoothingPasses{3} altitudeStart{700} altitudeEnd{500} lookAheadKm{0.7} travelKm{4.5} /组件 Props 全表与默认值以下参数与默认值均直接取自 CesiumFlythrough.tsx 的CesiumFlythroughProps类型与函数签名其中altitudeStart/altitudeEnd等都以**绝对海拔米**给出、与地形无关Prop类型/取值默认值含义modelandscape \| citylandscape运镜模式决定数据源与瓦片加载策略pathLngLat[][lng, lat]内置cesium-path.json相机航线控制点pathSmoothingPassesnumber3Chaikin 圆角化迭代轮数3 默认、4 更柔和、2 更紧贴狭窄走廊altitudeStartnumber4600起始相机绝对海拔米随进度插值到altitudeEndaltitudeEndnumber4300结束相机绝对海拔米lookAheadKmnumber1.5朝向瞄准点距相机的弧长km衡量航向平滑度与响应性travelKmnumber13相机实际行进的总里程km速度 travelKm / 时长秒数pitchFromNadirnumber76以「距天底正下方度数」表达的俯仰90 平视verticalExaggerationnumber1.1地形垂直夸张系数塑造地形的戏剧感maximumScreenSpaceErrornumber8瓦片屏幕空间误差值越小细节越精细、下载与渲染开销越大飞行路径的三级打磨管线第一步稀疏控制点 Chaikin 圆角化pathSmoothingPasses的底层实现是 flight-path.ts 中的Chaikin corner cutting每一轮把每条线段替换为 1/4 与 3/4 分位点0.75a0.25b、0.25a0.75b把「直线然后拐弯」的折线磨成连续的弧形过弯。TECHNIQUE.md给出的调参规律pathSmoothingPasses{3}起步增大到4获得更软滑的路线降到2用于必须贴紧狭窄走廊的镜头。该文件还处理了一个容易被忽略的边界跨反经线antimeridian的航线——在平滑前先将所有经度按上一顶点解包unwrapped使相邻点经度连续避免 ±180° 跳变把路径切碎const unwrapped: LngLat[] [source[0]]; for (let index 1; index source.length; index) { const [lng, lat] source[index]; const previous unwrapped[index - 1][0]; let adjusted lng; while (adjusted - previous 180) adjusted - 360; while (adjusted - previous -180) adjusted 360; unwrapped.push([adjusted, lat]); }组件侧通过makePathWalker把平滑后的曲线预计算累计距离并封装along(km)弧长插值器CesiumFlythrough.tsx为逐帧等速前进做准备。第二步landscape 专用路径生成脚本对于河流/公路等依赖地理中心线的地形镜头prep-cesium-path.mjs 会先做一轮几何预处理把原始 GeoJSON 中心线加工成适合飞行的长弧线clip按起始点截取一段窗口→ 按 0.1 km 等弧长重采样 → 移动平均平滑±2.8 km 窗口、2 轮 → 向首尾直线弦阻尼DAMP 0.45→ 输出 cesium-path.json输入必须是单一 LineString取features[0].geometry.coordinates需按新地点调整脚本顶部START必须是中心线上的点脚本自动吸附到最近顶点、WINDOW_KM默认 30以及DAMP/SMOOTH旋钮选源建议峡谷内部推荐 OSM Overpass顶点间距约 0.3 kmNatural Earth 对内侧峡谷过于粗糙overpass-api.de繁忙时可切换镜像overpass.kumi.systems脚本会输出两条诊断信息精简流水线各阶段点数与总里程以及每约 1.5 km 采样的航向增量序列。DAMP是唯一的摆幅旋钮0表示完全直线、1表示完整保留河流摆动样例值 0.45 保留约 45% 的已平滑偏差形成轻柔连续的侧摆。关于这条管线有三个关键工程决策值得注意3d-flyover-architecture.md有详细论证组件对预处理产物或手写城市短航线还会再施加一次 Chaikin 平滑不要用 Douglas-Peucker /turf.simplify——它会把曲率集中到稀疏控制点上、重新制造「折线拐角」移动平均平滑天然是连续曲率无尖点而它正是prep-cesium-path.mjs对河流这类数据选择的工具。流水线的输出质量判据是航向增量序列必须小且渐进变化参考文档记录的水域样例约为3,0,-1,-3,-4,1,7,9,5,-5,-12,-7,…出现大跳变意味着路径仍有拐角。脚本附带的样例会打印出clip → resample → smooth → … pts的统计供核对。相机逐帧数学航向、俯仰与侧倾TECHNIQUE.md「Camera behavior」一节概括了三条铁律而 3d-flyover-architecture.md 给出了完整推导按弧长等速前进平滑曲线预计算累计距离按dCam公里插值取点保证地面速度恒定绝不能用「按源点索引」驱动动画源点间距不均会造成速度起伏朝曲线前方更远处的真实点瞄准heading 相机点到lookAheadKm之外一个真实路径点的方位角。远处的瞄准点会平均掉局部抖动且会提前进入弯道、让航向随路径平滑转动——若用局部切线方向瞄准会在每个折点抖镜头从 look-ahead 方位角变化推导侧倾roll用aim与2·lookAheadKm处探测点的方位角差dH表征转弯速率roll clamp(dH · BANK_GAIN, ±MAX_BANK)。由于路径平滑dH渐进变化侧倾也随之缓入缓出让相机倾斜进弯而不是左右抽搐。组件内的相机设置逻辑如下CesiumFlythrough.tsxconst maxTravel Math.max(0, walker.lengthKm - lookAheadKm * 2); const cameraDistance Math.min(travelKm, maxTravel) * progress; const camera walker.along(cameraDistance); const aim walker.along(cameraDistance lookAheadKm); const aim2 walker.along(cameraDistance lookAheadKm * 2); const heading bearing(camera, aim); let headingDelta bearing(aim, aim2) - heading; // 归一化到 [-π, π] viewer.camera.setView({ destination: C.Cartesian3.fromDegrees(camera[0], camera[1], lerp(altitudeStart, altitudeEnd, progress)), orientation: { heading, pitch: C.Math.toRadians(-(90 - pitchFromNadir)), roll: clamp(headingDelta * BANK_GAIN, -MAX_BANK, MAX_BANK), }, });组件常量MAX_BANK 0.13rad约 7.5°、BANK_GAIN 0.6。注意Math.min(travelKm, maxTravel)保证PATHKM ≥ TRAVEL_KM 2·LOOK_AHEAD_KM否则航向/转弯探测点在末端会被钳制失效。坐标系约定陷阱Cesium vs MapLibreCesium 的 heading 为弧度、0 北、顺时针为正pitch 0 地平线、负值向下与 MapLibre 相反。组件保留了一个 MapLibre 风格参数pitchFromNadir90 平视再换算Cesium pitch -(90 - pitchFromNadir)度因此默认 76° 实际传入-14°roll 为正表示向右侧倾符号需要按实际画面微调。组件源码中有一组经过实际飞行测试的「感知调优」参数表记录于架构参考文档可作为起点参数取值说明travelKm13相机总行程速度 travelKm / durationSeconds时长24 s30fps 下 720 帧13 km / 24 s ≈0.54 km/s缓慢从容的滑翔感8 s 会显得「非常赶」altitudeStart → altitudeEnd4600 → 4300 m绝对海拔在峡谷壁之内飞行是「穿行」而非「掠过」lookAheadKm1.5航向平滑度 vs 响应性的权衡pitchFromNadir76°沿走廊向前下俯视对应 Cesium-14°MAX_BANK/BANK_GAIN0.13 rad约 7.5°/ 0.6过弯时的直升机式侧倾verticalExaggeration1.1微妙的地形立体感DAMP预处理0.45摆幅大小越大越「S 型甩动」越小越笔直渲染机制为什么必须经由 Remotion 帧循环Cesium 在独立无头 Playwright/Chromium下不会真正绘制地球——参考文档 3d-troubleshooting.md 记录了这一实测结论星空背景能渲染但球面产生0 条绘制命令scene.frameState.commandList.length 0、globe.tilesLoaded永不为 true、帧输出为黑色星空。可行的方案是让 Remotion 驱动同一无头 Chrome 的帧循环但必须遵守四条「非协商条款」viewer.useDefaultRenderLoop false——逐帧手动驱动每帧调用viewer.render()而非scene.render()viewer.render()完成完整帧initializeFrame → 瓦片流式加载 → 绘制scene.render()跳过帧初始化瓦片永不前进、地球永不出现。这是全方案最重要的一行创建 Viewer 时开启contextOptions: {webgl: {preserveDrawingBuffer: true}}否则 Remotion 截图拿到的是空白/透明帧用delayRender(..., {timeoutInMilliseconds})同时门控初始化与每一帧初始化 120 s、单帧 60 s见 CesiumFlythrough.tsx 与逐帧逻辑 #L253-L263。组件加载流程对应loadCesium先设置window.CESIUM_BASE_URL指向 Cesium CDN测试版本固定为1.143再注入Cesium.js与 widgets.css脚本加载完成后 resolve。settle瓦片稳定策略settle()循环每 8 ms 调用一次viewer.render()直到「瓦片加载完成」状态连续稳定约 8 次 tick上限 600 tick后放行判定条件按模式区分——landscape 看globe.tilesLoadedcity 看tileset.tilesLoadedCesiumFlythrough.tsx。初始化 effect 与逐帧 effect 各自持有独立的delayRenderhandle全部 settle 完成后continueRender任何初始化异常走cancelRender(error)。另外组件会在初始化 effect 中做两个守卫校验city 模式要求REMOTION_GOOGLE_MAPS_API_KEY存在同时city 模式的durationInFrames / fps不得超过 30 秒遵守 Google Photorealistic 3D Tiles 的推广素材时长条款超出会抛错终止。调试与故障排查Symptom → Fix无头环境下瓦片渲染的坑远比想象中多以下是 3d-troubleshooting.md 整理的症状速查表症状原因修复画面为带星星的黑色地球未绘制独立无头 Playwright或误用scene.render()经 Remotion 渲染用viewer.render()useDefaultRenderLoop false截图空白/透明缺少preserveDrawingBuffer开启contextOptions: {webgl: {preserveDrawingBuffer: true}}delayRender timed out冷启动瓦片超过默认超时delayRender(…, {timeoutInMilliseconds: 120000})并配--timeout180000地球是深色/藏青球体影像层未挂载baseLayer: false后viewer.imageryLayers.addImageryProvider(...)高俯仰画面出现虚空/星空没有大气层viewer.scene.skyAtmosphere.show true瓦片 403MapTiler 密钥被域名锁定使用**不限域名unrestricted**的密钥Google 根 tileset 返回 403Map Tiles API 未启用、无结算、密钥错误或应用限制拦截了本地无头请求启用 API 与结算密钥限制到该 API 但放行 Remotion 请求Google 场景出现重复/竞争表面MapTiler 或 Cesium globe 未关不添加 MapTiler设viewer.scene.globe.show falseGoogle 网格仍然粗糙屏幕空间误差过大或截图早于细化完成调低maximumScreenSpaceError以tileset.tilesLoaded为准 settleWebGL 不可用/落入软件渲染缺少 GL 标志渲染时加--glangle相机看天空/地面而非地形俯仰符号约定问题Cesium pitch 0 地平线、负值向下与 MapLibre 相反-(90 - PITCH_FROM_NADIR)航向/转弯探测在末端被钳制路径太短PATHKM ≥ TRAVEL_KM 2·LOOK_AHEAD_KM预处理时调大WINDOW_KM路径像「直飞—折向—直飞」用了 Douglas-Peucker 简化改用重采样 → 移动平均平滑而非turf.simplify相机左右颠簸而非侧摆过弯稀疏路由顶点仍被当作直线段逐点跟随保持pathSmoothingPasses{3}、稀疏有意的控制点 弧长驱动maximumScreenSpaceError的实用建议主力地标镜头从4起步开阔城市场景用6–8参考文档示例中 CityFlyover 即用了6。渲染验证流程与 CLI 参数架构参考文档给出推荐的验证/渲染命令序列Remotion 官方 CLI入口文件按你的项目填写# 先渲染中帧静帧校验构图与侧倾 bunx remotion still src/index.ts Comp out.png --frameN --glangle --timeout180000 # 确认无误后再渲染完整视频 bunx remotion render src/index.ts Comp out.mp4 --glangle --concurrency1 --timeout180000要点--glangle是必选项否则可能落到不可用的 WebGL 软件路径使用--concurrency1——settle()本身已经串行化瓦片加载高并发反而无益TECHNIQUE.md提醒在每个需要的宽高比下检查渲染出的像素而非仅看 Studio 预览一个值得记录的工程经验慢速相机渲染反而更快——以 0.54 km/s 移动时每帧约前进 18 m瓦片可保持在缓存中settle()几乎立即返回720 帧的一次性渲染即可完成无需分块渲染。合规与出片注意事项保持 provider attribution 全程可见landscape 模式组件通过viewer.creditDisplay.addStaticCredit加入 MapTiler 署名© MapTilercity 模式在 tileset 上开启showCreditsOnScreen: true不要隐藏 credit display。city 模式组件还会在画面右上角叠加「For promotional purposes only」提示水印且如前所述将成片时长钳制在 30 秒内——二者对应 Google Photorealistic 3D Tiles 的推广用途条款。若包含自定义或存有争议的地理内容需记录其来源与生效日期。组件初始化时启用了skyAtmosphere、开启 fog雾效、关闭globe.enableLighting并应用verticalExaggeration这些是画面氛围的一部分可在源码中按需调整。配套文件速览TECHNIQUE.md — 本方案总入口双模式操作手册assets/CesiumFlythrough.tsx — 可复用的双模式核心组件推荐直接通读全文件assets/flight-path.ts — 零依赖的 Chaikin 航线平滑含反经线解包assets/example-Root.tsx — landscape 与 city 两条 Composition 的注册样例assets/cesium-path.json / assets/city-path.json — 地形/城市示例航线assets/sample-river.geojson — 路径预处理示例输入示例河段中心线脚本注释注明取自雅鲁藏布峡谷河段scripts/prep-cesium-path.mjs — 零依赖的 landscape 航线预处理工具node prep-cesium-path.mjs即可针对内置样例运行references/3d-flyover-architecture.md — 相机数学与参数依据的深度文档references/3d-data-sources.md — 数据源与厂商文档说明references/3d-troubleshooting.md — 空白、粗糙、未授权与超时渲染的排障全集。若需要了解本技巧在 remotion-maps 技能体系中的定位可阅读同目录的 SKILL.md 及其下的techniques/mapbox、techniques/maplibre、techniques/maptiler、techniques/static-map等同级方案它们分别覆盖 2D/矢量地图与静态地图的运镜实现。【免费下载链接】remotion Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考