概要
「3D City Experience lab.」では、渋谷駅周辺の都市3Dモデルがオープンデータで公開されています。
サイトではデータ閲覧ソフトとしてMeshLabが紹介されているのですが、「これはやっぱりWebGLで表示したいよね」と思い、Three.jsで表示してみました。
都市3Dデータがオープンデータで公開されるとか、すごい時代になったもんだなあ。
— t_mat (@t_mat) June 23, 2019
渋谷の多様性が3Dデータによって浮かび上がる都市の新しい姿を捉えるビジュアライゼーション https://t.co/66XfC7ZBP0
使用したデータ・ライブラリ等
・渋谷駅周辺3Dデータ:https://3dcel.com/opendata/
・Three.js boilerplate:https://github.com/learnthreejs/three-js-boilerplate
※boilerplateはちょっと古いのですが、このまま使いました。
ファイル構成
ファイル構成は以下のとおりとしました。
なお、SizeLディレクトリ配下のobj等は3dcelよりダウンロードした渋谷駅周辺の都市3Dデータです。
- index.html
- script.js
- assets
- MTLLoader.js
- OBJLoader.js
- OrbitControls.js
- SizeL
- Tile_173078_LD_010_017_L22.mtl
- Tile_173078_LD_010_017_L22.obj
- Tile_173078_LD_010_017_L22_0.jpg
ソースコード
index.htmlは、ほぼboilerplateをそのまま使っています。
<html>
<head>
<title>渋谷駅周辺3Dデータ</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
<script src="assets/OrbitControls.js"></script>
<script src="assets/OBJLoader.js"></script>
<script src="assets/MTLLoader.js"></script>
<script src="scripts.js"></script>
</body>
</html>
script.jsは以下のとおりとしました。
モデルは平面直角第9系の座標になっているので、モデル読み込み後、中心を原点に移動させています。
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 100000 );
camera.position.z = 300;
camera.position.x = 0;
camera.position.y = 0;
camera.lookAt(new THREE.Vector3(0, 0, 0));
let renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
let controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = false;
controls.dampingFactor = 0.1;
controls.enableZoom = true;
let keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
let fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
let backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
let axis = new THREE.AxisHelper(10000);
axis.position.set(0,0,0);
scene.add(axis);
let mtlLoader = new THREE.MTLLoader();
mtlLoader.setTexturePath('assets/SizeL/');
mtlLoader.setPath('assets/SizeL/');
mtlLoader.load('Tile_173078_LD_010_017_L22.mtl', function (materials) {
materials.preload();
let objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('assets/SizeL/');
objLoader.load('Tile_173078_LD_010_017_L22.obj', function (object) {
scene.add(object);
fitCamera(object,camera);
});
});
let animate = function () {
requestAnimationFrame( animate );
controls.update();
renderer.render(scene, camera);
};
let getCompoundBoundingBox=function(object3D) {
var box = null;
object3D.traverse(function (obj3D) {
var geometry = obj3D.geometry;
if (geometry === undefined) return;
geometry.computeBoundingBox();
if (box === null) {
box = geometry.boundingBox;
} else {
box.union(geometry.boundingBox);
}
});
return box;
}
var fitCamera=function(object, camera) {
let bbox=getCompoundBoundingBox(object);
let xx=(bbox.max.x+bbox.min.x)/2;
let yy=(bbox.max.y+bbox.min.y)/2;
let zz=(bbox.max.z+bbox.min.z)/2;
object.position.set(-xx,-yy,-zz);
}
animate();
実行結果
VSCodeのliveServer等でindex.htmlを立ち上げると、しばらく待つとモデルが表示されます。
渋谷駅周辺3Dデータ©PASCO CORPORATION クリエイティブ・コモンズ・ライセンス(表示4.0 国際)
https://creativecommons.org/licenses/by/4.0/
GoogleMapと比べてみる
表示したモデルをGoogleMapの3Dモデル、ストリートビューと比較してみました。
あたり前ですが、一致していました。
https://t.co/Efm7p3Yhbwの渋谷駅周辺3DデータをThree.jsに読み込んで閲覧中。当たりまえですが、GoogleMapと一致しました。https://t.co/Uz7kTvRi3Rhttps://t.co/e4CR2Zee4g pic.twitter.com/xZ8ptwhSkS
— t_mat (@t_mat) June 25, 2019
感想
Three.jsはあまり使い慣れていないのですが、シーングラフでの3D構築は分かり易くて良いですね。Java3Dを思い出します。
しかし、都市3Dデータがオープンデータで公開されるとか、すごい時代になったものです。