Optimiser des données 3D avec la compression à la géométrie Draco

1. Présentation

Les graphismes 3D sont un élément fondamental de nombreuses applications, y compris les jeux vidéo, la conception et la visualisation des données. À mesure que les processeurs graphiques et les outils de création continuent de s'améliorer, des modèles 3D plus grands et plus complexes vont devenir courants. Ils contribueront à alimenter de nouvelles applications de réalité virtuelle (RV) immersive et de réalité augmentée (RA). En raison de cette complexité accrue des modèles, les besoins en stockage et en bande passante doivent suivre le rythme de l'explosion des données 3D.

Avec Draco, les applications utilisant des graphismes 3D peuvent être nettement plus petites sans compromettre la fidélité visuelle. Pour les utilisateurs, cela signifie que les applications peuvent désormais être téléchargées plus rapidement, que les graphismes en 3D dans le navigateur peuvent se charger plus rapidement, et qu'il est désormais possible de transmettre des scènes de RV et de RA avec une faible quantité de bande passante, et d'obtenir un rendu rapide avec un rendu fantastique.

Qu'est-ce que Draco ?

Draco est une bibliothèque permettant de compresser et de décompresser les maillons géométriques 3D et les nuages de points. Elle a pour but d'améliorer le stockage et la transmission des graphismes 3D.

Draco a été conçu et construit dans un souci d'efficacité et de rapidité de compression. Le code prend en charge les points de compression, les informations de connectivité, les coordonnées de texture, les informations de couleur, les normales et tout autre attribut générique associé à la géométrie. Draco est publié sous forme de code source C++ qui peut être utilisé pour compresser des graphiques 3D ainsi que des décodeurs C++ et JavaScript pour les données encodées.

Objectifs de l'atelier

  • Utiliser Draco pour compresser un modèle 3D
  • Comment utiliser différents modèles de compression et leur impact sur leur qualité et leur taille
  • Afficher un modèle 3D sur le Web

Prérequis

2. Configuration

Clonez le dépôt GitHub à l'aide de la ligne de commande suivante:

git clone https://github.com/google/draco

Accédez au répertoire racine Draco.

cd draco

3. Créer l'encodeur

Commençons par créer les applications pour encoder et décoder Draco.

Créer un encodeur

  • Exécutez cmake à partir d'un répertoire dans lequel vous souhaitez générer des fichiers de compilation, puis transmettez-lui le chemin d'accès à votre dépôt Draco.
mkdir build

cd build

cmake ../

make

4. Encoder votre premier asset 3D

draco_encoder lira les fichiers OBJ ou PLY en entrée et générera des fichiers encodés en Draco. Nous avons inclus le maillage Bunny de Stanford à des fins de test. La ligne de commande de base se présente comme suit:

./draco_encoder -i ../testdata/bun_zipper.ply -o bunny.drc

Vous pouvez maintenant voir la taille du fichier de sortie et la comparer à celle du fichier .ply d'origine. La taille du fichier compressé doit être nettement inférieure à la taille du fichier d'origine.

Remarque: La taille compressée peut varier en fonction des options de compression.

5. Décoder un fichier Draco dans le navigateur

À ce stade, nous allons commencer par une page Web de base pour décoder les fichiers Draco. Nous allons commencer par copier et coller les sections de code suivantes dans l'éditeur de texte.

  1. Commencez par un fichier HTML de base.
<!DOCTYPE html>
<html>
<head>
  <title>Codelab - Draco Decoder</title>
  1. L'extrait de code suivant charge le décodeur Draco WASM.
  <script src="https://www.gstatic.com/draco/versioned/decoders/1.4.1/draco_wasm_wrapper.js">
    // It is recommended to always pull your Draco JavaScript and WASM decoders
    // from the above URL. Users will benefit from having the Draco decoder in
    // cache as more sites start using the static URL.
  </script>
  1. Ajoutez ensuite cette fonction, qui créera un module de décodeur Draco. La création du module de décodeur est asynchrone. Vous devez donc attendre que le rappel soit appelé avant de pouvoir utiliser le module.
  <script>
    'use strict';

    // The global Draco decoder module.
    let decoderModule = null;

    // Creates the Draco decoder module.
    function createDracoDecoderModule() {
      let dracoDecoderType = {};

      // Callback when the Draco decoder module is fully instantiated. The
      // module parameter is the created Draco decoder module.
      dracoDecoderType['onModuleLoaded'] = function(module) {
        decoderModule = module;

        // Download the Draco encoded file and decode.
        downloadEncodedMesh('bunny.drc');
      };
      DracoDecoderModule(dracoDecoderType);
    }
  1. Ajoutez la fonction permettant de décoder un maillage encodé en Draco.
    // Decode an encoded Draco mesh. byteArray is the encoded mesh as
    // an Uint8Array.
    function decodeMesh(byteArray) {
      // Create the Draco decoder.
      const decoder = new decoderModule.Decoder();

      // Create a buffer to hold the encoded data.
      const buffer = new decoderModule.DecoderBuffer();
      buffer.Init(byteArray, byteArray.length);

      // Decode the encoded geometry.
      let outputGeometry = new decoderModule.Mesh();
      let decodingStatus = decoder.DecodeBufferToMesh(buffer, outputGeometry);

      alert('Num points = ' + outputGeometry.num_points());

      // You must explicitly delete objects created from the DracoModule
      // or Decoder.
      decoderModule.destroy(outputGeometry);
      decoderModule.destroy(decoder);
      decoderModule.destroy(buffer);
    }
  1. Maintenant que la fonction de décodage Draco est en place, ajoutez une fonction pour télécharger un maillage encodé en Draco. La fonction "downloadEncodedMesh" accepte un paramètre dans le fichier Draco à charger. Ici, il s'agit de "bunny.drc". de l'étape précédente.
    // Download and decode the Draco encoded geometry.
    function downloadEncodedMesh(filename) {
      // Download the encoded file.
      const xhr = new XMLHttpRequest();
      xhr.open("GET", filename, true);
      xhr.responseType = "arraybuffer";
      xhr.onload = function(event) {
        const arrayBuffer = xhr.response;
        if (arrayBuffer) {
          const byteArray = new Uint8Array(arrayBuffer);
          decodeMesh(byteArray);
        }
      };
      xhr.send(null);
    }
  1. Appelez la méthode "createDracoDecoderModule" pour créer le module de décodeur Draco, qui appellera "downloadEncodedMesh" pour télécharger le fichier Draco encodé, qui appellera la fonction pour décoder le maillage Draco encodé.
    // Create the Draco decoder module.
    createDracoDecoderModule();
  </script>
</head>
<body>
</body>
</html>
  1. Enregistrez ce fichier sous le nom "DracoDecode.html".
  2. Démarrez le serveur Web Python. Dans le type de terminal:
python -m SimpleHTTPServer

  1. Ouvrez le fichier localhost:8000/DracoDecode.html dans Chrome. Un message d'alerte doit s'afficher avec le nombre de points (Nombre de points = 34 834) qui ont été décodés à partir du modèle.

6. Afficher un fichier Draco avec three.js

Maintenant que nous savons comment décoder un fichier Draco à l'aide de WASM, nous allons utiliser une visionneuse 3D Web très utilisée : three.js. Comme dans l'exemple précédent, nous allons commencer par copier et coller les sections de code suivantes dans l'éditeur de texte.

  1. Commencer avec un fichier HTML de base
<!DOCTYPE html>
<html>
<head>
  <title>Codelab - Draco three.js Render</title>
  1. Ajout de code pour charger three.js et le chargeur Draco three.js
  <script type="importmap">
          {
            "imports": {
              "three": "https://unpkg.com/three@v0.162.0/build/three.module.js",
              "three/addons/": "https://unpkg.com/three@v0.162.0/examples/jsm/"
            }
          }
  </script>
  1. Configurez le chemin d'accès au décodeur Draco.
  <script type="module">
    // import three.js and DRACOLoader.
    import * as THREE from 'three';
    import {DRACOLoader} from 'three/addons/loaders/DRACOLoader.js'

    // three.js globals.
    var camera, scene, renderer;

    // Create the Draco loader.
    var dracoLoader = new DRACOLoader();

    // Specify path to a folder containing WASM/JS decoding libraries.
    // It is recommended to always pull your Draco JavaScript and WASM decoders
    // from the below URL. Users will benefit from having the Draco decoder in
    // cache as more sites start using the static URL.
    dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.4.1/');
  1. Ajoutez le code de rendu three.js.
    function initThreejs() {
      camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 0.1, 15 );
      camera.position.set( 3, 0.25, 3 );

      scene = new THREE.Scene();
      scene.background = new THREE.Color( 0x443333 );
      scene.fog = new THREE.Fog( 0x443333, 1, 4 );

      // Ground
      var plane = new THREE.Mesh(
        new THREE.PlaneGeometry( 8, 8 ),
        new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
      );
      plane.rotation.x = - Math.PI / 2;
      plane.position.y = 0.03;
      plane.receiveShadow = true;
      scene.add(plane);

      // Lights
      var light = new THREE.HemisphereLight( 0x443333, 0x111122 );
      scene.add( light );

      var light = new THREE.SpotLight();
      light.angle = Math.PI / 16;
      light.penumbra = 0.5;
      light.castShadow = true;
      light.position.set( - 1, 1, 1 );
      scene.add( light );

      // renderer
      renderer = new THREE.WebGLRenderer( { antialias: true } );
      renderer.setPixelRatio( window.devicePixelRatio );
      renderer.setSize( window.innerWidth, window.innerHeight );
      renderer.shadowMap.enabled = true;

      const container = document.getElementById('container');
      container.appendChild( renderer.domElement );

      window.addEventListener( 'resize', onWindowResize, false );
    }

    function onWindowResize() {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();

      renderer.setSize( window.innerWidth, window.innerHeight );
    }

    function animate() {
      render();
      requestAnimationFrame( animate );
    }

    function render() {
      var timer = Date.now() * 0.0003;

      camera.position.x = Math.sin( timer ) * 0.5;
      camera.position.z = Math.cos( timer ) * 0.5;
      camera.lookAt( new THREE.Vector3( 0, 0.1, 0 ) );

      renderer.render( scene, camera );
    }
  1. Ajoute le chargement et le décodage de code dans Draco.
    function loadDracoMesh(dracoFile) {
      dracoLoader.load(dracoFile, function ( geometry ) {
        geometry.computeVertexNormals();

        var material = new THREE.MeshStandardMaterial( { vertexColors: THREE.VertexColors } );
        var mesh = new THREE.Mesh( geometry, material );
        mesh.castShadow = true;
        mesh.receiveShadow = true;
        scene.add( mesh );
      } );
    }

  1. Ajoutez du code pour charger le fichier.
    window.onload = function() {
      initThreejs();
      animate();
      loadDracoMesh('bunny.drc');
    }
  </script>
</head>
<body>
  <div id="container"></div>
</body>
</html>
  1. Enregistrez ce fichier sous le nom "DracoRender.html".
  2. Si nécessaire, redémarrez le serveur Web.
python -m SimpleHTTPServer

  1. Ouvrez localhost:8000/DracoRender.html dans Chrome. Votre fichier Draco devrait maintenant s'afficher dans le navigateur.

7. Essayer différents paramètres d'encodage

L'encodeur Draco accepte de nombreux paramètres différents qui ont une incidence sur la taille du fichier compressé et la qualité visuelle du code. Essayez d'exécuter les commandes suivantes dans la ligne de commande et d'observer les résultats.

  1. La commande suivante quantifie les positions du modèle sur 12 bits (11 bits par défaut).
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12

  1. Notez la taille du fichier out12.drc par rapport au fichier bunny.drc de la section précédente. L'utilisation d'un plus grand nombre de bits de quantification peut augmenter la taille du fichier compressé.

3.La commande suivante quantifie les positions du modèle sur 6 bits.

./draco_encoder -i ../testdata/bun_zipper.ply -o out6.drc -qp 6

  1. Notez la taille du fichier out6.drc par rapport à celle du fichier bunny.drc de la section précédente. L'utilisation de moins de bits de quantification peut réduire la taille du fichier compressé.
  1. Les paramètres suivants ont une incidence sur les niveaux de compression du modèle. À l'aide de l'indicateur cl, vous pouvez régler le taux de compression de 1 (taux de compression le plus faible) à 10 (taux de compression le plus élevé).
./draco_encoder -i ../testdata/bun_zipper.ply -o outLow.drc -cl 1

./draco_encoder -i ../testdata/bun_zipper.ply -o outHigh.drc -cl 10

Notez la sortie de l'encodeur Draco. Comme vous pouvez le constater, il existe un compromis en termes de temps requis pour la compression aux niveaux de compression les plus élevés par rapport au gain de bits. Le paramètre adapté à votre application dépend des exigences de durée et de taille au moment de l'encodage.

8. Félicitations

Vous avez terminé l'atelier sur le code sur la compression des mailles Draco et exploré avec succès de nombreuses fonctionnalités clés de Draco.

Nous espérons que vous avez compris comment Draco peut vous aider à réduire la taille de vos éléments 3D et à les transmettre plus efficacement sur le Web. Vous pouvez en apprendre davantage sur Draco et obtenir la dernière bibliothèque sur github.