three.js使用3DTilesRendererJS加载3d tiles数据

原生的 three.js 目前不支持 3d tiles 数据的加载,不过开源社区已经给出了一些解决方案,其中最活跃的要属 3DTilesRendererJS。它为 three.js 提供了加载和调度 3d tiles 数据的基本能力,虽说和 Cesium.js 对 3d tiles 的支持相比还有很大的差距,但也比没有的好。毕竟 3d tiles 数据的加载和调度还是比较复杂的,要自己写也没那么容易,这一点在以前研究 Cesium.js 相关源码的时候就深有体会。

3DTilesRendererJS 最核心的类是 TilesRenderer,用来渲染和调度一份 3d tiles 数据,相当于Cesium.js 里的 Cesium3DTileset。使用起来非常简单,构造的时候传入 JSON 文件的 url 即可。

javascript 复制代码
const tileset = new TilesRenderer("http://localhost:8080/XXX/tileset.json");

构造 TilesRenderer 实例

接着,需要把 TilesRenderer 实例和 three.js 的 camera 以及 renderer 关联起来,根据 three.js 的相机和渲染器参数来设置切片显示的分辨率。

javascript 复制代码
tileset.setCamera(camera);
tileset.setResolutionFromRenderer(camera, renderer);

关联 three.js 的相机和渲染器参数

很多 3d tiles 数据都是做了顶点压缩或纹理压缩的,比如顶点的 DRACO 压缩、KTX2 和 DDS 等纹理压缩格式,对于这类数据需要在GLTF解析器(GLTFLoader)中添加解压缩的能力。下面以解压缩 DRACO 为例用代码加以说明。

javascript 复制代码
// 配置GLTF数据的解析器
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('./jsm/libs/draco/gltf/');

const loader = new GLTFLoader(tileset.manager);
loader.setDRACOLoader(dracoLoader);
tileset.manager.addHandler(/\.gltf$/, loader);

为GLTF解析器配置解压缩 DRACO 的能力

3d tiles数据以往基本上都是在 WGS84椭球上呈现的。现在要在 three.js 的局部场景下展示,则需要把它放在局部场景相机的视野范围内,并保证数据的上方向正确。这里封装了一个 adjustTilesPositionAndDirection 方法,将数据放置在局部场景的中心,并将Y轴正方向(Y+)作为数据的上方向。这样数据在 three.js 三维场景中就能正常摆放了。

javascript 复制代码
function rotationBetweenDirections(dir1, dir2) {
  const rotation = new THREE.Quaternion();
  const a = new THREE.Vector3().crossVectors(dir1, dir2);
  rotation.x = a.x;
  rotation.y = a.y;
  rotation.z = a.z;
  rotation.w = 1 + dir1.clone().dot(dir2);
  rotation.normalize();

  return rotation;
}

function adjustTilesPositionAndDirection(tiles) {
  if (!tiles) {
	return;
  }

  const sphere = new THREE.Sphere();
  tiles.getBoundingSphere(sphere);

  const position = sphere.center.clone();
  const distanceToEllipsoidCenter = position.length();

  const surfaceDirection = position.normalize();
  const up = new THREE.Vector3(0, 1, 0);
  const rotationToNorthPole = rotationBetweenDirections(surfaceDirection, up);

  tiles.group.quaternion.x = rotationToNorthPole.x;
  tiles.group.quaternion.y = rotationToNorthPole.y;
  tiles.group.quaternion.z = rotationToNorthPole.z;
  tiles.group.quaternion.w = rotationToNorthPole.w;

  tiles.group.position.y = - distanceToEllipsoidCenter;
}

调整数据在 three.js 场景中的位置和上方向

最后在每一帧渲染时都去执行一次 TilesRenderer 的更新。至此,一份3d tiles数据的基本加载就完成了。

javascript 复制代码
function renderLoop() {
  // 更新 TilesRenderer 之前需要更新 three.js 的相机参数
  camera.updateMatrixWorld();
  
  tileset.update(); // 更新 TilesRenderer

  renderer.render(scene, camera);
}

每一帧都更新 TilesRenderer

以上是使用 3DTilesRendererJS 的基本流程。还可以做一些辅助工作。

可以根据需要为数据注册一些插件,可选的插件在官方文档中查看。下面的示例以调试插件为例,简要说明插件的注册和使用方式。

javascript 复制代码
// 注册调试插件
tileset.registerPlugin(new DebugTilesPlugin());

// ...

// 获取调试插件,并显示包围盒的线框
tileset.getPluginByName('DEBUG_TILES_PLUGIN').displayBoxBounds = true;

插件的注册和使用

当场景中加载了多份 3d tiles 数据时,最好共享内存和下载队列,以减少性能开销。

javascript 复制代码
// 设置图层1的缓存大小
tileset.lruCache.minSize = 900;
tileset.lruCache.maxSize = 1300;

// 图层2和图层1共享内存和下载队列以减少性能开销
tileset2.lruCache = tileset.lruCache;
tileset2.downloadQueue = tileset.downloadQueue;
tileset2.parseQueue = tileset.parseQueue;

共享内存和下载队列

github上只提供了源码,没有提供打包好的库。有需要编译库的同学可以在这里下载。


个人觉得和 Cesium.js 相比,3DTilesRendererJS 加载和调度 3d tiles 的能力还是挺弱的。小场景、和数据之间交互(操作、修改)要求不那么高的情况下可以尝试。如果是做大场景下的 GIS 应用,也许 Cesium.js 和 Three.js 做深度融合(绘制在同一个 canvas 上,深度值做统一),GIS 功能交给 Cesium.js,Three.js 做一些效果上的补充,可能会是更好的方案。

相关推荐
tedcloud1231 小时前
UI-TARS-desktop部署教程:构建AI桌面自动化系统
服务器·前端·人工智能·ui·自动化·github
UXbot4 小时前
AI原型设计工具如何支持团队协作与快速迭代
前端·交互·个人开发·ai编程·原型模式
ZC跨境爬虫5 小时前
跟着MDN学HTML_day_48:(Node接口)
前端·javascript·ui·html·音视频
DTAS尺寸公差分析软件6 小时前
DTAS 3D公差分析软件最新版本介绍
python·3d·尺寸公差分析·尺寸链计算·尺寸工程·尺寸链校核软件·公差仿真分析
PieroPc6 小时前
CAMWATCH — 局域网摄像头监控系统 Fastapi + html
前端·python·html·fastapi·监控
巴巴博一7 小时前
2026 最新:Trae / Cursor 一键接入 taste-skill 完整教程(让 AI 前端告别“AI 味”)
前端·ai·ai编程
kyriewen7 小时前
半夜三点线上崩了,AI替我背了锅——用AI排错,五分钟定位三年老bug
前端·javascript·ai编程
kyriewen8 小时前
我让 AI 当了 24 小时全年无休的“毒舌考官”
前端·ci/cd·ai编程
hexu_blog8 小时前
vue+java实现图片批量压缩
java·前端·vue.js
IT_陈寒8 小时前
为什么你应该学习JavaScript?
前端·人工智能·后端