การเพิ่มประสิทธิภาพข้อมูล 3 มิติด้วย Draco Geometry Compression

1. ภาพรวม

กราฟิก 3 มิติเป็นส่วนพื้นฐานของแอปพลิเคชันจำนวนมาก ซึ่งรวมถึงเกม การออกแบบ และการแสดงข้อมูลด้วยภาพ เมื่อโปรเซสเซอร์กราฟิกและเครื่องมือสร้างสรรค์ได้รับการปรับปรุงอย่างต่อเนื่อง โมเดล 3 มิติที่มีขนาดใหญ่และซับซ้อนมากขึ้นจะกลายเป็นเรื่องปกติและช่วยขับเคลื่อนแอปพลิเคชันใหม่ๆ ใน Virtual Reality (VR) และ Augmented Reality (AR) ที่สมจริง เนื่องจากความซับซ้อนของโมเดลที่เพิ่มขึ้นนี้ ข้อกำหนดด้านพื้นที่เก็บข้อมูลและแบนด์วิดท์จึงต้องเพิ่มขึ้นตามการขยายตัวของข้อมูล 3 มิติ

Draco ช่วยให้แอปพลิเคชันที่ใช้กราฟิก 3 มิติมีขนาดเล็กลงอย่างมากโดยไม่ลดความเที่ยงตรงของภาพ สำหรับผู้ใช้แล้ว หมายความว่าตอนนี้สามารถดาวน์โหลดแอปได้เร็วขึ้น กราฟิก 3 มิติในเบราว์เซอร์โหลดได้เร็วขึ้น และฉาก VR และ AR สามารถส่งได้โดยใช้แบนด์วิดท์เพียงเล็กน้อย แสดงผลได้อย่างรวดเร็ว และดูดี

Draco คืออะไร

Draco เป็นไลบรารีสำหรับการบีบอัดและคลายการบีบอัดเมชและกลุ่มจุดทางเรขาคณิต 3 มิติ โดยมีวัตถุประสงค์เพื่อปรับปรุงการจัดเก็บและการส่งกราฟิก 3 มิติ

Draco ออกแบบและสร้างขึ้นเพื่อประสิทธิภาพและความเร็วในการบีบอัด โค้ดรองรับการบีบอัดจุด ข้อมูลการเชื่อมต่อ พิกัดพื้นผิว ข้อมูลสี เวกเตอร์ปกติ และแอตทริบิวต์ทั่วไปอื่นๆ ที่เชื่อมโยงกับเรขาคณิต Draco เปิดตัวเป็นซอร์สโค้ด C++ ที่ใช้บีบอัดกราฟิก 3 มิติได้ รวมถึงตัวถอดรหัส C++ และ JavaScript สำหรับข้อมูลที่เข้ารหัส

สิ่งที่คุณจะได้เรียนรู้

  • วิธีใช้ Draco เพื่อบีบอัดโมเดล 3 มิติ
  • วิธีใช้โมเดลการบีบอัดต่างๆ และวิธีที่โมเดลเหล่านั้นส่งผลต่อคุณภาพและขนาดของโมเดล
  • วิธีดูโมเดล 3 มิติบนเว็บ

สิ่งที่คุณต้องมี

2. การเริ่มตั้งค่า

โคลนที่เก็บ Github โดยใช้บรรทัดคำสั่งนี้

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

ไปยังไดเรกทอรีรูทของ Draco

cd draco

3. สร้างโปรแกรมเปลี่ยนไฟล์

หากต้องการเริ่มต้นด้วยการเข้ารหัสและถอดรหัส Draco เรามาเริ่มสร้างแอปกันก่อน

สร้างโปรแกรมเปลี่ยนไฟล์

  • เรียกใช้ cmake จากไดเรกทอรีที่ต้องการสร้างไฟล์บิลด์ แล้วส่งเส้นทางไปยังที่เก็บ Draco
mkdir build

cd build

cmake ../

make

4. เข้ารหัสชิ้นงาน 3 มิติชิ้นแรก

draco_encoder จะอ่านไฟล์ OBJ หรือ PLY เป็นอินพุต และส่งออกไฟล์ที่เข้ารหัส Draco เราได้รวมโมเดลตาข่ายกระต่ายของมหาวิทยาลัยสแตนฟอร์ดไว้สำหรับการทดสอบ บรรทัดคำสั่งพื้นฐานมีลักษณะดังนี้

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

ตอนนี้คุณสามารถดูขนาดของไฟล์เอาต์พุตและเปรียบเทียบกับไฟล์ .ply ต้นฉบับได้แล้ว ไฟล์ที่บีบอัดควรมีขนาดเล็กกว่าไฟล์ต้นฉบับมาก

หมายเหตุ: ขนาดที่บีบอัดอาจแตกต่างกันไปตามตัวเลือกการบีบอัด

5. ถอดรหัสไฟล์ Draco ในเบราว์เซอร์

ตอนนี้เราจะเริ่มด้วยหน้าเว็บพื้นฐานเพื่อถอดรหัสไฟล์ Draco เราจะเริ่มต้นด้วยการคัดลอกและวางส่วนโค้ดต่อไปนี้ลงในโปรแกรมแก้ไขข้อความ

  1. เริ่มต้นด้วยไฟล์ HTML พื้นฐาน
<!DOCTYPE html>
<html>
<head>
  <title>Codelab - Draco Decoder</title>
  1. ข้อมูลโค้ดต่อไปนี้จะโหลดตัวถอดรหัส 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. จากนั้นเพิ่มฟังก์ชันนี้ ซึ่งจะสร้างโมดูลตัวถอดรหัส Draco การสร้างโมดูลตัวถอดรหัสเป็นแบบไม่พร้อมกัน ดังนั้นคุณต้องรอจนกว่าจะมีการเรียกใช้ฟังก์ชันเรียกกลับก่อนจึงจะใช้โมดูลได้
  <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. เพิ่มฟังก์ชันเพื่อถอดรหัสเมชที่เข้ารหัสด้วย 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. ตอนนี้เรามีฟังก์ชันถอดรหัส Draco แล้ว ให้เพิ่มฟังก์ชันเพื่อดาวน์โหลด Mesh ที่เข้ารหัสด้วย Draco ฟังก์ชัน "downloadEncodedMesh" รับพารามิเตอร์ไปยังไฟล์ Draco ที่จะโหลด ในกรณีนี้จะเป็น "bunny.drc" จากขั้นตอนก่อนหน้า
    // 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. เรียกใช้ฟังก์ชัน "createDracoDecoderModule" เพื่อสร้างโมดูลตัวถอดรหัส Draco ซึ่งจะเรียกใช้ฟังก์ชัน "downloadEncodedMesh" เพื่อดาวน์โหลดไฟล์ Draco ที่เข้ารหัส ซึ่งจะเรียกใช้ฟังก์ชัน "decodeMesh" เพื่อถอดรหัสเมช Draco ที่เข้ารหัส
    // Create the Draco decoder module.
    createDracoDecoderModule();
  </script>
</head>
<body>
</body>
</html>
  1. บันทึกไฟล์นี้เป็น "DracoDecode.html"
  2. เริ่มเว็บเซิร์ฟเวอร์ Python ในประเภทเทอร์มินัล ให้ทำดังนี้
python -m SimpleHTTPServer

  1. เปิด localhost:8000/DracoDecode.html ใน Chrome ซึ่งควรแสดงกล่องข้อความแจ้งเตือนพร้อมจำนวนคะแนน (Num points = 34834) ที่ถอดรหัสจากโมเดล

6. แสดงผลไฟล์ Draco ด้วย three.js

ตอนนี้เราทราบวิธีถอดรหัสไฟล์ Draco โดยใช้ WASM แล้ว เราจะใช้โปรแกรมดู 3 มิติบนเว็บยอดนิยมอย่าง three.js เช่นเดียวกับตัวอย่างก่อนหน้า เราจะเริ่มด้วยการคัดลอกและวางส่วนโค้ดต่อไปนี้ลงในโปรแกรมแก้ไขข้อความ

  1. เริ่มต้นด้วยไฟล์ HTML พื้นฐาน
<!DOCTYPE html>
<html>
<head>
  <title>Codelab - Draco three.js Render</title>
  1. เพิ่มโค้ดเพื่อโหลด three.js และโปรแกรมโหลด 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. ตั้งค่าเส้นทางตัวถอดรหัส 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. เพิ่มโค้ดการแสดงผล 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. เพิ่มโค้ดการโหลดและการถอดรหัส 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. เพิ่มโค้ดเพื่อโหลดไฟล์
    window.onload = function() {
      initThreejs();
      animate();
      loadDracoMesh('bunny.drc');
    }
  </script>
</head>
<body>
  <div id="container"></div>
</body>
</html>
  1. บันทึกไฟล์นี้เป็น "DracoRender.html"
  2. รีสตาร์ทเว็บเซิร์ฟเวอร์หากจำเป็น
python -m SimpleHTTPServer

  1. เปิด localhost:8000/DracoRender.html ใน Chrome ตอนนี้คุณควรเห็นไฟล์ Draco แสดงในเบราว์เซอร์แล้ว

7. ลองใช้พารามิเตอร์การเข้ารหัสอื่นๆ

ตัวเข้ารหัส Draco อนุญาตให้ใช้พารามิเตอร์ต่างๆ มากมายซึ่งส่งผลต่อขนาดของไฟล์ที่บีบอัดและคุณภาพของภาพในโค้ด ลองเรียกใช้คำสั่ง 2-3 คำสั่งถัดไปในบรรทัดคำสั่งและดูผลลัพธ์

  1. คำสั่งต่อไปนี้จะกำหนดปริมาณตำแหน่งของโมเดลโดยใช้ 12 บิต (ค่าเริ่มต้นคือ 11)
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12

  1. โปรดสังเกตขนาดของไฟล์ out12.drc เมื่อเทียบกับไฟล์ bunny.drc ในส่วนก่อนหน้า การใช้บิตการหาปริมาณมากขึ้นจะเพิ่มขนาดของไฟล์ที่บีบอัด

3. คำสั่งต่อไปนี้จะควอนไทซ์ตำแหน่งของโมเดลโดยใช้ 6 บิต

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

  1. โปรดสังเกตขนาดของไฟล์ out6.drc เมื่อเทียบกับไฟล์ bunny.drc ในส่วนก่อนหน้า การใช้บิตการหาปริมาณน้อยลงจะช่วยลดขนาดของไฟล์ที่บีบอัดได้
  1. พารามิเตอร์ต่อไปนี้ส่งผลต่อระดับการบีบอัดของโมเดล การใช้แฟล็ก cl จะช่วยให้คุณปรับการบีบอัดได้ตั้งแต่ 1 (อัตราการบีบอัดต่ำสุด) ถึง 10 (อัตราการบีบอัดสูงสุด)
./draco_encoder -i ../testdata/bun_zipper.ply -o outLow.drc -cl 1

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

จดบันทึกเอาต์พุตจากตัวเข้ารหัส Draco คุณจะเห็นว่าเวลาที่ใช้ในการบีบอัดที่ระดับการบีบอัดสูงสุดนั้นต้องแลกมากับการประหยัดบิต พารามิเตอร์ที่ถูกต้องสำหรับแอปพลิเคชันจะขึ้นอยู่กับข้อกำหนดด้านเวลาและขนาดในเวลาที่เข้ารหัส

8. ขอแสดงความยินดี

คุณทำโค้ดแล็บการบีบอัดเมช Draco เสร็จแล้ว และได้สำรวจฟีเจอร์สำคัญหลายอย่างของ Draco เรียบร้อยแล้ว

เราหวังว่าคุณจะเห็นได้ชัดว่า Draco ช่วยลดขนาดชิ้นงาน 3 มิติและทำให้ส่งผ่านเว็บได้อย่างมีประสิทธิภาพมากขึ้นได้อย่างไร ดูข้อมูลเพิ่มเติมเกี่ยวกับ Draco และรับไลบรารีล่าสุดได้จาก github