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

Three.js 加载3dtiles教程

加载3dtiles ·Load Tiles· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • OrbitControls 相机轨道交互
  • glTF/Draco 模型加载与优化
  • 3D Tiles 流式 LOD 场景
  • requestAnimationFrame渲染循环与resize自适应

效果说明

本案例演示加载3dtiles效果:基于 WebGL 实现「加载3dtiles」可视化效果,附完整可运行源码;核心用到 OrbitControls、glTF/Draco、3D。建议先打开文首在线案例查看动态画面,再对照下方源码逐步理解。

核心概念

  • Loader异步加载模型;glTF 返回gltf.scene,加载后注意scale与坐标系。Draco 需配置DRACOLoader
  • OrbitControls轨道旋转缩放;开enableDamping时每帧需controls.update()

实现步骤

  • 搭建 Scene / Camera / Renderer 与 OrbitControls
  • Loader 异步加载模型/纹理资源
  • rAF 循环中 update 并 render
  • 代码要点

    import * as THREE from 'three'

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import { TilesRenderer } from '3d-tiles-renderer'

    const box = document.getElementById('box')

    const scene = new THREE.Scene()

    const camera = new THREE.PerspectiveCamera(75, box.clientWidth / box.clientHeight, 0.1, 1000)

    camera.position.set(0, 30, 30)

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true })

    renderer.setSize(box.clientWidth, box.clientHeight)

    box.appendChild(renderer.domElement)

    new OrbitControls(camera, renderer.domElement)

    scene.add(new THREE.AxesHelper(1000))

    // 加载3d tiles const tilesRenderer = new TilesRenderer(FILE_HOST + '3dtiles/test/tileset.json')

    tilesRenderer.setCamera(camera)

    tilesRenderer.setResolutionFromRenderer(camera, renderer)

    const model = new THREE.Group().add(tilesRenderer.group)

    scene.add(model)

    const box3 = new THREE.Box3()

    tilesRenderer.addEventListener('load-tile-set', () => {

    if (tilesRenderer.getBoundingBox(box3)) {

    box3.getCenter(tilesRenderer.group.position)

    tilesRenderer.group.position.multiplyScalar(-1)

    }

    })

    animate()

    function animate() {

    requestAnimationFrame(animate)

    tilesRenderer.update()

    renderer.render(scene, camera)

    }

    // tilesRenderer.errorTarget = 1 // 设置错误阈值,默认值为0.5,范围0~1,值越小越严格

    // https://blog.csdn.net/m0_73348873/article/details/151783069

    /* function initTiles() { tilesRenderer = new TilesRenderer("3dtiles路径/tileset.json"); const gltfLoader = new GLTFLoader(); // Draco const dracoLoader = new DRACOLoader(); dracoLoader.setDecoderPath("https://unpkg.com/three@0.180.0/examples/jsm/libs/draco/"); gltfLoader.setDRACOLoader(dracoLoader); // KTX2 const ktx2Loader = new KTX2Loader(); ktx2Loader.setTranscoderPath("https://unpkg.com/three@0.180.0/examples/jsm/libs/basis/"); ktx2Loader.detectSupport(renderer); gltfLoader.setKTX2Loader(ktx2Loader); tilesRenderer.manager.addHandler(/\.(gltf|glb)$/g, gltfLoader); tilesRenderer.setCamera(camera); tilesRenderer.setResolutionFromRenderer(camera, renderer); // 更新矩阵并设置相机位置 let loadedTileSetHandled = false; tilesRenderer.addEventListener("load-tile-set", () => { if (loadedTileSetHandled) return; loadedTileSetHandled = true; const sphere = new THREE.Sphere(); tilesRenderer.getBoundingSphere(sphere); const center = sphere.center.clone(); // 获取包围球中心 const radius = sphere.radius; // 获取包围球半径 controls.target.copy(center); // 把控制器目标设为包围球中心 const offset = new THREE.Vector3(radius * 2, radius, 0); // 给相机一个偏移 camera.position.copy(center).add(offset); // 设置相机位置 const m = (tilesRenderer as any).root.transform; // 获取原始矩阵 const rotationMat3 = new THREE.Matrix3().set(m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]); // 取出旋转部分 rotationMat3.transpose(); // 逆旋转 const rotationMat4 = new THREE.Matrix4().setFromMatrix3(rotationMat3); // 转回Matrix4以便应用 const rotX90 = new THREE.Matrix4().makeRotationX((90 * Math.PI) / 180); // x轴旋转90度矩阵 rotationMat4.multiply(rotX90); // 合并矩阵(由z轴向上坐标系 转为 y轴向上坐标系) const translationMatrix1 = new THREE.Matrix4().makeTranslation(center.x, center.y, center.z); // T(center) const translationMatrix2 = new THREE.Matrix4().makeTranslation(-center.x, -center.y, -center.z); // T(-center) const finalMatrix = new THREE.Matrix4().multiplyMatrices(translationMatrix1, rotationMat4).multiply(translationMatrix2); // 最终矩阵 = T(center)R⁻¹T(-center) tilesRenderer.group.matrix.copy(finalMatrix); // 设置矩阵 tilesRenderer.group.matrixAutoUpdate = false; // 禁止自动更新矩阵 tilesRenderer.group.updateMatrixWorld(true); // 更新矩阵 }); scene.add(tilesRenderer.group); // 添加到场景 } */

    完整源码:GitHub

    小结

    • 本文提供加载3dtiles完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
http://www.jsqmd.com/news/1113689/

相关文章:

  • 突破品类边界:智能模板机全域缝制解决方案
  • YOLOv10模型改进-Backbone改进-第53篇: YOLOv10改进策略【Backbone】| VGG16 Backbone替换
  • 从Notebook到生产环境的ML服务化实战:稳定性、可观测性与数据漂移监控
  • 模型服务化实战:从Notebook到生产就绪的12个关键环节
  • 深入解析OWASP A08:软件与数据完整性故障的防御实战
  • 计算机毕业设计之基于Java的NBA球队管理系统
  • AI Agent开发实战:核心技术、行业应用与优化策略
  • 开源与闭源大模型选型实战:从TCO、风险到混合架构决策
  • 《HarmonyOS技术精讲-Media Library Kit》之文件操作进阶
  • CentOS 7怎么搭建服务器监控告警?Prometheus与Alertmanager邮件通知教程
  • 条码/标签打印软件帮助车间标签打印混乱的难题终于理顺了
  • 2026中国AI先锋企业TOP30榜单正式揭晓|第一新声
  • AI Agent 工具接入多个模型时,API 中转层要先看哪些真实指标
  • PhotoGIMP终极指南:如何在3天内从Photoshop零成本迁移到开源图像编辑
  • 5分钟搞定WPS文献引用:免费开源插件让科研写作效率翻倍
  • VSCode——打开大型项目提示 `OOM (Out of Memory)` 的解决方案
  • mobaxterm vim +y复制到命令行卡住
  • Selenium自动化测试避坑指南:从环境配置到框架设计的实战解决方案
  • Windows微信QQ防撤回补丁RevokeMsgPatcher原理与配置详解
  • 数据库查询优化器<2>物理计划搜索和代价估计
  • Docker完整学习笔记
  • 直方图的替代方案:箱线图、KDE与小提琴图实战指南
  • Recrute Staffing Recruiting Agency WordPress Theme: Review, Installation Guide, and Setup Walkthro
  • std::move用法
  • Python 虚拟环境终极指南:16 款工具分类盘点,一文终结你的选择困难症
  • Steam饰品价格追踪系统:3步搭建24小时自动监控的完整指南
  • 多维聚合与数据变形:从维度语义到度量聚合的工程实践
  • PHP应用安全实践:Tempest Framework加密组件设计与核心原理
  • 如何5步构建企业级CMDB系统:open-cmdb终极指南
  • 官司胜诉也难以回款,中资企业承建阿塞拜疆基建分包项目深陷经营困境