با یک رندر کاشی سه بعدی کار کنید

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

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

کار با CesiumJS

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

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

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

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

بهترین شیوه‌ها

چندین رویکرد وجود دارد که می‌توانید برای کاهش زمان بارگذاری سه‌بعدی CesiumJS استفاده کنید. برای مثال:

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

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

    هرچه REQUEST_COUNT بالاتر باشد، کاشی‌ها سریع‌تر بارگذاری می‌شوند. با این حال، هنگام بارگذاری در مرورگر کروم با REQUEST_COUNT بیشتر از 10 و غیرفعال بودن حافظه پنهان، ممکن است با یک مشکل شناخته شده کروم مواجه شوید. در بیشتر موارد استفاده، برای عملکرد بهینه، REQUEST_COUNT برابر با 18 را توصیه می‌کنیم.

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

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

معیارهای رندرینگ

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

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

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

شما می‌توانید با ارائه URL ریشه tileset، از رندرکننده 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 همانطور که در اینجا نشان داده شده است، رندر می‌شود.

ادغام API مکان‌ها

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

<!DOCTYPE html>
<head>
 <meta charset="utf-8" />
 <title>CesiumJS 3D Tiles Places API 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 for Unreal با API کاشی‌های سه‌بعدی، مراحل زیر را دنبال کنید.

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

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

  3. به API کاشی‌های سه‌بعدی واقع‌گرایانه گوگل متصل شوید.

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

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

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

    4. منبع را از «از یون سزیم» به «از URL» تغییر دهید.

    5. آدرس اینترنتی (URL) را به عنوان آدرس اینترنتی کاشی‌های سه‌بعدی گوگل (Google 3D Tiles) تنظیم کنید.

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

با سزیم برای یونیتی کار کنید

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

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

  2. یک رجیستری Scoped جدید در بخش Package Manager (از طریق Editor > Project Settings ) اضافه کنید.

    • نام: سزیم

    • آدرس اینترنتی: https://unity.pkg.cesium.com

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

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

  4. به API کاشی‌های سه‌بعدی واقع‌گرایانه گوگل متصل شوید.

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

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

    3. در پنل سمت چپ، در گزینه‌ی Tileset Source در زیر Source ، گزینه‌ی From URL (به جای From Cesium Ion) را انتخاب کنید.

    4. آدرس اینترنتی (URL) را روی آدرس اینترنتی کاشی‌های سه‌بعدی گوگل (Google 3D Tiles URL) تنظیم کنید.

    https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
    
    1. برای نمایش صحیح ارجاعات، گزینه «نمایش اعتبار روی صفحه» را فعال کنید.
  5. این کار جهان را بارگذاری می‌کند. برای انتقال به هر LatLng، آیتم CesiumGeoreference را در سلسله مراتب صحنه انتخاب کنید و سپس Origin Latitude/Longitude/Height را در Inspector ویرایش کنید.

کار با deck.gl

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

انتساب

با استخراج فیلد copyright از tiles 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>

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

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>