1. Panoramica
La grafica 3D è una parte fondamentale di molte applicazioni, tra cui quelle di gioco, progettazione e visualizzazione dei dati. Con il costante miglioramento dei processori grafici e degli strumenti di creazione, i modelli 3D più grandi e complessi diventeranno comuni e contribuiranno ad alimentare nuove applicazioni nella realtà virtuale immersiva (VR) e nella realtà aumentata (AR). A causa dell'aumento della complessità del modello, i requisiti di archiviazione e larghezza di banda sono costretti a stare al passo con l'esplosione dei dati 3D.
Con Draco, le applicazioni che utilizzano grafica 3D possono essere significativamente più piccole senza compromettere la fedeltà visiva. Per gli utenti, ciò significa che le app possono essere scaricate più rapidamente, 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, essere visualizzate rapidamente e avere un aspetto fantastico.
Cos'è Draco?
Draco è una libreria per comprimere e decomprimere meshe geometriche e nuvole di punti in 3D. È destinata a migliorare la memorizzazione e la trasmissione di grafica 3D.
Draco è stato progettato e realizzato per offrire efficienza e velocità di compressione. Il codice supporta punti di compressione, informazioni di connettività, coordinate di texture, informazioni sui colori, 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 così come i decoder 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 come questi 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 root di Draco.
cd draco
3. Crea l'encoder
Per cominciare con la codifica e decodifica Draco, iniziamo innanzitutto creando le app.
Codificatore build
- Esegui cmake da una directory in cui desideri generare i file di build, quindi passa il percorso al tuo repository Draco.
mkdir build
cd build
cmake ../
make
4. Codifica il tuo primo asset 3D
draco_encoder leggerà i file OBJ o PLY come input e restituirà i file con codifica Draco. Per i test abbiamo incluso il mesh Bunny di Stanford. La riga di comando di base è simile alla seguente:
./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. Le dimensioni del file compresso dovrebbero essere di gran lunga inferiori a quelle del file originale.
Nota: le dimensioni compresse possono variare in base alle opzioni di compressione.
5. Decodifica un file Draco nel browser
A questo punto inizieremo con una pagina web di base per decodificare i file Draco. Iniziamo 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 decoder 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>
- Poi aggiungi questa funzione, che creerà un modulo decoder Draco. La creazione del modulo decoder è asincrona, quindi devi attendere che venga chiamato il 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 in 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 la funzione di decodifica Draco è attiva, aggiungi una funzione per scaricare un mesh codificato Draco. La funzione "downloadEncodedMesh" accetta un parametro per il caricamento del file Draco. In questo caso sarà "bunny.drc". rispetto alla 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 "createDracoDecoderModule" per creare il modulo decoder Draco, che chiamerà "downloadEncodedMesh" per scaricare il file Draco codificato, che chiama "decodeMesh" per decodificare la mesh Draco codificata.
// Create the Draco decoder module.
createDracoDecoderModule();
</script>
</head>
<body>
</body>
</html>
- Salva il file come "DracoDecode.html"
- Avvia il server web Python. Nel tipo di terminale:
python -m SimpleHTTPServer
- Apri localhost:8000/DracoDecode.html in Chrome. Dovrebbe apparire una casella con un messaggio di avviso con il numero di punti (Num. punti = 34834) che sono stati decodificati dal modello.
6. Esegui il rendering di un file Draco con tre.js
Ora che sappiamo come decodificare un file Draco utilizzando WASM, utilizzeremo il famoso visualizzatore 3D per il web, tre.js. Come nell'esempio precedente, inizieremo copiando e incollando nell'editor di testo le seguenti sezioni di codice.
- Inizia con il file HTML di base
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco three.js Render</title>
- Aggiungi il codice per caricare tre.js e il caricatore tre.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>
- Configura il percorso del 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/');
- Aggiungi il codice di rendering tre.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 caricamento e la decodifica del codice 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 il file come "DracoRender.html"
- Se necessario, riavvia il server web.
python -m SimpleHTTPServer
- Apri localhost:8000/DracoRender.html in Chrome. A questo punto dovresti vedere il rendering del file Draco nel browser.
7. Provare parametri di codifica diversi
Il codificatore Draco consente l'uso di molti parametri diversi che influiscono sulle dimensioni del file compresso e sulla qualità visiva del codice. Prova a eseguire i comandi successivi nella riga di comando e a vedere i risultati.
- Il comando seguente quantifica le posizioni del modello utilizzando 12 bit (il valore predefinito è 11).
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12
- Osserva le dimensioni del file out12.drc rispetto a quelle del file bunny.drc nella sezione precedente. L'utilizzo di più bit di quantizzazione può aumentare le dimensioni del file compresso.
3.Il comando seguente quantifica le posizioni del modello a 6 bit.
./draco_encoder -i ../testdata/bun_zipper.ply -o out6.drc -qp 6
- Osserva le dimensioni del file out6.drc rispetto a quelle del file bunny.drc nella sezione precedente. L'utilizzo di meno 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 ottimizzare la compressione da 1 (rapporto di compressione più basso) a 10 (massimo).
./draco_encoder -i ../testdata/bun_zipper.ply -o outLow.drc -cl 1
./draco_encoder -i ../testdata/bun_zipper.ply -o outHigh.drc -cl 10
Osserva l'output del codificatore Draco. Puoi notare un compromesso nel tempo necessario per la compressione ai livelli di compressione più elevati rispetto al risparmio in bit. Il parametro corretto per l'applicazione dipenderà dai requisiti di tempo e dimensioni al momento della codifica.
8. Complimenti
Hai terminato il lab sul codice di compressione della rete mesh di Draco ed hai esplorato con successo molte funzionalità chiave di Draco.
Speriamo che ti sia chiaro come Draco può aiutarti a rendere le tue risorse 3D più piccole e più efficienti da trasmettere sul web. Puoi scoprire di più su Draco e scaricare la raccolta più recente da github.