在 CesiumJS 中使用 Cesium World Bathymetry

全新的全球 tileset——Cesium World Bathymetry可以帮助你构建用于可视化水下环境(如海底、海岸线或内陆水体)的应用。本文将介绍在 CesiumJS 中增强测深地形可视化的一些最佳实践,比如照明、等高线与深度着色。

文中的代码示例摘自一个完整的 Sandcastle 示例(可直接运行、调整参数)。

下文会把示例中展示的功能逐一拆解说明。


连接 Cesium ion,并将 Cesium World Bathymetry 设为地形

const viewer = new Cesium.Viewer("cesiumContainer", {
  terrainProvider: await Cesium.CesiumTerrainProvider.fromIonAssetId(2426648),
  timeline: false,
  animation: false,
});

启用照明(Enable lighting)

给场景打光可以更容易看清 3D 地形的起伏轮廓。虽然通常贴在地形上的卫星影像在拍摄时自带光照与阴影,但水体区域的影像往往并不明亮。启用 CesiumJS 的光照选项可以突出“山”和“谷”,更易理解水下地形的形态。

“未开启照明”的效果(夏威夷区域)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“开启照明”的效果(同一区域)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由于更强调了地形几何,后续示例中我们会把全局的 maximumScreenSpaceError 从默认值下调,以便更早加载更高细节。


关闭地表大气与雾效(Disable ground atmosphere and fog)

大气与雾是对陆地显示很有用的可视化功能,但对测深可视化不一定友好。

  • “大气”结合了光照与颜色效果,让地球与天空更逼真,帮助观众感知距离与时间。
  • “雾”则在地平线方向将大气与远处几何进行混合,既更真实,也有助于性能。

不过,这两者都会让水下高程(深度)变化更难分辨。下面的示例代码会:打开照明、关闭大气与雾;并用 Cesium.DirectionalLight 做坡向加亮(hillside lighting),让原本容易“糊成一片”的斜坡更立体。注意:光照计算需要顶点法线,向地形请求时务必带上 requestVertexNormals: true

const viewer = new Cesium.Viewer("cesiumContainer", {
  terrainProvider: await Cesium.CesiumTerrainProvider.fromIonAssetId(
    2426648,
    { requestVertexNormals: true }
  ),
});

const scene = viewer.scene;
const globe = scene.globe;
const camera = scene.camera;

scene.fog.enabled = false;
globe.showGroundAtmosphere = false;

globe.enableLighting = true;

// 使用定向光,并在每帧根据相机方向更新光照方向
scene.light = new Cesium.DirectionalLight({
  direction: new Cesium.Cartesian3(1, 0, 0), // 每帧更新
});

const scratchNormal = new Cesium.Cartesian3();
scene.preRender.addEventListener(function (scene, time) {
  const surfaceNormal = globe.ellipsoid.geodeticSurfaceNormal(
    camera.positionWC,
    scratchNormal
  );
  const negativeNormal = Cesium.Cartesian3.negate(surfaceNormal, surfaceNormal);
  scene.light.direction = Cesium.Cartesian3.normalize(
    Cesium.Cartesian3.add(
      negativeNormal,
      camera.rightWC,
      surfaceNormal
    ),
    scene.light.direction
  );
});

// 更低的 SSE 让高分辨率 tile 更早加载,利于海底阴影/着色
globe.maximumScreenSpaceError = 1.0;

“开启雾效”的地平线视图(夏威夷区域)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“关闭雾效”的地平线视图(同一区域)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


选择更适合的全球影像(Choose the best global imagery)

CesiumJS 默认的影像提供者是 Bing Aerial imagery,它在水体区域偏暗,缺乏对比度会让测深更难看清。作为 Cesium ion 的一部分,Sentinel-2 影像更明亮,通常能更好突出海洋中的地形数据。

Bing Aerial imagery(加州外海)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sentinel-2 imagery(同一区域)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可视化并不限于卫星影像。简化或风格化底图(例如 Stadia Alidade)与测深地形、光照搭配时,能获得更高对比度。

菲律宾外海,使用 Stadia Alidade 底图
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


夸张纵向比例(Exaggerate the elevation)

对测深高程做“夸张”处理可以放大高度差,从而更容易看清细微起伏。

黑海区域(无夸张)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

黑海区域(开启夸张)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

示例:将地形夸张系数设为 5

viewer.scene.verticalExaggeration = 5.0;

建议在应用中加入滑杆,允许用户自行调整夸张程度。


用颜色与等高线表示高程(Use color and contour lines to indicate elevation)

除了光照与夸张,程序化着色(例如根据高程的 color ramp、等高线)可以提供更多视觉洞见。下面的示例包含一个常用的海洋配色方案,并允许用户在不同底色下反转等高线颜色以提升可见性。可根据你的场景选择更合适的配色与等高线参数,并在界面上提供图例帮助理解。

下面的代码会创建:

  • 高程 color ramp
  • 用于高程着色与等高线叠加的材质
  • 随距离变化的等高线密度
  • 当用户操作控件时动态更新材质,并应用到地球
// Globe material constants
const minHeight = -10000.0;
const approximateSeaLevel = 0.0;
const maxHeight = 2000.0;
const countourLineSpacing = 500.0;

const range = maxHeight - minHeight;
const d = (height) => (height - minHeight) / range;

// Create a color ramp based on https://matplotlib.org/cmocean/#deep
function getColorRamp() {
  const ramp = document.createElement("canvas");
  ramp.width = 100;
  ramp.height = 15;
  const ctx = ramp.getContext("2d");
  const grd = ctx.createLinearGradient(0, 0, 100, 0);

  grd.addColorStop(d(maxHeight), "#B79E6C");
  grd.addColorStop(d(100.0), "#FBFFEE");
  grd.addColorStop(d(0.0), "#F9FCCA");
  grd.addColorStop(d(-500.0), "#BDE7AD");
  grd.addColorStop(d(-1000.0), "#81D2A3");
  grd.addColorStop(d(-1500.0), "#5AB7A4");
  grd.addColorStop(d(-2000.0), "#4C9AA0");
  grd.addColorStop(d(-2500.0), "#437D9A");
  grd.addColorStop(d(-4000.0), "#3E6194");
  grd.addColorStop(d(-5000.0), "#424380");
  grd.addColorStop(d(-8000.0), "#392D52");
  grd.addColorStop(d(minHeight), "#291C2F");

  ctx.fillStyle = grd;
  ctx.fillRect(0, 0, ramp.width, ramp.height);

  return ramp;
}

// Creates a composite material with both elevation shading and contour lines
function getElevationContourMaterial() {
  return new Cesium.Material({
    fabric: {
      type: "ElevationColorContour",
      materials: {
        contourMaterial: {
          type: "ElevationContour",
        },
        elevationRampMaterial: {
          type: "ElevationRamp",
        },
      },
      components: {
        diffuse:
          "(1.0 - contourMaterial.alpha) * elevationRampMaterial.diffuse + contourMaterial.alpha * contourMaterial.diffuse",
        alpha: "max(contourMaterial.alpha, elevationRampMaterial.alpha)",
      },
    },
    translucent: false,
  });
}

// Apply the material to the globe
function updateGlobeMaterial() {
  const material = getElevationContourMaterial();

  // 高程着色
  let shadingUniforms = material.materials.elevationRampMaterial.uniforms;
  shadingUniforms.image = getColorRamp();
  shadingUniforms.minimumHeight =
    minHeight * viewer.scene.verticalExaggeration;
  shadingUniforms.maximumHeight =
    maxHeight * viewer.scene.verticalExaggeration;

  // 等高线
  shadingUniforms = material.materials.contourMaterial.uniforms;
  shadingUniforms.width = 1.0;
  shadingUniforms.spacing =
    countourLineSpacing * viewer.scene.verticalExaggeration;
  shadingUniforms.color = Cesium.Color.BLACK.withAlpha(0.5);

  viewer.scene.globe.material = material;
}

updateGlobeMaterial();

南加州外海,Esri World Ocean Imagery(仅底图)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

同一区域,叠加高程 color ramp 与等高线
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


原文地址:https://cesium.com/blog/2024/01/29/cesium-world-bathymetry-in-cesiumjs/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值