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)

相关推荐
Nan_Shu_6141 天前
学习: Threejs (15)& Threejs (16)
学习·three.js
Charlie_lll1 天前
学习Three.js–材质(Material)
前端·three.js
答案—answer5 天前
开源项目:Three.js3D模型可视化编辑系统
javascript·3d·开源·开源项目·three.js·three.js编辑器
贝格前端工场5 天前
困在像素里:我的可视化大屏项目与前端价值觉醒
前端·three.js
全栈王校长6 天前
Three.js 材质进阶
webgl·three.js
全栈王校长6 天前
Three.js Geometry进阶
webgl·three.js
烛阴7 天前
3D字体TextGeometry
前端·webgl·three.js
全栈王校长7 天前
Three.js 开发快速入门
three.js
全栈王校长7 天前
Three.js 环境搭建与开发初识
three.js
DaMu7 天前
Dreamcore3D ARPG IDE “手搓”游戏引擎,轻量级实时3D创作工具,丝滑操作,即使小白也能轻松愉快的创作出属于你自己的游戏世界!
前端·架构·three.js