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

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

<!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以进行数据解析

<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并加入场景中

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渲染器

function animate() {
    requestAnimationFrame(animate);
    tilesRenderer.update();
    // ...
    renderer.render(scene, camera);
}

加载的结果如下:

image-20240320163435241

完整代码如下:

<!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>

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

image-20240320163934943

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

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)

[2] 3D Tiles Renderer Options Example (nasa-ammos.github.io)

[3] threejs加载3dtiles(倾斜摄影)数据_threejs 3dtiles-CSDN博客

posted @ 2024-03-20 23:21  当时明月在曾照彩云归  阅读(273)  评论(4编辑  收藏  举报