کار کردن با پردازنده «کاشی‌های سه‌بعدی»

توسعه‌دهندگان منطقه اقتصادی اروپا (EEA)

«کاشی‌های سه‌بعدی واقع‌نما» در قالب glTF استاندارد OGC هستند، یعنی می‌توانید از هر پردازگری که از مشخصات «کاشی‌های سه‌بعدی OGC» پشتیبانی می‌کند برای ساختن مصورسازی‌های سه‌بعدی خود استفاده کنید. برای مثال، Cesium یک کتابخانه متن‌باز بنیادی برای رندر کردن تجسم‌های سه‌بعدی است.

کار با CesiumJS

CesiumJS یک کتابخانه جاوا اسکریپت متن‌باز برای دیداری‌سازی سه‌بعدی در وب است. برای اطلاعات بیشتر درباره استفاده از CesiumJS، به آشنایی با CesiumJS مراجعه کنید.

کنترل‌های کاربر

پردازنده کاشی CesiumJS دارای مجموعه‌ای استاندارد از کنترل‌های کاربر است.

کنش شرح
نمای پانوراما کلیک چپ و کشیدن
نمای بزرگ‌نمایی کلیک راست کنید و بکشید، یا چرخ موشواره را بچرخانید
چرخاندن نما Ctrl + کلیک چپ/راست و کشیدن، یا کلیک وسط و کشیدن

روال‌های مطلوب

چندین رویکرد وجود دارد که می‌توانید برای کاهش زمان بار کردن CesiumJS 3D اتخاذ کنید. برای مثال:

  • با افزودن عبارت زیر به HTML پرداز، درخواست‌های هم‌زمان را فعال کنید:

    Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = <REQUEST_COUNT>
    

    هرچه REQUEST_COUNT بالاتر باشد، کاشی‌ها سریع‌تر بار می‌شوند. بااین‌حال، هنگام بار کردن در مرورگر Chrome با REQUEST_COUNT بیشتر از ۱۰ و حافظه نهان غیرفعال، ممکن است با یک مشکل شناخته‌شده Chrome مواجه شوید. برای اکثر موارد استفاده، REQUEST_COUNT ۱۸ را برای عملکرد بهینه توصیه می‌کنیم.

  • رد شدن از سطوح جزئیات را فعال کنید. برای اطلاعات بیشتر، این مشکل Cesium را ببینید.

با فعال کردن showCreditsOnScreen: true، مطمئن شوید که ارجاع‌های داده را به‌درستی نمایش می‌دهید. برای اطلاعات بیشتر، خط‌مشی‌ها را ببینید.

سنجه‌های پرداز زدن

برای پیدا کردن نرخ فریم، ببینید روش requestAnimationFrame چند بار در ثانیه فراخوانی می‌شود.

برای دیدن نحوه محاسبه تأخیر فریم، به کلاس PerformanceDisplay نگاهی بیندازید.

نمونه‌های پردازنده CesiumJS

می‌توانید از پردازنده CesiumJS با «کاشی‌های سه‌بعدی» Map Tiles API استفاده کنید، کافی است نشانی وب مجموعه کاشی ریشه را ارائه دهید.

مثال ساده

مثال زیر رندرکننده CesiumJS را مقداردهی اولیه می‌کند و سپس مجموعه کاشی ریشه را بار می‌کند.

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <title>CesiumJS 3D Tiles Simple Demo</title>
  <script src="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Cesium.js"></script>
  <link href="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>
  <div id="cesiumContainer"></div>
  <script>

    // Enable simultaneous requests.
    Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = 18;

    // Create the viewer.
    const viewer = new Cesium.Viewer('cesiumContainer', {
      imageryProvider: false,
      baseLayerPicker: false,
      geocoder: false,
      globe: false,
      // https://cesium.com/blog/2018/01/24/cesium-scene-rendering-performance/#enabling-request-render-mode
      requestRenderMode: true,
    });

    // Add 3D Tiles tileset.
    const tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
      url: "https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY",
      // This property is needed to appropriately display attributions
      // as required.
      showCreditsOnScreen: true,
    }));
  </script>
</body>

برای اطلاعات درباره requestRenderMode، فعال کردن حالت ارائه درخواست را ببینید.

صفحه HTML به‌صورت نشان‌داده‌شده در اینجا ارائه می‌شود.

ادغام Places API (جدید)

می‌توانید از CesiumJS با Places API (جدید) برای بازیابی اطلاعات بیشتر استفاده کنید. می‌توانید از ابزارک «تکمیل خودکار» برای پرواز به نمای «مکان‌ها» استفاده کنید. این نمونه از Places Autocomplete API استفاده می‌کند که با دنبال کردن این دستورالعمل‌ها فعال می‌شود، و Maps JavaScript API که با دنبال کردن این دستورالعمل‌ها فعال می‌شود.

<!DOCTYPE html>
<head>
 <meta charset="utf-8" />
 <title>CesiumJS 3D Tiles Places API (New) Integration Demo</title>
 <script src="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Cesium.js"></script>
 <link href="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>
 <label for="pacViewPlace">Go to a place: </label>
 <input
   type="text"
   id="pacViewPlace"
   name="pacViewPlace"
   placeholder="Enter a location..."
   style="width: 300px"
 />
 <div id="cesiumContainer"></div>
 <script>
   // Enable simultaneous requests.
   Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = 18;

   // Create the viewer.
   const viewer = new Cesium.Viewer("cesiumContainer", {
     imageryProvider: false,
     baseLayerPicker: false,
     requestRenderMode: true,
     geocoder: false,
     globe: false,
   });

   // Add 3D Tiles tileset.
   const tileset = viewer.scene.primitives.add(
     new Cesium.Cesium3DTileset({
       url: "https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY",
       // This property is required to display attributions as required.
       showCreditsOnScreen: true,
     })
   );

   const zoomToViewport = (viewport) => {
     viewer.entities.add({
       polyline: {
         positions: Cesium.Cartesian3.fromDegreesArray([
           viewport.getNorthEast().lng(), viewport.getNorthEast().lat(),
           viewport.getSouthWest().lng(), viewport.getNorthEast().lat(),
           viewport.getSouthWest().lng(), viewport.getSouthWest().lat(),
           viewport.getNorthEast().lng(), viewport.getSouthWest().lat(),
           viewport.getNorthEast().lng(), viewport.getNorthEast().lat(),
         ]),
         width: 10,
         clampToGround: true,
         material: Cesium.Color.RED,
       },
     });
     viewer.flyTo(viewer.entities);
   };

   function initAutocomplete() {
     const autocomplete = new google.maps.places.Autocomplete(
       document.getElementById("pacViewPlace"),
       {
         fields: [
           "geometry",
           "name",
         ],
       }
     );
     autocomplete.addListener("place_changed", () => {
       viewer.entities.removeAll();
       const place = autocomplete.getPlace();
       if (!place.geometry || !place.geometry.viewport) {
         window.alert("No viewport for input: " + place.name);
         return;
       }
       zoomToViewport(place.geometry.viewport);
     });
   }
 </script>
 <script
   async=""
   src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initAutocomplete"
 ></script>
</body>

نمای پهپاد درحال چرخش

می‌توانید دوربین را کنترل کنید تا در مجموعه کاشی‌ها پویانمایی کند. وقتی این پویانمایی با Places API (جدید) و Elevation API ترکیب می‌شود، پرواز تعاملی پهپاد بر فراز هر مکان نشان‌دار را شبیه‌سازی می‌کند.

این نمونه کد شما را به اطراف مکانی که در ابزاره «تکمیل خودکار» انتخاب کرده‌اید می‌برد.

<!DOCTYPE html>
<head>
  <meta charset="utf-8" />
  <title>CesiumJS 3D Tiles Rotating Drone View Demo</title>
  <script src="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Cesium.js"></script>
  <link href="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>
  <label for="pacViewPlace">Go to a place: </label>
  <input type="text" id="pacViewPlace" name="pacViewPlace" placeholder="Enter a location..." style="width: 300px" />
  <div id="cesiumContainer"></div>
  <script>
    // Enable simultaneous requests.
    Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = 18;

    // Create the viewer and remove unneeded options.
    const viewer = new Cesium.Viewer("cesiumContainer", {
      imageryProvider: false,
      baseLayerPicker: false,
      homeButton: false,
      fullscreenButton: false,
      navigationHelpButton: false,
      vrButton: false,
      sceneModePicker: false,
      geocoder: false,
      globe: false,
      infobox: false,
      selectionIndicator: false,
      timeline: false,
      projectionPicker: false,
      clockViewModel: null,
      animation: false,
      requestRenderMode: true,
    });

    // Add 3D Tile set.
    const tileset = viewer.scene.primitives.add(
      new Cesium.Cesium3DTileset({
        url: "https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY",
        // This property is required to display attributions.
        showCreditsOnScreen: true,
      })
    );

    // Point the camera at a location and elevation, at a viewport-appropriate distance.
    function pointCameraAt(location, viewport, elevation) {
      const distance = Cesium.Cartesian3.distance(
        Cesium.Cartesian3.fromDegrees(
          viewport.getSouthWest().lng(), viewport.getSouthWest().lat(), elevation),
        Cesium.Cartesian3.fromDegrees(
          viewport.getNorthEast().lng(), viewport.getNorthEast().lat(), elevation)
      ) / 2;
      const target = new Cesium.Cartesian3.fromDegrees(location.lng(), location.lat(), elevation);
      const pitch = -Math.PI / 4;
      const heading = 0;
      viewer.camera.lookAt(target, new Cesium.HeadingPitchRange(heading, pitch, distance));
    }

    // Rotate the camera around a location and elevation, at a viewport-appropriate distance.
    let unsubscribe = null;
    function rotateCameraAround(location, viewport, elevation) {
      if(unsubscribe) unsubscribe();
      pointCameraAt(location, viewport, elevation);
      unsubscribe = viewer.clock.onTick.addEventListener(() => {
        viewer.camera.rotate(Cesium.Cartesian3.UNIT_Z);
      });
    }

    function initAutocomplete() {
      const autocomplete = new google.maps.places.Autocomplete(
        document.getElementById("pacViewPlace"), {
          fields: [
            "geometry",
            "name",
          ],
        }
      );

      autocomplete.addListener("place_changed", async () => {
        const place = autocomplete.getPlace();

        if (!(place.geometry && place.geometry.viewport && place.geometry.location)) {
          window.alert(`Insufficient geometry data for place: ${place.name}`);
          return;
        }
        // Get place elevation using the ElevationService.
        const elevatorService = new google.maps.ElevationService();
        const elevationResponse =  await elevatorService.getElevationForLocations({
          locations: [place.geometry.location],
        });

        if(!(elevationResponse.results && elevationResponse.results.length)){
          window.alert(`Insufficient elevation data for place: ${place.name}`);
          return;
        }
        const elevation = elevationResponse.results[0].elevation || 10;

        rotateCameraAround(
          place.geometry.location,
          place.geometry.viewport,
          elevation
        );
      });
    }
  </script>
  <script async src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initAutocomplete"></script>
</body>

ترسیم چندخطی‌ها و برچسب‌ها

این نمونه کد نحوه افزودن چندخطی و برچسب به نقشه را نشان می‌دهد. می‌توانید چندخطی‌ها را به نقشه اضافه کنید تا مسیرهای رانندگی و پیاده‌روی را نشان دهید، یا مرزهای ملک را نشان دهید، یا مدت زمان رانندگی و پیاده‌روی را محاسبه کنید. همچنین می‌توانید بدون رندر کردن واقعی صحنه، مشخصه‌ها را دریافت کنید.

می‌توانید کاربران را به گشت‌وگذار در محله‌ای ببرید یا می‌توانید املاک همسایه را که درحال‌حاضر برای فروش هستند نشان دهید و سپس اشیای سه‌بعدی مانند بیلبوردها را به صحنه اضافه کنید.

می‌توانید سفری را خلاصه کنید، املاکی را که مشاهده کرده‌اید فهرست کنید، و این جزئیات را در اشیای مجازی نمایش دهید.

<!DOCTYPE html>
<head>
  <meta charset="utf-8" />
  <title>CesiumJS 3D Tiles Polyline and Label Demo</title>
  <script src="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Cesium.js"></script>
  <link
    href="https://ajax.googleapis.com/ajax/libs/cesiumjs/1.105/Build/Cesium/Widgets/widgets.css"
    rel="stylesheet"
  />
</head>
<body>
  <div id="cesiumContainer"></div>
  <script>
    // Enable simultaneous requests.
    Cesium.RequestScheduler.requestsByServer["tile.googleapis.com:443"] = 18;

    // Create the viewer.
    const viewer = new Cesium.Viewer("cesiumContainer", {
      imageryProvider: false,
      baseLayerPicker: false,
      requestRenderMode: true,
      geocoder: false,
      globe: false,
    });

    // Add 3D Tiles tileset.
    const tileset = viewer.scene.primitives.add(
      new Cesium.Cesium3DTileset({
        url: "https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY",

        // This property is required to display attributions as required.
        showCreditsOnScreen: true,
      })
    );

    // Draws a circle at the position, and a line from the previous position.
    const drawPointAndLine = (position, prevPosition) => {
      viewer.entities.removeAll();
      if (prevPosition) {
        viewer.entities.add({
          polyline: {
            positions: [prevPosition, position],
            width: 3,
            material: Cesium.Color.WHITE,
            clampToGround: true,
            classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
          },
        });
      }
      viewer.entities.add({
        position: position,
        ellipsoid: {
          radii: new Cesium.Cartesian3(1, 1, 1),
          material: Cesium.Color.RED,
        },
      });
    };

    // Compute, draw, and display the position's height relative to the previous position.
    var prevPosition;
    const processHeights = (newPosition) => {
      drawPointAndLine(newPosition, prevPosition);

      const newHeight = Cesium.Cartographic.fromCartesian(newPosition).height;
      let labelText = "Current altitude (meters above sea level):\n\t" + newHeight;
      if (prevPosition) {
        const prevHeight =
          Cesium.Cartographic.fromCartesian(prevPosition).height;
        labelText += "\nHeight from previous point (meters):\n\t" + Math.abs(newHeight - prevHeight);
      }
      viewer.entities.add({
        position: newPosition,
        label: {
          text: labelText,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
          pixelOffset: new Cesium.Cartesian2(0, -10),
          showBackground: true,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        }
      });

      prevPosition = newPosition;
    };

    const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
    handler.setInputAction(function (event) {
      const earthPosition = viewer.scene.pickPosition(event.position);
      if (Cesium.defined(earthPosition)) {
        processHeights(earthPosition);
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  </script>
</body>

مدار دوربین

در Cesium، می‌توانید دوربین را در مدار نقطه‌ای جالب بچرخانید و از برخورد با ساختمان‌ها جلوگیری کنید. یا می‌توانید ساختمان‌ها را شفاف کنید تا وقتی دوربین از میان آن‌ها حرکت می‌کند، دیده شوند.

ابتدا دوربین را روی نقطه‌ای قفل کنید، سپس می‌توانید مدار دوربین ایجاد کنید تا دارایی‌تان را به‌نمایش بگذارید. می‌توانید این کار را بااستفاده از عملکرد lookAtTransform دوربین با شنونده رویداد انجام دهید، همان‌طور که در این نمونه کد نشان داده شده است.

// Lock the camera onto a point.
const center = Cesium.Cartesian3.fromRadians(
  2.4213211833389243,
  0.6171926869414084,
  3626.0426275055174
);

const transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);

viewer.scene.camera.lookAtTransform(
  transform,
  new Cesium.HeadingPitchRange(0, -Math.PI / 8, 2900)
);

// Orbit around this point.
viewer.clock.onTick.addEventListener(function (clock) {
  viewer.scene.camera.rotateRight(0.005);
});

برای اطلاعات بیشتر درباره کنترل دوربین، به کنترل دوربین مراجعه کنید

کار با Cesium برای Unreal

برای استفاده از Cesium برای Unreal Plugin با 3D Tiles API، مراحل زیر را دنبال کنید.

  1. افزایه Cesium for Unreal را نصب کنید.

  2. پروژه Unreal جدیدی ایجاد کنید.

  3. به Google Photorealistic 3D Tiles API متصل شوید.

    1. پنجره Cesium را با انتخاب Cesium > Cesium از منو باز کنید.

    2. Blank 3D Tiles Tileset (مجموعه کاشی‌های سه‌بعدی خالی) را انتخاب کنید.

    3. در World Outliner، پانل جزئیات را با انتخاب این Cesium3DTileset باز کنید.

    4. منبع را از از Cesium Ion به از نشانی وب تغییر دهید.

    5. نشانی وب را روی نشانی وب «کاشی‌های سه‌بعدی Google» تنظیم کنید.

    https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
    
    1. نمایش اعتبارها در صفحه را فعال کنید تا ارجاع‌ها به‌درستی نمایش داده شوند.
  4. این کار دنیا را بار می‌کند. برای رفتن به هر LatLng، مورد CesiumGeoreference را در پانل Outliner انتخاب کنید، سپس Origin Latitude/Longitude/Height را در پانل Details ویرایش کنید.

کار کردن با Cesium برای Unity

برای استفاده از کاشی‌های واقع‌گرایانه با Cesium برای Unity، مراحل زیر را دنبال کنید.

  1. پروژه Unity جدیدی ایجاد کنید.

  2. در بخش «مدیر بسته» (ازطریق ویرایشگر > تنظیمات پروژه)، «ثبت دامنه» جدیدی اضافه کنید.

    • نام: Cesium

    • نشانی وب: https://unity.pkg.cesium.com

    • حوزه(ها): com.cesium.unity

  3. بسته Cesium for Unity را نصب کنید.

  4. به Google Photorealistic 3D Tiles API متصل شوید.

    1. با انتخاب Cesium > Cesium از منو، پنجره Cesium را باز کنید.

    2. روی مجموعه کاشی‌های سه‌بعدی خالی کلیک کنید.

    3. در پانل سمت راست، در گزینه منبع مجموعه کاشی در بخش منبع، از نشانی وب را (به‌جای «از Cesium Ion») انتخاب کنید.

    4. نشانی وب را روی نشانی وب «کاشی‌های سه‌بعدی Google» تنظیم کنید.

    https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
    
    1. نمایش اعتبارها در صفحه را فعال کنید تا ارجاع‌ها به‌درستی نمایش داده شوند.
  5. این کار دنیا را بار می‌کند. برای رفتن به هر LatLng، مورد CesiumGeoreference را در سلسله‌مراتب صحنه انتخاب کنید، سپس «طول جغرافیایی/ عرض جغرافیایی/ ارتفاع مبدأ» را در بازرس ویرایش کنید.

کار با deck.gl

deck.gl، که از WebGL بهره می‌برد، چارچوب جاوا اسکریپت متن‌باز برای تجسم داده‌های مقیاس بزرگ با عملکرد بالا است.

اِسناد

مطمئن شوید که با استخراج فیلد copyright از کاشی‌های gltf asset و سپس نمایش آن در نمای پردازش‌شده، ارجاع‌های داده را به‌درستی نمایش می‌دهید. برای اطلاعات بیشتر، به نمایش ارجاع داده‌ها مراجعه کنید.

نمونه‌های پردازش‌کننده deck.gl

مثال ساده

مثال زیر پردازنده deck.gl را مقداردهی اولیه می‌کند و سپس مکانی را به‌صورت سه‌بعدی بار می‌کند. در کدتان، حتماً YOUR_API_KEY را با کلید میانای API واقعی‌تان جایگزین کنید.

<!DOCTYPE html>
<html>
 <head>
   <title>deck.gl Photorealistic 3D Tiles example</title>
   <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;}
   </style>
 </head>

 <body>
   <div id="map"></div>
   <div id="credits"></div>
   <script>
     const GOOGLE_API_KEY = YOUR_API_KEY;
     const TILESET_URL = `https://tile.googleapis.com/v1/3dtiles/root.json`;
     const creditsElement = document.getElementById('credits');
     new deck.DeckGL({
       container: 'map',
       initialViewState: {
         latitude: 50.0890,
         longitude: 14.4196,
         zoom: 16,
         bearing: 90,
         pitch: 60,
         height: 200
       },
       controller: {minZoom: 8},
       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;
             }
           }
         })
       ]
     });
   </script>
 </body>
</html>

لایه‌های دوبعدی را روی «کاشی‌های سه‌بعدی واقع‌نمای Google» تجسم کنید

‫deck.gl TerrainExtension داده‌های دوبعدی را روی سطح سه‌بعدی رندر می‌کند. برای مثال، می‌توانید GeoJSON ردپای ساختمان را روی هندسه «کاشی‌های سه‌بعدی واقع‌نما» بپوشانید.

در مثال زیر، لایه‌ای از ساختمان‌ها با چندضلعی‌هایی که با سطح «کاشی‌های سه‌بعدی واقع‌نما» تطبیق داده شده‌اند تجسم شده است.

<!DOCTYPE html>
<html>
 <head>
   <title>Google 3D tiles example</title>
   <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;}
   </style>
 </head>

 <body>
   <div id="map"></div>
   <div id="credits"></div>
   <script>
     const GOOGLE_API_KEY = YOUR_API_KEY;
     const TILESET_URL = `https://tile.googleapis.com/v1/3dtiles/root.json`;
     const BUILDINGS_URL = 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/google-3d-tiles/buildings.geojson'
     const creditsElement = document.getElementById('credits');
     const deckgl = new deck.DeckGL({
       container: 'map',
       initialViewState: {
         latitude: 50.0890,
         longitude: 14.4196,
         zoom: 16,
         bearing: 90,
         pitch: 60,
         height: 200
       },
       controller: 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;
             }
           },
           operation: 'terrain+draw'
         }),
         new deck.GeoJsonLayer({
           id: 'buildings',
           // This dataset is created by CARTO, using other Open Datasets available. More info at: https://3dtiles.carto.com/#about.
           data: 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/google-3d-tiles/buildings.geojson',
           stroked: false,
           filled: true,
           getFillColor: ({properties}) => {
             const {tpp} = properties;
             // quantiles break
             if (tpp < 0.6249)
               return [254, 246, 181]
             else if (tpp < 0.6780)
               return [255, 194, 133]
             else if (tpp < 0.8594)
               return [250, 138, 118]
             return [225, 83, 131]
           },
           opacity: 0.2,
           extensions: [new deck._TerrainExtension()]
         })
       ]
     });
   </script>
 </body>
</html>