Mengoptimalkan data 3D dengan Kompresi Geometri Draco

1. Ringkasan

Grafis 3D adalah bagian dasar dari banyak aplikasi, termasuk game, desain, dan visualisasi data. Seiring dengan terus berkembangnya prosesor grafis dan alat pembuat grafis yang terus berkembang, model 3D yang lebih besar dan kompleks akan menjadi hal yang lumrah serta membantu mendorong aplikasi baru dalam virtual reality (VR) yang imersif dan augmented reality (AR). Karena kompleksitas model yang meningkat ini, persyaratan penyimpanan dan bandwidth terpaksa menyesuaikan dengan ledakan data 3D.

Dengan Draco, aplikasi yang menggunakan grafis 3D dapat secara signifikan lebih kecil tanpa mengorbankan fidelitas visual. Bagi pengguna, hal ini berarti aplikasi kini dapat didownload dengan lebih cepat, grafis 3D di browser dapat dimuat lebih cepat, dan adegan VR dan AR sekarang dapat ditransmisikan dengan sebagian kecil bandwidth, dirender dengan cepat dan terlihat luar biasa.

Apa itu Draco?

Draco adalah library untuk mengompresi dan mendekompresi jaring geometris 3D dan cloud titik. Hal ini dimaksudkan untuk meningkatkan penyimpanan dan transmisi grafis 3D.

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

Yang akan Anda pelajari

  • Cara menggunakan Draco untuk mengompresi model 3D
  • Cara menggunakan model kompresi yang berbeda 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. Membangun encoder

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

Encoder Build

  • 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 membuat output file yang dienkode Draco. Kami telah menyertakan mesh Kelinci Stanford untuk pengujian. Command line dasar terlihat seperti ini:

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

Sekarang Anda dapat melihat ukuran file {i>output<i} dan membandingkannya dengan file .ply asli. File yang dikompresi harus jauh lebih kecil dari ukuran file aslinya.

Catatan: Ukuran terkompresi 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 menempelkan bagian kode berikut ke dalam editor teks.

  1. Mulailah dengan file HTML biasa.
<!DOCTYPE html>
<html>
<head>
  <title>Codelab - Draco Decoder</title>
  1. Cuplikan kode berikut akan memuat dekoder 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 untuk membuat modul decoder Draco. Pembuatan modul decoder bersifat asinkron, sehingga Anda harus menunggu hingga callback dipanggil sebelum dapat menggunakan modul tersebut.
  <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 berenkode 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 kita menerapkan fungsi dekode Draco, tambahkan fungsi untuk mendownload mesh berenkode Draco. Fungsi ‘downloadEncodedMesh' menerima parameter ke file Draco yang akan dimuat. Dalam hal ini, variabel 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. Memanggil 'createDracoDecoderModule' untuk membuat modul decoder Draco, yang akan memanggil 'downloadEncodedMesh' untuk mengunduh 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. Pada jenis terminal:
python -m SimpleHTTPServer

  1. Buka localhost:8000/DracoDecode.html di Chrome. Tindakan ini akan menampilkan kotak pesan peringatan dengan jumlah poin (Num poin = 34834) yang telah didekode dari model.

6. Merender file Draco dengan tiga.js

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

  1. Mulai dengan file HTML dasar
<!DOCTYPE html>
<html>
<head>
  <title>Codelab - Draco three.js Render</title>
  1. Menambahkan kode untuk memuat loader3.js dan loader tiga.js Draco.
  <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. Menyiapkan jalur decoder 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 tiga.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 Anda dirender di browser.

7. Coba parameter encoding lain

Encoder Draco memungkinkan berbagai parameter yang memengaruhi ukuran file terkompresi dan kualitas visual kode. Coba jalankan beberapa perintah berikutnya di baris perintah dan lihat hasilnya.

  1. Perintah berikut mengkuantiasi posisi model menggunakan 12 (defaultnya adalah 11) bit.
./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 mengkuantiasi 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 men-tuning kompresi dari 1 (rasio kompresi terendah) sampai 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

Catat output dari encoder Draco. Anda dapat melihat bahwa ada imbal balik 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 pada waktu encoding.

8. Selamat

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

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