LoginSignup
7
3

MapLibre GL JS + deck.gl + Google Photorealistic 3D Tilesを試す

Last updated at Posted at 2023-05-19

はじめに

前提条件

  • Google Maps PlatformのAPIキーを取得済みであること。

※Google Maps Platform APIキーの取得・発行についてはこちらを参照してください。
https://www.zenrin-datacom.net/business/gmapsapi/api_key/index.html

deck.glのレイヤーをMapLibre GL JSに組み込む方法

  • MapLibre GL JSでGoogleのPhotorealistic 3D Tilesを表示するためには、deck.glのTile3DLayerを使用する必要があります。
  • deck.glのTile3DLayerをMapLibre GL JSに組み込むには主に3つの方法があるようです。
  • 下記のブログ記事に詳しく書かれています(おすすめは方法2とのこと📝)。
  • 方法1、方法2及び方法3について紹介します。

方法1:MapboxOverlayを使ったオーバーレイ
方法2:MapboxOverlayを使ったインターリーブ(おすすめ📝)

  • オーバーレイ、インターリーブの違いはこちらのページの図がわかりやすいです。
  • オーバーレイは、2つのライブラリが相互に独立してレンダリングを管理する仕様のようです。
  • 一方で、インターリーブは、deck.glのレイヤーとMapLibre GL JSのレイヤーのオクルージョンが可能になるようです(方法2がおすすめな理由はここにありそうです📝)。

方法3:MapboxLayerを使ったインターリーブ

  • 方法3は、上記の方法2に近い仕様のようです(オクルージョンが可能かなどは試して確認したいところです)。

MapboxOverlayを使ったオーバーレイ

  • Google Maps PlatformのAPIキーは、ご自身で用意してください。
  • GoogleのPhotorealistic 3D Tilesの表示には、deck.glのMapboxOverlay及びTile3DLayerを使用します。
  • MapboxOverlayのオーバーレイは、interleavedをfalseにすることで機能するようです。
  • map.addControlでdeck.glのレイヤーをMapLibre GL JSのコントロールとして追加できるようです。

コード

<html>

<head>
  <title>Google 3D tiles example</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js"></script>
  <link href="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css" rel="stylesheet">
  <script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }

    #credits {
      position: absolute;
      bottom: 0;
      right: 0;
      padding: 2px;
      font-size: 15px;
      color: white;
      text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
      z-index: 1000;
    }

    #credits a {
      color: white;
      pointer-events: auto;
    }
  </style>
</head>

<body>
  <div id="map"></div>
  <div id="credits"></div>
  <script type="text/javascript">
    // 【参考】https://developers.google.com/maps/documentation/tile/use-renderer?hl=ja
    const GOOGLE_API_KEY = 'YOUR_API_KEY';
    const TILESET_URL = `https://tile.googleapis.com/v1/3dtiles/root.json`;
    const creditsElement = document.getElementById('credits');

    const map = new maplibregl.Map({
      container: 'map',
      style: {
        version: 8,
        sources: {},
        layers: []
      },
      hash: true,
      zoom: 16,
      center: [139.7660988, 35.6808658],
      pitch: 60,
      bearing: 0,
      attributionControl: false,
    })

    // ズーム・回転
    map.addControl(new maplibregl.NavigationControl());

    // フルスクリーンモードのオンオフ
    map.addControl(new maplibregl.FullscreenControl());

    // 現在位置表示
    map.addControl(new maplibregl.GeolocateControl({
      positionOptions: {
        enableHighAccuracy: false
      },
      fitBoundsOptions: { maxZoom: 18 },
      trackUserLocation: true,
      showUserLocation: true
    }));

    // スケール表示
    map.addControl(new maplibregl.ScaleControl({
      maxWidth: 200,
      unit: 'metric'
    }));

    map.on('load', () => {
      // MapboxOverlayを使ったオーバーレイ
      const overlay = new deck.MapboxOverlay({
        interleaved: false,
        layers: [
          new deck.Tile3DLayer({
            id: 'google-3d-tiles',
            data: TILESET_URL,
            loadOptions: {
              fetch: {
                headers: {
                  'X-GOOG-API-KEY': GOOGLE_API_KEY
                }
              }
            },
            onTilesetLoad: tileset3d => {
              tileset3d.options.onTraversalComplete = selectedTiles => {
                const credits = new Set();
                selectedTiles.forEach(tile => {
                  const { copyright } = tile.content.gltf.asset;
                  copyright.split(';').forEach(credits.add, credits);
                  creditsElement.innerHTML = [...credits].join('; ');
                });
                return selectedTiles;
              }
            }
          })
        ]
      });

      map.addControl(overlay);

    })
  </script>
</body>

</html>

MapboxOverlayを使ったインターリーブ

  • Google Maps PlatformのAPIキーは、ご自身で用意してください。
  • GoogleのPhotorealistic 3D Tilesの表示には、deck.glのMapboxOverlay及びTile3DLayerを使用します。
  • MapboxOverlayのインターリーブは、interleavedをtrueにすることで機能するようです。
  • map.addControlでdeck.glのレイヤーをMapLibre GL JSのコントロールとして追加できるようです。

コード

<html>

<head>
  <title>Google 3D tiles example</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js"></script>
  <link href="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css" rel="stylesheet">
  <script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }

    #credits {
      position: absolute;
      bottom: 0;
      right: 0;
      padding: 2px;
      font-size: 15px;
      color: white;
      text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
      z-index: 1;
    }

    #credits a {
      color: white;
      pointer-events: auto;
    }
  </style>
</head>

<body>
  <div id="map"></div>
  <div id="credits"></div>
  <script type="text/javascript">
    // 【参考】https://developers.google.com/maps/documentation/tile/use-renderer?hl=ja
    const GOOGLE_API_KEY = 'YOUR_API_KEY';
    const TILESET_URL = `https://tile.googleapis.com/v1/3dtiles/root.json`;
    const creditsElement = document.getElementById('credits');

    const map = new maplibregl.Map({
      container: 'map',
      style: {
        version: 8,
        sources: {},
        layers: []
      },
      hash: true,
      zoom: 16,
      center: [139.7660988, 35.6808658],
      pitch: 60,
      bearing: 0,
      attributionControl: false,
    })

    // ズーム・回転
    map.addControl(new maplibregl.NavigationControl());

    // フルスクリーンモードのオンオフ
    map.addControl(new maplibregl.FullscreenControl());

    // 現在位置表示
    map.addControl(new maplibregl.GeolocateControl({
      positionOptions: {
        enableHighAccuracy: false
      },
      fitBoundsOptions: { maxZoom: 18 },
      trackUserLocation: true,
      showUserLocation: true
    }));

    // スケール表示
    map.addControl(new maplibregl.ScaleControl({
      maxWidth: 200,
      unit: 'metric'
    }));

    map.on('load', () => {
      // MapboxOverlayを使ったインターリーブ
      const overlay = new deck.MapboxOverlay({
        interleaved: true,
        layers: [
          new deck.Tile3DLayer({
            id: 'google-3d-tiles',
            data: TILESET_URL,
            loadOptions: {
              fetch: {
                headers: {
                  'X-GOOG-API-KEY': GOOGLE_API_KEY
                }
              }
            },
            onTilesetLoad: tileset3d => {
              tileset3d.options.onTraversalComplete = selectedTiles => {
                const credits = new Set();
                selectedTiles.forEach(tile => {
                  const { copyright } = tile.content.gltf.asset;
                  copyright.split(';').forEach(credits.add, credits);
                  creditsElement.innerHTML = [...credits].join('; ');
                });
                return selectedTiles;
              }
            },
            beforeId: 'admin_labels'
          })
        ]
      });

      map.addControl(overlay);

    })
  </script>
</body>

</html>

MapboxLayerを使ったインターリーブ

  • Google Maps PlatformのAPIキーは、ご自身で用意してください。
  • GoogleのPhotorealistic 3D Tilesの表示には、deck.glのMapboxLayer及びTile3DLayerを使用します。
  • map.addLayerでdeck.glのレイヤーがMapLibre GL JSのカスタムスタイルレイヤー(よくわかっていません・・・)として追加されるようです。

コード

<html>

<head>
  <title>Google 3D tiles example</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js"></script>
  <link href="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css" rel="stylesheet">
  <script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 100%;
    }

    #credits {
      position: absolute;
      bottom: 0;
      right: 0;
      padding: 2px;
      font-size: 15px;
      color: white;
      text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
      z-index: 1;
    }

    #credits a {
      color: white;
      pointer-events: auto;
    }
  </style>
</head>

<body>
  <div id="map"></div>
  <div id="credits"></div>
  <script type="text/javascript">
    // 【参考】https://developers.google.com/maps/documentation/tile/use-renderer?hl=ja
    const GOOGLE_API_KEY = 'YOUR_API_KEY';
    const TILESET_URL = `https://tile.googleapis.com/v1/3dtiles/root.json`;
    const creditsElement = document.getElementById('credits');

    const map = new maplibregl.Map({
      container: 'map',
      style: {
        version: 8,
        sources: {},
        layers: []
      },
      hash: true,
      zoom: 16,
      center: [139.7660988, 35.6808658],
      pitch: 60,
      bearing: 0,
      attributionControl: false,
    })

    // ズーム・回転
    map.addControl(new maplibregl.NavigationControl());

    // フルスクリーンモードのオンオフ
    map.addControl(new maplibregl.FullscreenControl());

    // 現在位置表示
    map.addControl(new maplibregl.GeolocateControl({
      positionOptions: {
        enableHighAccuracy: false
      },
      fitBoundsOptions: { maxZoom: 18 },
      trackUserLocation: true,
      showUserLocation: true
    }));

    // スケール表示
    map.addControl(new maplibregl.ScaleControl({
      maxWidth: 200,
      unit: 'metric'
    }));

    map.on('load', () => {

      const { MapboxLayer, Tile3DLayer } = deck;

      // MapboxLayerを使ったインターリーブ
      const tile3dLayer = new MapboxLayer({
        id: 'google-3d-tiles',
        type: Tile3DLayer,
        data: TILESET_URL,
        loadOptions: {
          fetch: {
            headers: {
              'X-GOOG-API-KEY': GOOGLE_API_KEY
            }
          }
        },
        onTilesetLoad: tileset3d => {
          tileset3d.options.onTraversalComplete = selectedTiles => {
            const credits = new Set();
            selectedTiles.forEach(tile => {
              const { copyright } = tile.content.gltf.asset;
              copyright.split(';').forEach(credits.add, credits);
              creditsElement.innerHTML = [...credits].join('; ');
            });
            return selectedTiles;
          }
        }
      });

      map.addLayer(tile3dLayer);

    })
  </script>
</body>

</html>

参考文献

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3