Utiliser un moteur de rendu de tuiles 3D

Les tuiles 3D photoréalistes se trouvent dans Format glTF standard OGC Vous pouvez donc utiliser n'importe quel moteur de rendu compatible avec la spécification OGC 3D Tiles pour créer vos visualisations 3D. Par exemple : Césium est une bibliothèque Open Source fondamentale pour le rendu de visualisations 3D.

Utiliser CesiumJS

CesiumJS est une bibliothèque JavaScript Open Source destinée à la visualisation 3D sur le Web. Pour en savoir plus sur l'utilisation de CesiumJS, consultez Apprenez à utiliser CesiumJS.

Contrôle utilisateur

Le moteur de rendu de tuiles CesiumJS dispose d'un ensemble standard de commandes utilisateur.

Action Description
Vue panoramique Clic gauche et faire glisser
Vue Zoom Effectuez un clic droit et faites glisser ou utilisez la molette de la souris
Faire pivoter la vue Ctrl+clic gauche/droit et faites glisser ou cliquez avec le milieu et faire glisser

Bonnes pratiques

Il existe plusieurs approches pour réduire le chargement en 3D CesiumJS fois. Exemple :

  • Activez les requêtes simultanées en ajoutant l'instruction suivante au code HTML de votre rendu:

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

    Plus la valeur de REQUEST_COUNT est élevée, plus la les vignettes se chargent. Toutefois, lors du chargement dans un navigateur Chrome avec REQUEST_COUNT supérieur à 10 et le cache désactivé, vous risquez de rencontrer Problème Chrome. Dans la plupart des cas d'utilisation, nous recommandons une REQUEST_COUNT de 18 pour des performances.

  • Permet d'ignorer les niveaux de détail. Pour en savoir plus, consultez cette Problème Cesium.

Assurez-vous d'afficher correctement les attributions de données en activant showCreditsOnScreen: true Pour en savoir plus, consultez Règles.

Métriques d'affichage

Pour connaître la fréquence d'images, regardez combien de fois par seconde requestAnimationFrame est appelée.

Pour savoir comment la latence des images est calculée, consultez la PerformanceDisplay .

Exemples de moteur de rendu CesiumJS

Vous pouvez utiliser le moteur de rendu CesiumJS avec les tuiles 3D de l'API Map Tiles en en fournissant l'URL de l'ensemble de tuiles racine.

Exemple simple

L'exemple suivant initialise le moteur de rendu CesiumJS, puis charge la racine Tileset.

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

Pour en savoir plus sur requestRenderMode, consultez Activer le mode de demande d'affichage

La page HTML s'affiche comme indiqué ici.

Intégration de l'API Places

Vous pouvez utiliser CesiumJS avec API Places pour obtenir plus d'informations. Vous pouvez utiliser le widget de saisie semi-automatique pour accéder la fenêtre d'affichage des lieux. Cet exemple utilise l'API Places Autocomplete, qui est activée par en suivant ces instructions, et l'API Maps JavaScript, qui est activée en suivant ces instructions.

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

Vue rotative par drone

Vous pouvez contrôler l'activité de la caméra pour animer l'ensemble de mosaïques. Lorsqu'elle est combinée avec l'API Places et l'API Elevation, cette animation simule une animation le survol d'un drone de n'importe quel point d'intérêt.

Cet exemple de code vous fait découvrir le lieu que vous avez sélectionné dans le Widget de saisie semi-automatique.

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

Tracer des polylignes et des étiquettes

Cet exemple de code montre comment ajouter des polylignes et des étiquettes à une carte. Vous pouvez ajouter des polylignes à une carte pour afficher des itinéraires en voiture et à pied, ou pour afficher les limites d'une propriété, ou calculer les durées de trajet en voiture et à pied. Vous pouvez également obtenir des attributs sans afficher réellement la scène.

Vous pouvez emmener les utilisateurs dans une visite organisée d'un quartier, ou vous pouvez leur montrer des biens immobiliers voisins qui sont en vente, vous pouvez ajouter tels que des panneaux d'affichage.

Vous pouvez résumer un voyage, répertorier les établissements que vous avez consultés, ces détails dans des objets virtuels.

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

Orbite de la caméra

Avec Cesium, vous pouvez tourner la caméra autour d'un point d'intérêt des collisions avec des bâtiments. Vous pouvez aussi rendre les bâtiments transparents lorsque la caméra les traverse.

Commencez par verrouiller la caméra sur un point d'accès, puis créez une orbite pour présenter votre asset. Pour ce faire, vous pouvez utiliser le lookAtTransform avec un écouteur d'événements, comme illustré dans cet exemple de code.

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

Pour en savoir plus sur le contrôle de la caméra, consultez Contrôler la caméra

Travailler avec Cesium for Unreal

Pour utiliser le plug-in Cesium for Unreal avec l'API 3D Tiles, suivez les étapes ci-dessous ci-dessous.

  1. Installez le plug-in Cesium for Unreal.

  2. Créez un projet Unreal.

  3. Connexion à l'API Google Photoréaliste 3D Tiles

    1. Ouvrez la fenêtre Cesium en sélectionnant Cesium > Cesium dans le menu.

    2. Sélectionnez Ensemble de tuiles 3D vides.

    3. Dans le World Outliner, ouvrez le panneau Details (Détails) en sélectionnant cette Cesium3DTileset :

    4. Changez la Source de From Cesium Ion (De l'ion de césium) à From URL (De l'URL).

    5. Définissez l'URL de sorte qu'elle corresponde à l'URL de Google 3D Tiles.

    https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
    
    1. Activez l'option Afficher les crédits à l'écran pour afficher correctement les attributions.
  4. Cela charge le monde. Pour déplacer la carte LatLng de votre choix, sélectionnez l'icône CesiumGeoreference dans le panneau Idéateur, puis modifiez la Latitude/Longitude/Hauteur de départ dans le panneau Détails

Utiliser Cesium pour Unity

Pour utiliser des tuiles photoréalistes avec Cesium for Unity, suivez les étapes ci-dessous.

  1. Créez un projet Unity.

  2. Ajoutez un registre délimité dans la section "Gestionnaire de packages" (via Éditeur > Paramètres du projet).

    • Nom: Césium

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

    • Champ d'application : com.cesium.unity

  3. Installez le package Cesium for Unity.

  4. Connectez-vous à l'API Google Photoréaliste 3D Tiles.

    1. Ouvrez la fenêtre Cesium en sélectionnant Cesium > Cesium dans le menu.

    2. Cliquez sur Ensemble de tuiles 3D vides.

    3. Dans le panneau de gauche, dans l'option Tileset Source sous Source : Sélectionnez À partir de l'URL (au lieu de "À partir de Cesium Ion").

    4. Définissez l'URL sur l'URL de Google 3D Tiles.

    https://tile.googleapis.com/v1/3dtiles/root.json?key=YOUR_API_KEY
    
    1. Activez l'option Afficher les crédits à l'écran pour afficher correctement les attributions.
  5. Cela charge le monde. Pour déplacer la carte LatLng de votre choix, sélectionnez l'icône l'élément CesiumGeoreference dans Scene Hierarchy (Hiérarchie des scènes), puis modifiez le paramètre Latitude/Longitude/Hauteur d'origine dans l'outil d'inspection.

Utiliser deck.gl

deck.gl, basé sur WebGL, est un framework JavaScript Open Source pour des visualisations des données à grande échelle.

Attribution

Assurez-vous d'afficher correctement les attributions de données en extrayant le copyright. à partir des cartes gltf asset, puis de l'afficher dans la vue affichée. Pour Pour en savoir plus, consultez Afficher les attributions de données :

Exemples de moteur de rendu deck.gl

Exemple simple

L'exemple suivant initialise le moteur de rendu deck.gl, puis charge un emplacement en 3D. Dans votre code, veillez à remplacer YOUR_API_KEY par votre clé API réelle.

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

Visualisez des calques 2D sur des tuiles 3D photoréalistes Google.

Le fichier deck.gl TerrainExtension affiche les données en 2D sur une surface 3D. Par exemple, vous pouvez GeoJSON d'une empreinte de bâtiment au-dessus de la géométrie de tuiles 3D photoréalistes.

Dans l'exemple suivant, un calque de bâtiments est illustré par les polygones adapté à la surface des tuiles 3D photoréalistes.

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