1. Descripción general
Los gráficos en 3D son una parte fundamental de muchas aplicaciones, incluidos los juegos, el diseño y la visualización de datos. A medida que los procesadores gráficos y las herramientas de creación sigan mejorando, los modelos 3D más grandes y complejos se volverán comunes y ayudarán a impulsar nuevas aplicaciones en la realidad virtual (RV) y la realidad aumentada (RA) inmersivas. Debido a esta mayor complejidad del modelo, los requisitos de almacenamiento y ancho de banda deben mantenerse al ritmo de la explosión de datos en 3D.
Con Draco, las aplicaciones que usan gráficos en 3D pueden ser mucho más pequeñas sin comprometer la fidelidad visual. Para los usuarios, esto significa que las apps ahora se pueden descargar más rápido, los gráficos en 3D en el navegador se pueden cargar más rápido y las escenas de RV y RA ahora se pueden transmitir con una fracción del ancho de banda, renderizar rápidamente y verse fantásticas.
¿Qué es Draco?
Draco es una biblioteca para comprimir y descomprimir mallas geométricas y nubes de puntos en 3D. Su objetivo es mejorar el almacenamiento y la transmisión de gráficos en 3D.
Draco se diseñó y creó para ofrecer eficiencia y velocidad de compresión. El código admite la compresión de puntos, información de conectividad, coordenadas de textura, información de color, normales y cualquier otro atributo genérico asociado con la geometría. Draco se lanza como código fuente en C++ que se puede usar para comprimir gráficos en 3D, así como decodificadores en C++ y JavaScript para los datos codificados.
Qué aprenderás
- Cómo usar Draco para comprimir un modelo 3D
- Cómo usar diferentes modelos de compresión y cómo afectan la calidad y el tamaño del modelo
- Cómo ver un modelo 3D en la Web
Requisitos
- Una versión reciente de Chrome
- El código de muestra
- Un editor de texto
- Python
- cmake
2. Cómo prepararte
Clona el repositorio de GitHub con esta línea de comandos:
git clone https://github.com/google/draco
Navega al directorio raíz de Draco.
cd draco
3. Compila el codificador
Para comenzar con la codificación y decodificación de Draco, primero compilaremos las apps.
Compila el codificador
- Ejecuta cmake desde un directorio en el que desees generar archivos de compilación y pásale la ruta de acceso a tu repositorio de Draco.
mkdir build
cd build
cmake ../
make
4. Codifica tu primer recurso en 3D
draco_encoder leerá archivos OBJ o PLY como entrada y generará archivos codificados en Draco. Incluimos la malla de Bunny de Stanford para las pruebas. La línea de comandos básica se ve de la siguiente manera:
./draco_encoder -i ../testdata/bun_zipper.ply -o bunny.drc
Ahora puedes ver el tamaño del archivo de salida y compararlo con el archivo .ply original. El archivo comprimido debe ser mucho más pequeño que el tamaño del archivo original.
Nota: El tamaño comprimido puede variar según las opciones de compresión.
5. Cómo decodificar un archivo Draco en el navegador
En este punto, comenzaremos con una página web básica para decodificar archivos Draco. Comenzaremos por copiar y pegar las siguientes secciones de código en el editor de texto.
- Comienza con un archivo HTML básico.
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco Decoder</title>
- El siguiente fragmento de código cargará el decodificador WASM de 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>
- A continuación, agrega esta función, que creará un módulo decodificador de Draco. La creación del módulo del decodificador es asíncrona, por lo que debes esperar a que se llame a la devolución de llamada antes de poder usar el módulo.
<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);
}
- Agrega la función para decodificar una malla codificada 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);
}
- Ahora que tenemos la función de decodificación de Draco, agrega una función para descargar una malla codificada con Draco. La función "downloadEncodedMesh" acepta un parámetro para el archivo Draco que se cargará. En este caso, será "bunny.drc" de la etapa anterior.
// 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);
}
- Llama a la función "createDracoDecoderModule" para crear el módulo del decodificador de Draco, que llamará a la función "downloadEncodedMesh" para descargar el archivo de Draco codificado, que llamará a la función "decodeMesh" para decodificar la malla de Draco codificada.
// Create the Draco decoder module.
createDracoDecoderModule();
</script>
</head>
<body>
</body>
</html>
- Guarda este archivo como "DracoDecode.html".
- Inicia el servidor web de Python. En la terminal, escribe lo siguiente:
python -m SimpleHTTPServer
- Abre localhost:8000/DracoDecode.html en Chrome. Se debería mostrar un cuadro de mensaje de alerta con la cantidad de puntos (Num points = 34834) que se decodificaron del modelo.
6. Renderiza un archivo Draco con three.js
Ahora que sabemos cómo decodificar un archivo Draco con WASM, usaremos un popular visualizador web en 3D: three.js. Al igual que en el ejemplo anterior, comenzaremos por copiar y pegar las siguientes secciones de código en el editor de texto.
- Comienza con un archivo HTML básico
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco three.js Render</title>
- Agrega código para cargar three.js y el cargador de 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 la ruta de acceso del decodificador de 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/');
- Agrega código de renderización de 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 );
}
- Agrega código de carga y decodificación de 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 );
} );
}
- Agrega código para cargar el archivo.
window.onload = function() {
initThreejs();
animate();
loadDracoMesh('bunny.drc');
}
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
- Guarda este archivo como "DracoRender.html".
- Si es necesario, reinicia el servidor web.
python -m SimpleHTTPServer
- Abre localhost:8000/DracoRender.html en Chrome. Ahora deberías ver tu archivo Draco renderizado en el navegador.
7. Prueba diferentes parámetros de codificación
El codificador de Draco permite muchos parámetros diferentes que afectan el tamaño del archivo comprimido y la calidad visual del código. Intenta ejecutar los siguientes comandos en la línea de comandos y observa los resultados.
- El siguiente comando cuantifica las posiciones del modelo con 12 bits (el valor predeterminado es 11).
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12
- Ten en cuenta el tamaño del archivo out12.drc en comparación con el archivo bunny.drc de la sección anterior. Usar más bits de cuantificación puede aumentar el tamaño del archivo comprimido.
3.El siguiente comando cuantifica las posiciones del modelo con 6 bits.
./draco_encoder -i ../testdata/bun_zipper.ply -o out6.drc -qp 6
- Ten en cuenta el tamaño del archivo out6.drc en comparación con el archivo bunny.drc de la sección anterior. Usar menos bits de cuantificación puede reducir el tamaño del archivo comprimido.
- Los siguientes parámetros afectan los niveles de compresión del modelo. Con la marca cl, puedes ajustar la compresión de 1 (proporción de compresión más baja) a 10 (más alta).
./draco_encoder -i ../testdata/bun_zipper.ply -o outLow.drc -cl 1
./draco_encoder -i ../testdata/bun_zipper.ply -o outHigh.drc -cl 10
Observa el resultado del codificador de Draco. Puedes ver que existe una compensación entre el tiempo necesario para comprimir con los niveles de compresión más altos y el ahorro en bits. El parámetro correcto para tu aplicación dependerá de los requisitos de tiempo y tamaño en el momento de la codificación.
8. Felicitaciones
Completaste el codelab de compresión de mallas de Draco y exploraste con éxito muchas funciones clave de Draco.
Esperamos que te haya quedado claro cómo Draco puede ayudarte a reducir el tamaño de tus recursos 3D y a que sean más eficientes para transmitirlos a través de la Web. Puedes obtener más información sobre Draco y la biblioteca más reciente en GitHub.