当前位置: 首页 > news >正文

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 即可。

const tileset = new TilesRenderer("http://localhost:8080/XXX/tileset.json");

构造 TilesRenderer 实例

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

tileset.setCamera(camera);
tileset.setResolutionFromRenderer(camera, renderer);

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

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

// 配置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 三维场景中就能正常摆放了。

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数据的基本加载就完成了。

function renderLoop() {// 更新 TilesRenderer 之前需要更新 three.js 的相机参数camera.updateMatrixWorld();tileset.update(); // 更新 TilesRendererrenderer.render(scene, camera);
}

每一帧都更新 TilesRenderer 

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

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

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

插件的注册和使用 

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

// 设置图层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 做一些效果上的补充,可能会是更好的方案。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 传统CV算法——基于 SIFT 特征点检测与匹配实现全景图像拼接
  • C++:入门篇(补充C语言中的不足)
  • TestCraft - GPT支持的测试想法生成器和自动化测试生成器
  • 【论文阅读】01-Survey on Temporal Knowledge Graph
  • PhpStorm 下调试功能配置
  • 粉丝+1,马斯克点赞《黑神话:悟空》
  • PHP一站式解决方案高级房产系统小程序源码
  • 【在Unity完成三维场景多人在线同时操作的实现方式】
  • 使用Protocol Buffers传输数据
  • 李沐深度学习 自制数据集
  • GenAI 客户支持 — 第 3 部分:为人类设计聊天机器人的聊天界面
  • 数据结构之红黑树的 “奥秘“
  • HarmonyOS学习(七)——UI(五)常用布局总结
  • 多目标应用:四种多目标优化算法(NSGA2、NSPSO、NSDBO、NSCOA)求解柔性作业车间调度问题(FJSP),MATLAB代码
  • ffmpeg7.0 AVFrame的分配与释放
  • 2019年如何成为全栈工程师?
  • Angular Elements 及其运作原理
  • Babel配置的不完全指南
  • codis proxy处理流程
  • Cookie 在前端中的实践
  • echarts的各种常用效果展示
  • httpie使用详解
  • leetcode388. Longest Absolute File Path
  • PHP变量
  • python 学习笔记 - Queue Pipes,进程间通讯
  • Python爬虫--- 1.3 BS4库的解析器
  • React组件设计模式(一)
  • V4L2视频输入框架概述
  • 对JS继承的一点思考
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 将回调地狱按在地上摩擦的Promise
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 我与Jetbrains的这些年
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • (day 12)JavaScript学习笔记(数组3)
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (不用互三)AI绘画:科技赋能艺术的崭新时代
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (每日一问)基础知识:堆与栈的区别
  • (学习日记)2024.01.19
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (转)fock函数详解
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .NET 3.0 Framework已经被添加到WindowUpdate
  • .NET MVC之AOP
  • .NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖
  • .NET 直连SAP HANA数据库
  • .NET 中什么样的类是可使用 await 异步等待的?
  • /var/log/cvslog 太大
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • @DependsOn:解析 Spring 中的依赖关系之艺术