Three.js中加载和渲染3D Tiles

1. 引言

3D Tiles 是 3D GIS 中常见的三维数据格式,能否用Three.js来加载渲染呢?肯定是可以,Three.js只是一个WebGL框架,渲染数据肯定可以,但是加载、解析数据得手动解决

有没有一个第三方库解决这个问题呢?有,比如这个:NASA-AMMOS/3DTilesRendererJS: Renderer for 3D Tiles in Javascript using three.js (github.com)

这里就简要记录如何在Three.js中加载 3D Tiles

2. 加载3D Tiles

首先,搭建一个简单的三维场景

html 复制代码
<!DOCTYPE html>
<html lang="en">
 
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<style>
		html,
		body,
		canvas {
			height: 100%;
			width: 100%;
			margin: 0;
		}
	</style>
	
</head>
 
<body>
	<canvas id="canvas"></canvas>
 
	<script type="importmap">
		{
			"imports": {
				"three": "https://unpkg.com/three/build/three.module.js",
				"three/addons/": "https://unpkg.com/three/examples/jsm/"
			}
		}
	</script>
	
	<script type="module">
		import * as THREE from 'three';
		import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
		const scene = new THREE.Scene();
 
		const canvas = document.querySelector('#canvas');
		const camera = new THREE.PerspectiveCamera(75,  canvas.clientWidth / canvas.clientHeight , 0.1, 1000);
		camera.position.z = 5;
 
		const renderer = new THREE.WebGLRenderer({
			canvas: document.querySelector('#canvas')
		});
		renderer.setSize(window.innerWidth, window.innerHeight, false)
		
		const geometry = new THREE.BoxGeometry(1, 1, 1);
		const material = new THREE.MeshPhongMaterial({
			color: 0x00ff00
		});
		const cube = new THREE.Mesh(geometry, material);
		scene.add(cube);
 
		const light = new THREE.DirectionalLight(0xffffff, 1);
		light.position.set(0, 0, 5);
		scene.add(light);
 
		const controls = new OrbitControls( camera, renderer.domElement );
		
		function animate() {
			requestAnimationFrame(animate);
			cube.rotation.x += 0.01;
			cube.rotation.y += 0.01;
			renderer.render(scene, camera);
		}
		animate();
	</script>
</body>
 
</html>

然后是引入3DTilesRendererJS,这里引入的是GoogleTilesRenderer来加载Google的在线地图,另外还需要使用GLTFLoaderDRACOLoader以进行数据解析

html 复制代码
<script type="importmap">
		{
			"imports": {
				"three": "https://unpkg.com/three/build/three.module.js",
				"three/addons/": "https://unpkg.com/three/examples/jsm/",
                "3DTilesRendererJS": "https://cdn.jsdelivr.net/npm/3d-tiles-renderer@0.3.30/+esm"
			}
		}
</script>

<script type="module">
    import * as THREE from 'three';
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
    import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
    import { TilesRenderer, GoogleTilesRenderer } from '3DTilesRendererJS'
    import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
    // ...
</script>

下一步是加载谷歌在线3D Tiles并加入场景中

javascript 复制代码
const tilesRenderer = new GoogleTilesRenderer( 'AIzaSyBQ7Wj99aTxRqET-22qYWGFcDCWgVDt89A' ); // 传入的是谷歌倾斜摄影的API key
tilesRenderer.setLatLonToYUp( 36.266494 * THREE.MathUtils.DEG2RAD, 120.460205 * THREE.MathUtils.DEG2RAD ); // Tokyo Tower

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

const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath( 'https://unpkg.com/three@0.153.0/examples/jsm/libs/draco/gltf/' );

const loader = new GLTFLoader( tilesRenderer.manager );
loader.setDRACOLoader( dracoLoader );

tilesRenderer.manager.addHandler( /\.gltf$/, loader );

scene.add( tilesRenderer.group );

最后在每一帧中更新3D Tiles渲染器

javascript 复制代码
function animate() {
    requestAnimationFrame(animate);
    tilesRenderer.update();
    // ...
    renderer.render(scene, camera);
}

加载的结果如下:

完整代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="en">
 
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<style>
		html,
		body,
		canvas {
			height: 100%;
			width: 100%;
			margin: 0;
		}
	</style>
	
</head>
 
<body>
	<canvas id="canvas"></canvas>
 
	<script type="importmap">
		{
			"imports": {
				"three": "https://unpkg.com/three/build/three.module.js",
				"three/addons/": "https://unpkg.com/three/examples/jsm/"
			}
		}
	</script>
	
	<script type="module">
		import * as THREE from 'three';
		import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
		import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
        import { TilesRenderer, GoogleTilesRenderer } from 'https://cdn.jsdelivr.net/npm/3d-tiles-renderer@0.3.30/+esm'
        import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
 
		const scene = new THREE.Scene();
 
		const canvas = document.querySelector('#canvas');
		const camera = new THREE.PerspectiveCamera(75,  canvas.clientWidth / canvas.clientHeight , 0.1, 100000);
		camera.position.y = 500;
		camera.position.z = 500;
 
		const renderer = new THREE.WebGLRenderer({
			canvas: document.querySelector('#canvas')
		});
		renderer.setSize(window.innerWidth, window.innerHeight, false)
 
		const controls = new OrbitControls( camera, renderer.domElement );

        const tilesRenderer = new GoogleTilesRenderer( 'AIzaSyBQ7Wj99aTxRqET-22qYWGFcDCWgVDt89A' );
        tilesRenderer.setLatLonToYUp( 35.6586 * THREE.MathUtils.DEG2RAD, 139.7454 * THREE.MathUtils.DEG2RAD ); // Tokyo Tower

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

        const dracoLoader = new DRACOLoader();
        dracoLoader.setDecoderPath( 'https://unpkg.com/three@0.153.0/examples/jsm/libs/draco/gltf/' );

        const loader = new GLTFLoader( tilesRenderer.manager );
        loader.setDRACOLoader( dracoLoader );

        tilesRenderer.manager.addHandler( /\.gltf$/, loader );

        scene.add( tilesRenderer.group );
		
		function animate() {
			requestAnimationFrame(animate);
            tilesRenderer.update();
			renderer.render(scene, camera);
		}
		animate();
	</script>
</body>
 
</html>

上面加载的是日本东京的倾斜摄影数据,那在没有倾斜摄影数据的地方呢,比如中国的某些城市,答案是会加载类似于高程与遥感影像的合成数据,如下图:

此时只是把经纬度做以下修改:

javascript 复制代码
tilesRenderer.setLatLonToYUp( 36.266494 * THREE.MathUtils.DEG2RAD, 120.460205 * THREE.MathUtils.DEG2RAD ); // 山东青岛

总的来说,有时可以在Three.js中加载这样的3D Tiles作为底图来使用,更多的使用方法可参考官方文档:NASA-AMMOS/3DTilesRendererJS: Renderer for 3D Tiles in Javascript using three.js (github.com)

3. 参考资料

1\] [NASA-AMMOS/3DTilesRendererJS: Renderer for 3D Tiles in Javascript using three.js (github.com)](https://github.com/NASA-AMMOS/3DTilesRendererJS) \[2\] [3D Tiles Renderer Options Example (nasa-ammos.github.io)](https://nasa-ammos.github.io/3DTilesRendererJS/example/bundle/ionExample.html) \[3\] [threejs加载3dtiles(倾斜摄影)数据_threejs 3dtiles-CSDN博客](https://blog.csdn.net/weixin_39481659/article/details/121270254)

相关推荐
刘皇叔code16 小时前
PBR学习笔记与Three.js中MeshPhysicalMaterial源码阅读
webgl·three.js
答案answer16 小时前
1K+star,回顾一下我的开源之路
前端·程序员·three.js
谢小飞2 天前
一款解压的3D方块加载动画效果
前端·three.js
小桥风满袖7 天前
Three.js-硬要自学系列40之专项学习缓冲几何体法线属性
前端·css·three.js
Mintopia10 天前
🧠 从像素到现实:用 Three.js + Cesium 构建数字孪生系统
前端·javascript·three.js
Mintopia10 天前
🧱 用三维点亮前端宇宙:构建你自己的 Three.js 组件库
前端·javascript·three.js
curdcv_po11 天前
🔥🔥🔥结合 vue 或 react,去写three.js
前端·react.js·three.js
VincentFHR12 天前
Three.js 利用 shader 实现 3D 热力图
前端·three.js·canvas
星_离12 天前
初识Threejs
前端·three.js
火车叼位12 天前
threejs api速查表, 你的下一个鼠标垫图案素材
前端·api·three.js