1. Panoramica
La grafica 3D è una parte fondamentale di molte applicazioni, tra cui giochi, progettazione e visualizzazione dei dati. Man mano che i processori grafici e gli strumenti di creazione continuano a migliorare, i modelli 3D più grandi e complessi diventeranno comuni e contribuiranno a promuovere nuove applicazioni nella realtà virtuale (VR) e nella realtà aumentata (AR) immersive. A causa di questa maggiore complessità del modello, i requisiti di archiviazione e larghezza di banda sono costretti a tenere il passo con l'esplosione dei dati 3D.
Con Draco, le applicazioni che utilizzano la grafica 3D possono essere notevolmente più piccole senza compromettere la fedeltà visiva. Per gli utenti, questo significa che le app possono ora essere scaricate più velocemente, la grafica 3D nel browser può essere caricata più rapidamente e le scene VR e AR possono ora essere trasmesse con una frazione della larghezza di banda, renderizzate rapidamente e avere un aspetto fantastico.
Che cos'è Draco?
Draco è una libreria per la compressione e la decompressione di mesh geometriche 3D e nuvole di punti. Ha lo scopo di migliorare l'archiviazione e la trasmissione della grafica 3D.
Draco è stato progettato e realizzato per garantire efficienza e velocità di compressione. Il codice supporta la compressione di punti, informazioni di connettività, coordinate della texture, informazioni sul colore, normali e qualsiasi altro attributo generico associato alla geometria. Draco viene rilasciato come codice sorgente C++ che può essere utilizzato per comprimere la grafica 3D, nonché come decodificatori C++ e JavaScript per i dati codificati.
Cosa imparerai a fare
- Come utilizzare Draco per comprimere un modello 3D
- Come utilizzare diversi modelli di compressione e in che modo influiscono sulla qualità e sulle dimensioni del modello
- Come visualizzare un modello 3D sul web
Che cosa ti serve
- Una versione recente di Chrome
- Il codice campione
- Un editor di testo
- Python
- cmake
2. Preparazione
Clona il repository GitHub utilizzando questa riga di comando:
git clone https://github.com/google/draco
Vai alla directory radice di Draco.
cd draco
3. Crea l'encoder
Per iniziare con la codifica e la decodifica Draco, iniziamo creando le app.
Build Encoder
- Esegui cmake da una directory in cui vuoi generare i file di build e trasmetti il percorso del repository Draco.
mkdir build
cd build
cmake ../
make
4. Codificare il primo asset 3D
draco_encoder leggerà i file OBJ o PLY come input e genererà file codificati con Draco. Abbiamo incluso la mesh del coniglio di Stanford per i test. La riga di comando di base ha questo aspetto:
./draco_encoder -i ../testdata/bun_zipper.ply -o bunny.drc
Ora puoi esaminare le dimensioni del file di output e confrontarle con il file .ply originale. Il file compresso deve essere molto più piccolo delle dimensioni del file originale.
Nota: le dimensioni compresse possono variare in base alle opzioni di compressione.
5. Decodificare un file Draco nel browser
A questo punto inizieremo con una pagina web di base per decodificare i file Draco. Inizieremo copiando e incollando le seguenti sezioni di codice nell'editor di testo.
- Inizia con un file HTML di base.
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco Decoder</title>
- Il seguente snippet di codice caricherà il decodificatore WASM di 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>
- Quindi aggiungi questa funzione, che creerà un modulo di decodifica Draco. La creazione del modulo del decodificatore è asincrona, quindi devi attendere la chiamata del callback prima di poter utilizzare il modulo.
<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);
}
- Aggiungi la funzione per decodificare una mesh codificata con 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);
}
- Ora che abbiamo la funzione di decodifica Draco, aggiungi una funzione per scaricare una mesh codificata con Draco. La funzione "downloadEncodedMesh" accetta un parametro per il file Draco da caricare. In questo caso, sarà "bunny.drc" della fase precedente.
// 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);
}
- Chiama la funzione "createDracoDecoderModule" per creare il modulo di decodifica Draco, che chiamerà la funzione "downloadEncodedMesh" per scaricare il file Draco codificato, che chiamerà la funzione "decodeMesh" per decodificare la mesh Draco codificata.
// Create the Draco decoder module.
createDracoDecoderModule();
</script>
</head>
<body>
</body>
</html>
- Salva questo file come "DracoDecode.html"
- Avvia il server web Python. Nel terminale, digita:
python -m SimpleHTTPServer
- Apri localhost:8000/DracoDecode.html in Chrome. Dovrebbe essere visualizzata una finestra di messaggio di avviso con il numero di punti (Num points = 34834) decodificati dal modello.
6. Esegui il rendering di un file Draco con three.js
Ora che sappiamo come decodificare un file Draco utilizzando WASM, utilizzeremo un visualizzatore 3D web popolare: three.js. Come nell'esempio precedente, inizieremo copiando e incollando le seguenti sezioni di codice nell'editor di testo.
- Inizia con un file HTML di base
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco three.js Render</title>
- Aggiungi il codice per caricare three.js e il caricatore 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>
- Configura il percorso del decodificatore 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/');
- Aggiungi il codice di 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 );
}
- Aggiungi il codice di caricamento e decodifica 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 );
} );
}
- Aggiungi il codice per caricare il file.
window.onload = function() {
initThreejs();
animate();
loadDracoMesh('bunny.drc');
}
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
- Salva questo file come "DracoRender.html"
- Se necessario, riavvia il web server.
python -m SimpleHTTPServer
- Apri localhost:8000/DracoRender.html in Chrome. Ora dovresti vedere il file Draco visualizzato nel browser.
7. Prova parametri di codifica diversi
Il codificatore Draco consente di utilizzare molti parametri diversi che influiscono sulle dimensioni del file compresso e sulla qualità visiva del codice. Prova a eseguire i prossimi comandi nella riga di comando e a visualizzare i risultati.
- Il seguente comando quantizza le posizioni del modello utilizzando 12 bit (il valore predefinito è 11).
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12
- Prendi nota delle dimensioni del file out12.drc rispetto al file bunny.drc nella sezione precedente. L'utilizzo di più bit di quantizzazione può aumentare le dimensioni del file compresso.
3.Il seguente comando quantizza le posizioni del modello utilizzando 6 bit.
./draco_encoder -i ../testdata/bun_zipper.ply -o out6.drc -qp 6
- Prendi nota delle dimensioni di out6.drc rispetto al file bunny.drc nella sezione precedente. L'utilizzo di un numero inferiore di bit di quantizzazione può ridurre le dimensioni del file compresso.
- I seguenti parametri influiscono sui livelli di compressione del modello. Utilizzando il flag cl, puoi regolare la compressione da 1 (rapporto di compressione più basso) a 10 (rapporto di compressione più alto).
./draco_encoder -i ../testdata/bun_zipper.ply -o outLow.drc -cl 1
./draco_encoder -i ../testdata/bun_zipper.ply -o outHigh.drc -cl 10
Prendi nota dell'output dell'encoder Draco. Puoi notare che esiste un compromesso tra il tempo necessario per la compressione ai livelli più elevati e il risparmio in bit. Il parametro corretto per la tua applicazione dipende dai requisiti di tempistica e dimensioni al momento della codifica.
8. Complimenti
Hai completato il lab di programmazione sulla compressione della mesh Draco ed esplorato molte delle funzionalità chiave di Draco.
Spero che sia chiaro come Draco possa contribuire a rendere gli asset 3D più piccoli e più efficienti da trasmettere sul web. Puoi scoprire di più su Draco e scaricare l'ultima libreria da GitHub.