Mengoptimalkan data 3D dengan Kompresi Geometri Draco

1. Ringkasan

Grafis 3D adalah bagian mendasar dari banyak aplikasi, termasuk game, desain, dan visualisasi data. Seiring dengan terus meningkatnya kualitas prosesor grafis dan alat kreasi, model 3D yang lebih besar dan kompleks akan menjadi hal yang umum dan membantu memicu aplikasi baru dalam virtual reality (VR) dan augmented reality (AR) yang imersif. Karena peningkatan kompleksitas model ini, persyaratan penyimpanan dan bandwidth harus mengimbangi ledakan data 3D.

Dengan Draco, aplikasi yang menggunakan grafik 3D dapat berukuran jauh lebih kecil tanpa mengurangi kualitas visual. Bagi pengguna, hal ini berarti aplikasi kini dapat didownload lebih cepat, grafis 3D di browser dapat dimuat lebih cepat, dan adegan VR dan AR kini dapat ditransmisikan dengan sebagian kecil bandwidth, dirender dengan cepat, dan terlihat fantastis.

Apa itu Draco?

Draco adalah library untuk mengompresi dan mendekompresi mesh geometris 3D dan point cloud. Tujuannya adalah untuk meningkatkan penyimpanan dan transmisi grafis 3D.

Draco dirancang dan dibuat untuk efisiensi dan kecepatan kompresi. Kode ini mendukung kompresi titik, informasi konektivitas, koordinat tekstur, informasi warna, normal, dan atribut generik lainnya yang terkait dengan geometri. Draco dirilis sebagai kode sumber C++ yang dapat digunakan untuk mengompresi grafis 3D serta dekoder C++ dan Javascript untuk data yang dienkode.

Yang akan Anda pelajari

  • Cara menggunakan Draco untuk mengompresi model 3D
  • Cara menggunakan berbagai model kompresi dan pengaruhnya terhadap kualitas dan ukuran model
  • Cara melihat model 3D di web

Yang Anda butuhkan

2. Mempersiapkan

Clone repositori GitHub menggunakan command line ini:

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

Buka direktori root Draco.

cd draco

3. Buat encoder

Untuk memulai encoding dan decoding Draco, mari kita mulai dengan membangun aplikasi terlebih dahulu.

Membangun Encoder

  • Jalankan cmake dari direktori tempat Anda ingin membuat file build, dan teruskan jalur ke repositori Draco Anda.
mkdir build

cd build

cmake ../

make

4. Mengenkode aset 3D pertama Anda

draco_encoder akan membaca file OBJ atau PLY sebagai input, dan menghasilkan file yang dienkode dengan Draco. Kami telah menyertakan mesh Bunny Stanford untuk pengujian. Baris perintah dasarnya terlihat seperti ini:

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

Sekarang Anda dapat melihat ukuran file output dan membandingkannya dengan file .ply asli. File yang dikompresi harus jauh lebih kecil daripada ukuran file asli.

Catatan: Ukuran yang dikompresi dapat bervariasi berdasarkan opsi kompresi.

5. Mendekode file Draco di browser

Pada tahap ini, kita akan mulai dengan halaman web dasar untuk mendekode file Draco. Kita akan mulai dengan menyalin dan menempel bagian kode berikut ke dalam editor teks.

  1. Mulai dengan file HTML dasar.
<!DOCTYPE html>
<html>
<head>
  <title>Codelab - Draco Decoder</title>
  1. Cuplikan kode berikut akan memuat decoder WASM Draco.
  <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. Selanjutnya, tambahkan fungsi ini, yang akan membuat modul decoder Draco. Pembuatan modul dekoder bersifat asinkron, jadi Anda harus menunggu hingga callback dipanggil sebelum dapat menggunakan modul.
  <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. Tambahkan fungsi untuk mendekode mesh yang dienkode 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. Setelah fungsi dekode Draco tersedia, tambahkan fungsi untuk mendownload mesh yang dienkode Draco. Fungsi 'downloadEncodedMesh' menerima parameter ke file Draco yang akan dimuat. Dalam hal ini, file tersebut adalah 'bunny.drc' dari tahap sebelumnya.
    // 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. Panggil fungsi 'createDracoDecoderModule' untuk membuat modul decoder Draco, yang akan memanggil fungsi 'downloadEncodedMesh' untuk mendownload file Draco yang dienkode, yang akan memanggil fungsi 'decodeMesh' untuk mendekode mesh Draco yang dienkode.
    // Create the Draco decoder module.
    createDracoDecoderModule();
  </script>
</head>
<body>
</body>
</html>
  1. Simpan file ini sebagai "DracoDecode.html"
  2. Mulai server web python. Di terminal, ketik:
python -m SimpleHTTPServer

  1. Buka localhost:8000/DracoDecode.html di Chrome. Kotak pesan peringatan dengan jumlah poin (Num points = 34834) yang telah didekode dari model akan ditampilkan.

6. Merender file Draco dengan three.js

Setelah mengetahui cara mendekode file Draco menggunakan WASM, kita akan menggunakan penampil 3D web populer - three.js. Seperti pada contoh sebelumnya, kita akan mulai dengan menyalin dan menempel bagian kode berikut ke editor teks.

  1. Mulai dengan file HTML dasar
<!DOCTYPE html>
<html>
<head>
  <title>Codelab - Draco three.js Render</title>
  1. Tambahkan kode untuk memuat three.js dan Draco three.js loader.
  <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. Siapkan jalur dekoder 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. Tambahkan kode rendering 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. Tambahkan kode pemuatan dan dekode 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. Tambahkan kode untuk memuat file.
    window.onload = function() {
      initThreejs();
      animate();
      loadDracoMesh('bunny.drc');
    }
  </script>
</head>
<body>
  <div id="container"></div>
</body>
</html>
  1. Simpan file ini sebagai "DracoRender.html"
  2. Jika perlu, mulai ulang server web.
python -m SimpleHTTPServer

  1. Buka localhost:8000/DracoRender.html di Chrome. Sekarang Anda akan melihat file Draco yang dirender di browser.

7. Mencoba parameter encoding yang berbeda

Encoder Draco memungkinkan banyak parameter berbeda yang memengaruhi ukuran file yang dikompresi dan kualitas visual kode. Coba jalankan beberapa perintah berikutnya di command line dan lihat hasilnya.

  1. Perintah berikut menguantisasi posisi model menggunakan 12 bit (defaultnya adalah 11).
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12

  1. Perhatikan ukuran out12.drc dibandingkan dengan file bunny.drc di bagian sebelumnya. Menggunakan lebih banyak bit kuantisasi dapat meningkatkan ukuran file yang dikompresi.

3.Perintah berikut menguantisasi posisi model menggunakan 6 bit.

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

  1. Perhatikan ukuran out6.drc dibandingkan dengan file bunny.drc di bagian sebelumnya. Menggunakan lebih sedikit bit kuantisasi dapat mengurangi ukuran file yang dikompresi.
  1. Parameter berikut memengaruhi tingkat kompresi model. Dengan menggunakan tanda cl, Anda dapat menyesuaikan kompresi dari 1 (rasio kompresi terendah) hingga 10 (tertinggi).
./draco_encoder -i ../testdata/bun_zipper.ply -o outLow.drc -cl 1

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

Perhatikan output dari encoder Draco. Anda dapat melihat bahwa ada pertukaran dalam waktu yang diperlukan untuk mengompresi pada tingkat kompresi tertinggi dibandingkan dengan penghematan dalam bit. Parameter yang benar untuk aplikasi Anda akan bergantung pada persyaratan waktu dan ukuran saat waktu encoding.

8. Selamat

Anda telah menyelesaikan codelab kompresi mesh Draco dan berhasil mempelajari banyak fitur utama Draco.

Semoga Anda memahami bagaimana Draco dapat membantu membuat aset 3D Anda lebih kecil dan lebih efisien untuk ditransmisikan melalui web. Anda dapat mempelajari Draco lebih lanjut dan mendapatkan library terbaru dari github.