1. Übersicht
3D-Grafiken sind ein wesentlicher Bestandteil vieler Anwendungen wie Spielen, Design und Datenvisualisierung. Da Grafikprozessoren und Erstellungstools immer besser werden, werden immer größere und komplexere 3D-Modelle zum Standard machen und neue Anwendungen für immersive Virtual Reality (VR) und Augmented Reality (AR) ermöglichen. Aufgrund der zunehmenden Komplexität des Modells sind Speicher- und Bandbreitenanforderungen gezwungen, mit der explosionsartigen Zunahme von 3D-Daten Schritt zu halten.
Mit Draco können Anwendungen, die 3D-Grafiken verwenden, erheblich kleiner sein, ohne die visuelle Darstellung zu beeinträchtigen. Für Nutzer bedeutet das, dass Apps jetzt schneller heruntergeladen werden können, 3D-Grafiken im Browser schneller geladen werden und VR- und AR-Szenen mit einem Bruchteil der Bandbreite übertragen, schnell gerendert und fantastisch aussehen.
Was ist Draco?
Draco ist eine Bibliothek zum Komprimieren und Dekomprimieren von geometrischen 3D-Meshes und Punktwolken. Es dient dazu, die Speicherung und Übertragung von 3D-Grafiken zu verbessern.
Draco wurde für effiziente und schnelle Komprimierung entwickelt. Der Code unterstützt das Komprimieren von Punkten, Verbindungsinformationen, Texturkoordinaten, Farbinformationen, Normalen und alle anderen generischen Attribute im Zusammenhang mit Geometrie. Draco wird als C++-Quellcode veröffentlicht, mit dem 3D-Grafiken sowie C++- und JavaScript-Decodierer für die codierten Daten komprimiert werden können.
Lerninhalte
- Mit Draco ein 3D-Modell komprimieren
- Verwendung verschiedener Komprimierungsmodelle und deren Einfluss auf die Modellqualität und -größe
- 3D-Modelle im Web ansehen
Voraussetzungen
- Eine aktuelle Version von Chrome
- Beispielcode
- Ein Texteditor
- Python
- cmake
2. Einrichtung
Klonen Sie das GitHub-Repository mit dieser Befehlszeile:
git clone https://github.com/google/draco
Gehen Sie zum Draco-Stammverzeichnis.
cd draco
3. Encoder erstellen
Um mit der Draco-Codierung und -Decodierung zu beginnen, beginnen wir mit dem Erstellen der Apps.
Build-Encoder
- Führen Sie cmake in einem Verzeichnis aus, in dem Sie Build-Dateien generieren möchten, und übergeben Sie den Pfad an Ihr Draco-Repository.
mkdir build
cd build
cmake ../
make
4. Erstes 3D-Asset codieren
draco_encoder liest OBJ- oder PLY-Dateien als Eingabe und gibt Draco-codierte Dateien aus. Wir haben das Stanford's-Bunny-Mesh für Tests verwendet. Die einfache Befehlszeile sieht so aus:
./draco_encoder -i ../testdata/bun_zipper.ply -o bunny.drc
Jetzt können Sie die Größe der Ausgabedatei mit der ursprünglichen Ply-Datei vergleichen. Die komprimierte Datei sollte deutlich kleiner als die ursprüngliche Dateigröße sein.
Hinweis: Die komprimierte Größe kann je nach Komprimierungsoptionen variieren.
5. Draco-Datei im Browser decodieren
An dieser Stelle beginnen wir mit einer einfachen Webseite, um Draco-Dateien zu decodieren. Zunächst kopieren wir die folgenden Codeabschnitte und fügen sie in den Texteditor ein.
- Beginnen Sie mit einer einfachen HTML-Datei.
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco Decoder</title>
- Mit dem folgenden Code-Snippet wird der Draco-WASM-Decoder geladen.
<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>
- Fügen Sie diese Funktion hinzu, um ein Draco-Decoder-Modul zu erstellen. Die Erstellung des Decodermoduls erfolgt asynchron. Sie müssen also warten, bis der Callback aufgerufen wird, bevor Sie das Modul verwenden können.
<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);
}
- Fügen Sie die Funktion zum Decodieren eines Draco-codierten Mesh-Netzwerks hinzu.
// 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);
}
- Nachdem Sie nun die Draco-Decodierungsfunktion eingerichtet haben, fügen Sie eine Funktion zum Herunterladen eines Draco-codierten Mesh-Netzwerks hinzu. Die Funktion „downloadEncodedMesh“ akzeptiert einen Parameter für die zu ladende Draco-Datei. In diesem Fall ist das „bunny.drc“. aus der vorherigen Phase.
// 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);
}
- Rufen Sie „createDracoDecoderModule“ auf. um das Draco-Decoder-Modul zu erstellen, das "downloadEncodedMesh" um die codierte Draco-Datei herunterzuladen, die das "decodeMesh" um das codierte Draco-Mesh zu decodieren.
// Create the Draco decoder module.
createDracoDecoderModule();
</script>
</head>
<body>
</body>
</html>
- Speichern Sie diese Datei unter dem Namen "DracoDecode.html".
- Starten Sie den Python-Webserver. Im Terminaltyp:
python -m SimpleHTTPServer
- Öffnen Sie in Chrome localhost:8000/DracoDecode.html. Daraufhin sollte ein Meldungsfeld mit der Anzahl der Punkte (Num points = 34834) angezeigt werden, die aus dem Modell decodiert wurden.
6. Draco-Datei mit drei.js rendern
Nachdem wir nun wissen, wie eine Draco-Datei mit WASM decodiert wird, verwenden wir einen beliebten 3D-Web-Viewer: drei.js. Wie im vorherigen Beispiel kopieren wir zunächst die folgenden Codeabschnitte und fügen sie in den Texteditor ein.
- Mit einfacher HTML-Datei beginnen
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco three.js Render</title>
- Fügen Sie Code zum Laden des Ladeprogramms „3.js“ und „Three.js“ hinzu.
<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>
- Richten Sie den Draco-Decoder-Pfad ein.
<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/');
- Fügen Sie drei.js-Renderingcode hinzu.
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 );
}
- Lade und Decodierung von Draco-Code hinzufügen.
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 );
} );
}
- Fügen Sie Code zum Laden der Datei hinzu.
window.onload = function() {
initThreejs();
animate();
loadDracoMesh('bunny.drc');
}
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
- Speichern Sie diese Datei unter dem Namen "DracoRender.html".
- Starten Sie den Webserver gegebenenfalls neu.
python -m SimpleHTTPServer
- Öffnen Sie in Chrome localhost:8000/DracoRender.html. Die Draco-Datei sollte jetzt im Browser gerendert werden.
7. Verschiedene Codierungsparameter ausprobieren
Der Draco-Encoder unterstützt viele verschiedene Parameter, die sich auf die Größe der komprimierten Datei und die visuelle Qualität des Codes auswirken. Versuchen Sie, die nächsten Befehle in der Befehlszeile auszuführen, und sehen Sie sich die Ergebnisse an.
- Der folgende Befehl quantisiert die Positionen des Modells mit 12 Bit (Standardwert: 11).
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12
- Achten Sie auf die Größe von „out12.drc“ im Vergleich zur Datei „bunny.drc“ im vorherigen Abschnitt. Die Verwendung von mehr Quantisierungsbits kann die Größe der komprimierten Datei erhöhen.
3.Mit dem folgenden Befehl werden die Positionen des Modells mit 6 Bit quantisiert.
./draco_encoder -i ../testdata/bun_zipper.ply -o out6.drc -qp 6
- Beachten Sie die Größe von „out6.drc“ im Vergleich zur Datei „bunny.drc“ im vorherigen Abschnitt. Durch die Verwendung weniger Quantisierungsbits kann die Größe der komprimierten Datei reduziert werden.
- Die folgenden Parameter wirken sich auf die Komprimierungsstufen des Modells aus. Mit dem Flag „cl“ können Sie die Komprimierung von 1 (niedrigste Komprimierungsverhältnis) bis 10 (höchste) einstellen.
./draco_encoder -i ../testdata/bun_zipper.ply -o outLow.drc -cl 1
./draco_encoder -i ../testdata/bun_zipper.ply -o outHigh.drc -cl 10
Sehen Sie sich die Ausgabe des Draco-Encoders an. Wie Sie sehen, gibt es einen Kompromiss zwischen der für die Komprimierung bei höchsten Komprimierungsstufen erforderlichen Zeit im Vergleich zu den Einsparungen in Bit. Der richtige Parameter für Ihre App hängt von den Zeit- und Größenanforderungen zum Zeitpunkt der Codierung ab.
8. Glückwunsch
Sie haben das Lab für den Draco-Mesh-Komprimierungscode abgeschlossen und viele wichtige Funktionen von Draco erkundet.
Hoffentlich ist Ihnen jetzt klar, wie Sie mit Draco Ihre 3D-Assets verkleinern und sie effizienter über das Web übertragen können. Weitere Informationen zu Draco und die aktuelle Bibliothek finden Sie auf github.