1. Visão geral
Os gráficos 3D são uma parte fundamental de muitos aplicativos, incluindo jogos, design e visualização de dados. À medida que os processadores gráficos e as ferramentas de criação continuam melhorando, modelos 3D maiores e mais complexos vão se tornar comuns e ajudar a impulsionar novos aplicativos em realidade virtual (RV) e realidade aumentada (RA) imersivas. Devido a essa maior complexidade do modelo, os requisitos de armazenamento e largura de banda precisam acompanhar a explosão de dados 3D.
Com o Draco, os aplicativos que usam gráficos 3D podem ser significativamente menores sem comprometer a fidelidade visual. Para os usuários, isso significa que os apps podem ser baixados mais rápido, os gráficos 3D no navegador podem ser carregados mais rapidamente, e as cenas de RV e RA agora podem ser transmitidas com uma fração da largura de banda, renderizadas rapidamente e com uma aparência fantástica.
O que é o Draco?
O Draco é uma biblioteca para compactar e descompactar malhas geométricas 3D e nuvens de pontos. Ele foi criado para melhorar o armazenamento e a transmissão de gráficos 3D.
O Draco foi projetado e criado para oferecer eficiência e velocidade de compressão. O código é compatível com a compactação de pontos, informações de conectividade, coordenadas de textura, informações de cor, normais e outros atributos genéricos associados à geometria. O Draco é lançado como código-fonte em C++ que pode ser usado para compactar gráficos 3D, além de decodificadores em C++ e JavaScript para os dados codificados.
O que você vai aprender
- Como usar o Draco para compactar um modelo 3D
- Como usar diferentes modelos de compactação e como eles afetam a qualidade e o tamanho do modelo
- Como ver um modelo 3D na Web
O que é necessário
- Uma versão recente do Chrome
- Código de amostra
- Um editor de texto
- Python
- cmake
2. Etapas da configuração
Clone o repositório do GitHub usando esta linha de comando:
git clone https://github.com/google/draco
Navegue até o diretório raiz do Draco.
cd draco
3. Criar o codificador
Para começar a codificar e decodificar com o Draco, vamos criar os apps primeiro.
Criar codificador
- Execute o cmake em um diretório onde você quer gerar arquivos de build e transmita o caminho para seu repositório do Draco.
mkdir build
cd build
cmake ../
make
4. Codificar seu primeiro recurso 3D
O draco_encoder lê arquivos OBJ ou PLY como entrada e gera arquivos codificados em Draco. Incluímos a malha do coelho de Stanford para testes. A linha de comando básica é assim:
./draco_encoder -i ../testdata/bun_zipper.ply -o bunny.drc
Agora você pode conferir o tamanho do arquivo de saída e comparar com o arquivo .ply original. O arquivo compactado precisa ser muito menor do que o original.
Observação: o tamanho compactado pode variar de acordo com as opções de compactação.
5. Decodificar um arquivo Draco no navegador
Neste ponto, vamos começar com uma página da Web básica para decodificar arquivos Draco. Vamos começar copiando e colando as seções de código a seguir no editor de texto.
- Comece com um arquivo HTML básico.
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco Decoder</title>
- O snippet de código a seguir carrega o decodificador WASM do 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>
- Em seguida, adicione esta função, que vai criar um módulo de decodificador Draco. A criação do módulo de decodificador é assíncrona. Portanto, aguarde até que o callback seja chamado antes de usar o 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);
}
- Adicione a função para decodificar uma malha codificada em 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);
}
- Agora que temos a função de decodificação do Draco, adicione uma função para baixar uma malha codificada pelo Draco. A função "downloadEncodedMesh" aceita um parâmetro para o arquivo Draco a ser carregado. Nesse caso, será "bunny.drc" da 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);
}
- Chame a função "createDracoDecoderModule" para criar o módulo de decodificador do Draco, que vai chamar a função "downloadEncodedMesh" para fazer o download do arquivo Draco codificado, que vai chamar a função "decodeMesh" para decodificar a malha Draco codificada.
// Create the Draco decoder module.
createDracoDecoderModule();
</script>
</head>
<body>
</body>
</html>
- Salve o arquivo como "DracoDecode.html".
- Inicie o servidor da Web Python. No terminal, digite:
python -m SimpleHTTPServer
- Abra localhost:8000/DracoDecode.html no Chrome. Isso vai mostrar uma caixa de mensagem de alerta com o número de pontos (Num points = 34834) que foram decodificados do modelo.
6. Renderizar um arquivo Draco com three.js
Agora que sabemos como decodificar um arquivo Draco usando WASM, vamos usar um visualizador 3D da Web conhecido: o three.js. Como no exemplo anterior, vamos começar copiando e colando as seções de código a seguir no editor de texto.
- Comece com um arquivo HTML básico
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco three.js Render</title>
- Adicione código para carregar o three.js e o carregador 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>
- Configure o caminho do decodificador 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/');
- Adicione o código de renderização do 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 );
}
- Adicione o código de carregamento e decodificação do 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 );
} );
}
- Adicione o código para carregar o arquivo.
window.onload = function() {
initThreejs();
animate();
loadDracoMesh('bunny.drc');
}
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
- Salve o arquivo como "DracoRender.html"
- Se necessário, reinicie o servidor da Web.
python -m SimpleHTTPServer
- Abra localhost:8000/DracoRender.html no Chrome. Agora você vai ver o arquivo Draco renderizado no navegador.
7. Teste diferentes parâmetros de codificação
O codificador Draco permite muitos parâmetros diferentes que afetam o tamanho do arquivo compactado e a qualidade visual do código. Execute os próximos comandos na linha de comando e confira os resultados.
- O comando a seguir quantiza as posições do modelo usando 12 bits (o padrão é 11).
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12
- Observe o tamanho do out12.drc em comparação com o arquivo bunny.drc na seção anterior. Usar mais bits de quantização pode aumentar o tamanho do arquivo compactado.
3.O comando a seguir quantiza as posições do modelo usando 6 bits.
./draco_encoder -i ../testdata/bun_zipper.ply -o out6.drc -qp 6
- Observe o tamanho do out6.drc em comparação com o arquivo bunny.drc na seção anterior. Usar menos bits de quantização pode reduzir o tamanho do arquivo compactado.
- Os parâmetros a seguir afetam os níveis de compactação do modelo. Usando a flag "cl", você pode ajustar a compactação de 1 (menor taxa de compactação) a 10 (maior).
./draco_encoder -i ../testdata/bun_zipper.ply -o outLow.drc -cl 1
./draco_encoder -i ../testdata/bun_zipper.ply -o outHigh.drc -cl 10
Observe a saída do codificador Draco. É possível notar que há uma troca entre o tempo necessário para compactar nos níveis mais altos de compactação e a economia em bits. O parâmetro correto para seu aplicativo depende dos requisitos de tempo e tamanho no momento da codificação.
8. Parabéns
Você concluiu o codelab de compressão de malha do Draco e conheceu vários recursos importantes dele.
Esperamos que tenha ficado claro como o Draco pode ajudar a reduzir o tamanho dos seus recursos 3D e torná-los mais eficientes para transmissão na Web. Saiba mais sobre o Draco e baixe a biblioteca mais recente no GitHub.