Utilizzare un renderer in 3D Tile

I riquadri 3D fotorealistici sono Formato glTF standard OGC vale a dire che è possibile utilizzare qualsiasi renderer che supporti la specifica OGC 3D Tiles le tue visualizzazioni 3D. Ad esempio: Cesio è una libreria open source di base per il rendering di visualizzazioni 3D.

Lavorare con CesiumJS

CesiumJS è una libreria JavaScript open source per la visualizzazione 3D sul web. Per ulteriori informazioni sull'utilizzo di CesiumJS, vedi Scopri CesiumJS.

Controlli utente

Il renderer dei riquadri CesiumJS dispone di un set standard di controlli utente.

Azione Descrizione
Visualizzazione panoramica Clic con il pulsante sinistro del mouse e trascinare
Visualizzazione zoom Clic con il tasto destro del mouse e trascina o fai scorrere la rotellina del mouse
Ruota visualizzazione Ctrl+clic con il pulsante sinistro/destro e trascina o fai clic con il pulsante centrale e trascinare

Best practice

Esistono diversi approcci per ridurre il caricamento di CesiumJS 3D volte. Ad esempio:

  • Abilita le richieste simultanee aggiungendo la seguente istruzione all'HTML di rendering:

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

    Più alto è il valore di REQUEST_COUNT, più rapidamente è vengono caricati riquadri. Tuttavia, quando carichi contenuti in un browser Chrome con REQUEST_COUNT maggiore di 10 e la cache è disabilitata, potresti riscontrare Problema di Chrome. Per la maggior parte dei casi d'uso, consigliamo un valore REQUEST_COUNT pari a 18 per una delle prestazioni.

  • Attiva l'opzione per ignorare i livelli di dettaglio. Per ulteriori informazioni, leggi questo Problema relativo al cesio.

Assicurati di visualizzare correttamente le attribuzioni dei dati attivando showCreditsOnScreen: true. Per ulteriori informazioni, vedi Norme.

Metriche di rendering

Per trovare la frequenza fotogrammi, osserva quante volte al secondo requestAnimationFrame .

Per vedere come viene calcolata la latenza di frame, osserva la PerformanceDisplay .

Esempi di renderer CesiumJS

Puoi utilizzare il renderer CesiumJS con i riquadri 3D dell'API Map Tiles semplicemente che fornisce l'URL del set di riquadri principale.

Esempio semplice

L'esempio riportato di seguito inizializza il renderer CesiumJS, quindi carica il renderer il set di riquadri.

<!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>

Per informazioni su requestRenderMode, vedi Attivazione della modalità di rendering richiesta.

La pagina HTML viene visualizzata come mostrato qui.

Integrazione dell'API Places

Puoi utilizzare CesiumJS con API Places per recuperare altre informazioni. Puoi usare il widget Completamento automatico per volare area visibile di Luoghi. In questo esempio viene utilizzata l'API Places Autocomplete, che viene attivato seguendo queste istruzioni, e l'API Maps JavaScript, abilitata seguendo queste istruzioni.

<!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>

Vista rotante del drone

Puoi controllare la videocamera per animare il set di riquadri. Se combinato con API Places e API Elevation, questa animazione simula un evento panoramica con un drone di qualsiasi punto d'interesse.

Questo esempio di codice mostra il luogo selezionato nell' Widget di completamento automatico.

<!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>

Disegnare polilinee ed etichette

Questo esempio di codice mostra come aggiungere polilinee ed etichette a una mappa. Puoi aggiungi polilinee a una mappa per mostrare le indicazioni stradali e a piedi, o per mostrare confini delle proprietà o per calcolare la durata dei tragitti in auto e a piedi. Puoi anche ottenere attributi senza eseguire il rendering della scena.

Potresti guidare gli utenti in un tour selezionato di un quartiere oppure mostrare proprietà vicine attualmente in vendita, a cui puoi aggiungere oggetti come cartelloni pubblicitari.

Puoi riassumere un viaggio, elencare le proprietà che hai visualizzato, mostrare questi dettagli negli oggetti virtuali.

<!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>

Orbita fotocamera

In Cesium, puoi far orbitare la fotocamera intorno a un punto d'interesse, evitando collisioni con edifici. In alternativa, puoi rendere trasparenti gli edifici quando la videocamera si sposta attraverso questi elementi.

Innanzitutto, blocca la videocamera su un punto, poi crea un'orbita per mostra il tuo asset. Puoi farlo usando lo strumento lookAtTransform con un listener di eventi, come illustrato in questo esempio di codice.

// 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);
});

Per ulteriori informazioni su come controllare la fotocamera, vedi Controllare la videocamera

Collabora con Cesium per Unreal

Per utilizzare il plug-in Cesium for Unreal con l'API 3D Tiles, procedi nel seguente modo di seguito.

  1. Installa il plug-in Cesium for Unreal.

  2. Creare un nuovo progetto Unreal.

  3. Connettiti all'API Photorealistic 3D Tiles di Google.

    1. Apri la finestra Cesium selezionando Cesium > Cesium dal menu.

    2. Seleziona Set di riquadri 3D vuoti.

    3. In World Outliner, apri il riquadro Details selezionando questa opzione Cesium3DTileset.

    4. Cambia il valore di Source (Origine) da From Cesium Ion (Da Cesium Ion) a From URL (Da URL).

    5. Imposta l'URL come URL dei riquadri 3D di Google.

    https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
    
    1. Attiva Mostra crediti sullo schermo per visualizzare correttamente le attribuzioni.
  4. Questo carica il mondo. Per passare a un LatLng, seleziona CesiumGeoreference nel riquadro Outliner, quindi modifica Latitudine/longitudine/altezza origine nel riquadro Dettagli.

Collabora con Cesium per Unity

Per utilizzare riquadri fotorealistici con Cesium per Unity, segui i passaggi riportati di seguito.

  1. Crea un nuovo progetto Unity.

  2. Aggiungi un nuovo registro con ambito nella sezione Gestione pacchetti (tramite Editor > Impostazioni progetto).

    • Nome: Cesium

    • URL: https://unity.pkg.cesium.com

    • Ambiti: com.cesium.unity

  3. Installa il pacchetto Cesium per Unity.

  4. Connettiti all'API Photorealistic 3D Tiles di Google.

    1. Apri la finestra Cesium selezionando Cesium > Cesium dal menu.

    2. Fai clic su Set di riquadri 3D vuoti.

    3. Nel riquadro a sinistra, per l'opzione Origine set di riquadri in Origine, Seleziona Da URL (anziché Da Cesium Ion).

    4. Imposta l'URL sull'URL dei riquadri 3D di Google.

    https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
    
    1. Attiva Mostra crediti sullo schermo per visualizzare correttamente le attribuzioni.
  5. Questo carica il mondo. Per passare a un LatLng, seleziona CesiumGeoreference nella gerarchia di scena, quindi modifica il Latitudine/longitudine/altezza di origine nell'ispettore.

Utilizza deck.gl

deck.gl, basato su WebGL, è un framework JavaScript open source ad alte prestazioni, e visualizzazioni di dati su larga scala.

Attribuzione

Assicurati di visualizzare correttamente le attribuzioni dei dati estraendo l'elemento copyright dal riquadro gltf asset, per poi mostrarlo nella visualizzazione visualizzata. Per ulteriori informazioni, vedi Mostra attribuzioni dei dati.

Esempi di renderer deck.gl

Esempio semplice

Nell'esempio seguente viene inizializzato il renderer deck.gl, quindi viene caricato un luogo in 3D. Assicurati di sostituire YOUR_API_KEY nel codice con il tuo chiave API effettiva.

<!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>

Visualizza livelli 2D sopra i riquadri 3D fotorealistici di Google

Il deck.gl TerrainExtension il rendering di altri dati 2D su una superficie 3D. Ad esempio, puoi applicare il GeoJSON della traccia di un edificio sopra la geometria dei riquadri 3D fotorealistici.

Nell'esempio seguente, viene visualizzato un livello di edifici con i poligoni adattato alla superficie dei riquadri 3D fotorealistici.

<!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>