Display Google Maps 3D Tiles using Giro3D and 3d-tiles-renderer.

100%

This example requires a Google Maps API key. You can register this key directly in the URL by appending ?key=THE_KEY in the URL, or enter the key in the text box.

index.js
import { Vector3 } from "three";

import { GlobeControls } from "3d-tiles-renderer";

import {
  GoogleCloudAuthPlugin,
  TileCompressionPlugin,
  UpdateOnChangePlugin,
  UnloadTilesPlugin,
  TilesFadePlugin,
} from "3d-tiles-renderer/plugins";

import Instance from "@giro3d/giro3d/core/Instance.js";
import Tiles3D from "@giro3d/giro3d/entities/Tiles3D.js";
import Inspector from "@giro3d/giro3d/gui/Inspector.js";

function run(apiKey) {
  const instance = new Instance({
    target: "view",
    crs: "EPSG:4978",
    backgroundColor: "black",
  });

  // Note that we need the DRACO and Basis libraries.
  // You can omit those parameters to use the default URLs which use a CDN.
  const entity = new Tiles3D({
    dracoDecoderPath: "/assets/wasm/",
    ktx2DecoderPath: "/assets/wasm/",
  });

  const tiles = entity.tiles;

  const view = instance.view;

  view.minNearPlane = 200;

  const camera = view.camera;
  camera.up = new Vector3(0, 0, 1);
  camera.position.set(30_000_000, 0, 0);
  camera.lookAt(0, 0, 0);

  camera.updateMatrixWorld();

  tiles.registerPlugin(
    new GoogleCloudAuthPlugin({ apiToken: apiKey, autoRefreshToken: true }),
  );
  tiles.registerPlugin(new TileCompressionPlugin());
  tiles.registerPlugin(new UpdateOnChangePlugin());
  tiles.registerPlugin(new UnloadTilesPlugin());
  tiles.registerPlugin(new TilesFadePlugin());

  const controls = new GlobeControls(
    instance.scene,
    camera,
    instance.domElement,
    tiles,
  );

  controls.enableDamping = true;

  const attributions = [];

  function updateAttributions() {
    attributions.length = 0;

    entity.tiles.getAttributions(attributions);

    const text = attributions.map((a) => a.value).join(",");

    StatusBar.setAttributionHtml(`© ${text}`);
  }

  function animate() {
    const altitude = controls.getDistanceToCenter() - 6_400_000;

    if (altitude > 100_000) {
      view.minNearPlane = 2000;
    } else if (altitude > 1_000) {
      view.minNearPlane = 200;
    } else {
      view.minNearPlane = 2;
    }

    controls.update();

    instance.notifyChange(entity);

    updateAttributions();

    requestAnimationFrame(animate);
  }

  animate();

  controls.update();

  instance.add(entity);

  Inspector.attach("inspector", instance);
}

const url = new URL(document.URL);
let key = url.searchParams.get("key");

if (key != null) {
  run(key);
} else {
  document.getElementById("warning").style.display = "block";
}

document.getElementById("start").onclick = () => {
  const enteredKey = document.getElementById("googleApiKey").value;

  if (enteredKey != null) {
    const url = new URL(document.URL);
    url.searchParams.delete("key");

    url.searchParams.append("key", enteredKey);

    window.history.replaceState({}, null, url.toString());

    run(enteredKey);

    document.getElementById("warning").style.display = "none";
  }
};
index.html
<!doctype html>
<html lang="en">
  <head>
    <title>Google Photorealistic 3D Tiles</title>
    <meta charset="UTF-8" />
    <meta name="name" content="google_photorealistic_3d_tiles" />
    <meta
      name="description"
      content="Display Google Maps 3D Tiles using Giro3D and &lt;a href=&#34;https://github.com/NASA-AMMOS/3DTilesRendererJS&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;3d-tiles-renderer&lt;/code&gt;&lt;/a&gt;."
    />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="icon" href="https://giro3d.org/images/favicon.svg" />
    <link
      href="https://giro3d.org/assets/bootstrap-custom.css"
      rel="stylesheet"
    />
    <script src="https://giro3d.org/assets/bootstrap.bundle.min.js"></script>
    <link
      rel="stylesheet"
      type="text/css"
      href="https://giro3d.org/latest/examples/css/example.css"
    />
  </head>

  <body>
    <div id="view" class="m-0 p-0 w-100 h-100"></div>
    <div
      id="inspector"
      class="position-absolute top-0 start-0 mh-100 overflow-auto"
    ></div>

    <div
      class="position-absolute top-50 start-50 translate-middle text-center"
      style="display: none"
      id="warning"
    >
      No Google Maps API key registered.<br />You can register this key directly
      in the URL by appending <code>?key=THE_KEY</code> in the URL,<br />or
      enter the key in the text box and press 'Reload'.
    </div>

    <div class="side-pane-with-status-bar">
      <div class="input-group">
        <input
          type="text"
          class="form-control"
          id="googleApiKey"
          placeholder="Google Tiles API key"
        />
        <button class="btn btn-primary" id="start">Reload</button>
      </div>
    </div>

    <script type="module" src="index.js"></script>
    <script>
      /* activate popovers */
      const popoverTriggerList = [].slice.call(
        document.querySelectorAll('[data-bs-toggle="popover"]'),
      );
      popoverTriggerList.map(
        // bootstrap is used as script in the template, disable warning about undef
        // eslint-disable-next-line no-undef
        (popoverTriggerEl) =>
          new bootstrap.Popover(popoverTriggerEl, {
            trigger: "hover",
            placement: "left",
            content: document.getElementById(
              popoverTriggerEl.getAttribute("data-bs-content"),
            ).innerHTML,
            html: true,
          }),
      );
    </script>
  </body>
</html>
package.json
{
    "name": "google_photorealistic_3d_tiles",
    "dependencies": {
        "@giro3d/giro3d": "0.42.1"
    },
    "devDependencies": {
        "vite": "^3.2.3"
    },
    "scripts": {
        "start": "vite",
        "build": "vite build"
    }
}