i-Vinci TechBlog
株式会社i-Vinciの技術ブログ

harp.glでMap上に3Dでオブジェクトを描いてみた

前にGoogle Mapに3Dで描画しましたが……

皆さんこんにちは。
株式会社i-Vinci、元自衛官エンジニアの藤田です。最近はチョコボールのエンゼル集めにはまっています。
さて前回、Google Maps PlatformのMaps JavaScript APIを使用してGoogle Map上にi-Vinciの立体的なオブジェクトを描画しました。
描画したのですが、なんとなくすっきりしないものを感じていたのでそれを今回は解決したいと思います。
すっきりしなかった点は、一言に尽きます。
「Google Mapに3Dのオブジェクトを描くのって、すごくやりづらかったからなんかイケてないんじゃね?」
なので今回は別の方法で地図上に社名である「i-Vinci」の3Dのオブジェクトを描いてみたいと思います。

harp.gl

いろいろと調べていると、地図上に3Dを描く方法のスタンダードとして、WebGLを利用して描く方法が用いられていることが分かりました。

WebGL - Wikipedia

WebGL技術の実装として様々なライブラリが作成されていて、地図上への3D描画をするライブラリもいくつか作成されているようですが、今回はharp.glというライブラリを使用したいと思います。

事前準備

harp.glを利用するためには、HERE Technologies社の開発者アカウントを作成した上でAPI Keyを作成する必要があります。詳細はこちらです。
特にめんどくさい入力もないのでサクッと作っちゃっていいと思います。

harp.glのインストール

harp.glを利用する方法は3つあります。

  1. Yeomonジェネレータの利用
  2. htmlファイルでのscriptタグによるバンドル
  3. npm を利用したインストール

詳細はこちらをご覧ください
今回はYeamonジェネレータを使用してベースとなるプロジェクトを作成しました。
無事installが完了し、npm startによりローカルでの起動を行った後にlocalhost:8080にブラウザからアクセスすると下図のような画面が表示されると思います。

表示されたMapを操作することで地点を切り替えることも可能ですが、index.tsで指定されている経緯度座標を指定することで別の地点の視点に切り替えることもできます。

harp.glはチュートリアルが充実しており、これを進めることで非常に短時間で概要を理解することが出来ます。

harp.glの概要は以下の様にまとめられます。

  1. WebGL技術を利用しているためcanvas要素に2D・3Dの地図を表示することが出来る
  2. 地図上に表示されるあらゆる要素の表示スタイルを好みの様式に変更することが出来る
  3. 静的なGeoJsonデータ、及びタイル情報をMap上に表示することが出来る
  4. データによって表示スタイルを変更することが出来る
  5. harp.glはThree.jsを基盤として作成されているため任意の3DデータをMap上に表示することが出来る

今回は、5.の機能を利用してBlenderで作成した3DオブジェクトをMap上に表示してみたいを思います。

3Dオブジェクトの表示

Blenderを利用して3Dオブジェクトを作成する工程は省略したいと思います。下図のようなオブジェクトを作成しました。

gltf形式にエクスポートしてプログラムで利用可能な形式に変換します。

次にYeamonジェネレータで作成されたindex.tsファイルを以下のように編集しました。

index.ts

import { GeoCoordinates } from "@here/harp-geoutils";
import { MapAnchor, MapViewEventNames } from "@here/harp-mapview";
import THREE = require("three");
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

import { View } from "./View";

const cood = { 
    lond: 40.707085,
    latd: -74.010727
}

const app = new View({
    canvas: document.getElementById("map") as HTMLCanvasElement
});

const mapView = app.mapView;
// make map full-screen
mapView.resize(window.innerWidth, window.innerHeight);

// react on resize events from the browser.
window.addEventListener("resize", () => {
    mapView.resize(window.innerWidth, window.innerHeight);
});

let heading = -90;
mapView.addEventListener(MapViewEventNames.Render, () => {
    mapView.lookAt({ heading });
    heading += 0.2;
});
mapView.beginAnimation();

const anchor = new THREE.Object3D() as MapAnchor;
anchor.anchor = new GeoCoordinates(cood.lond, cood.latd, 0);
mapView.mapAnchors.add(anchor);

async function getIVinci() {
    const loader = new GLTFLoader();
    loader.load('./resources/vinci.glb', (gltf) => {
        anchor.add(gltf.scene);
        mapView.update();
    }, 
    undefined, 
    (error) => console.log(error));
    mapView.lookAt({
        target: new GeoCoordinates(cood.lond, cood.latd),
        tilt: 75,
        zoomLevel: 16,
    });
    mapView.update();
}
getIVinci();

// make sure the map is rendered
mapView.update();

上記のコードで以下のように3DオブジェクトをMap上に表示させたうえで、視点を徐々に回転させることが出来ます。

要となるコードについて説明します。


let heading = -90;
mapView.addEventListener(MapViewEventNames.Render, () => {
    mapView.lookAt({ heading });
    heading += 0.2;
});
mapView.beginAnimation();

<pre><code><br />-90°方向で視点を初期化し、描画されるごとに0.2°ずつ回転させています。
たった数行のコードで非常に動きのある画面を作ることが出来ます。

```index.ts
async function getIVinci() {
    const loader = new GLTFLoader();
    loader.load(&#039;./resources/vinci.glb&#039;, (gltf) => {
        anchor.add(gltf.scene);
        mapView.update();
    }, 
    undefined, 
    (error) => console.log(error));
    mapView.lookAt({
        target: new GeoCoordinates(cood.lond, cood.latd),
        tilt: 75,
        zoomLevel: 16,
    });
    mapView.update();
}
getIVinci();

この関数でオブジェクトの読み込み、配置、Mapの更新を行っています。
GLTF形式のデータの取り扱いが少し独特ではあると思いますが、Three.jsなどに触れたことがる人はすぐになれると思います。

まとめ

非常に少ないコードでMap上に3Dオブジェクトを描画することが出来ました。Google Map上に無理やり3Dを描画したときに比べてクオリティも良鋳物になりました。

今回は3Dオブジェクトを描画することに挑戦しましたが、harp.glを利用することで様々なデータをMap上に描画することが出来ます。
例えば、、、

  • GeoJsonデータとして地点情報が管理された重要な場所を3Dの地図上に表示する
  • リアルタイムで気象庁などが配信する気象情報をMap上に好みのスタイルで描画する
  • 複数の携帯端末から位置情報を取得し、リアルタイムでそれぞれの端末の現在位置をMap上に表示する

などなど、利用できるシーンは非常に幅広いです。

今回作成したコードはこちら

以下harp.glのチュートリアル中に作成した地図。鉄道の路線情報を赤線で表示しています。