1. Обзор
3D-графика является фундаментальной частью многих приложений, включая игры, дизайн и визуализацию данных. По мере совершенствования графических процессоров и инструментов для создания контента, более крупные и сложные 3D-модели станут обычным явлением и будут способствовать развитию новых приложений в области иммерсивной виртуальной реальности (VR) и дополненной реальности (AR). Из-за возросшей сложности моделей требования к хранению данных и пропускной способности должны соответствовать стремительному росту объёма 3D-данных.
Благодаря Draco, приложения, использующие 3D-графику, могут быть значительно меньше по размеру без ущерба для качества изображения. Для пользователей это означает, что приложения теперь можно загружать быстрее, 3D-графика в браузере загружается быстрее, а сцены VR и AR теперь могут передаваться с гораздо меньшей пропускной способностью, быстро отображаться и выглядеть фантастически.
Кто такой Драко?
Draco — это библиотека для сжатия и распаковки трехмерных геометрических сеток и облаков точек . Она предназначена для улучшения хранения и передачи трехмерной графики.
Draco был разработан и создан для обеспечения эффективности и скорости сжатия. Код поддерживает сжатие точек, информации о связности, текстурных координат, информации о цвете, нормалей и любых других общих атрибутов, связанных с геометрией. Draco выпускается в виде исходного кода на C++, который можно использовать для сжатия 3D-графики, а также в виде декодеров на C++ и Javascript для закодированных данных.
Что вы узнаете
- Как использовать Draco для сжатия 3D-модели
- Как использовать различные модели сжатия и как они влияют на качество и размер модели.
- Как просмотреть 3D-модель в интернете
Что вам понадобится
- Последняя версия Chrome
- Пример кода
- Текстовый редактор
- Python
- cmake
2. Настройка
Клонируйте репозиторий Github, используя следующую команду в командной строке:
git clone https://github.com/google/draco
Перейдите в корневой каталог Draco.
cd draco
3. Создайте кодировщик.
Для начала, чтобы разобраться с кодированием и декодированием Draco, давайте сначала разработаем приложения.
Build Encoder
- Запустите cmake из каталога, где вы хотите сгенерировать файлы сборки, и передайте ему путь к вашему репозиторию Draco.
mkdir build
cd build
cmake ../
make
4. Закодируйте свой первый 3D-объект.
draco_encoder будет считывать на вход файлы OBJ или PLY и выдавать файлы, закодированные в формате Draco. Для тестирования мы включили модель кролика из Стэнфорда. Базовая командная строка выглядит следующим образом:
./draco_encoder -i ../testdata/bun_zipper.ply -o bunny.drc
Теперь вы можете посмотреть на размер выходного файла и сравнить его с размером исходного файла .ply. Сжатый файл должен быть значительно меньше исходного.
Примечание: размер сжатого файла может варьироваться в зависимости от параметров сжатия.
5. Расшифруйте файл Draco в браузере.
На этом этапе мы начнём с простой веб-страницы для расшифровки файлов Draco. Для начала скопируем и вставим следующие фрагменты кода в текстовый редактор.
- Начните с базового HTML-файла.
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco Decoder</title>
- Следующий фрагмент кода загрузит декодер Draco WASM.
<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>
- Далее добавьте эту функцию, которая создаст модуль декодера Draco. Создание модуля декодера происходит асинхронно, поэтому вам нужно дождаться вызова функции обратного вызова, прежде чем вы сможете использовать модуль.
<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);
}
- Добавьте функцию для декодирования сетки, закодированной в формате 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);
}
- Теперь, когда у нас есть функция декодирования Draco, добавим функцию для загрузки закодированной сетки Draco. Функция 'downloadEncodedMesh' принимает в качестве параметра файл Draco для загрузки. В данном случае это будет файл 'bunny.drc' из предыдущего этапа.
// 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);
}
- Вызовите функцию 'createDracoDecoderModule' для создания модуля декодера Draco, который вызовет функцию 'downloadEncodedMesh' для загрузки закодированного файла Draco, а та, в свою очередь, вызовет функцию 'decodeMesh' для декодирования закодированной сетки Draco.
// Create the Draco decoder module.
createDracoDecoderModule();
</script>
</head>
<body>
</body>
</html>
- Сохраните этот файл как "DracoDecode.html"
- Запустите веб-сервер на Python. В терминале введите:
python -m SimpleHTTPServer
- Откройте в Chrome страницу localhost:8000/DracoDecode.html . Должно отобразиться всплывающее сообщение с указанием количества точек (Num points = 34834), декодированных из модели.
6. Отобразите файл Draco с помощью three.js
Теперь, когда мы знаем, как декодировать файл Draco с помощью WASM, мы воспользуемся популярным веб-просмотрщиком 3D-моделей — three.js. Как и в предыдущем примере, начнем с копирования и вставки следующих фрагментов кода в текстовый редактор.
- Начните с базового HTML-файла.
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco three.js Render</title>
- Добавьте код для загрузки three.js и загрузчика 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>
- Настройте путь декодера 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/');
- Добавьте код рендеринга в файл 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 );
}
- Добавить код загрузки и декодирования 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 );
} );
}
- Добавьте код для загрузки файла.
window.onload = function() {
initThreejs();
animate();
loadDracoMesh('bunny.drc');
}
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
- Сохраните этот файл как "DracoRender.html"
- При необходимости перезапустите веб-сервер.
python -m SimpleHTTPServer
- Откройте файл localhost:8000/DracoRender.html в Chrome. Теперь вы должны увидеть свой файл Draco, отображаемый в браузере.
7. Попробуйте разные параметры кодирования.
Кодировщик Draco позволяет задавать множество различных параметров, влияющих на размер сжатого файла и визуальное качество кода. Попробуйте выполнить следующие несколько команд в командной строке и посмотрите на результаты.
- Следующая команда квантует позиции модели, используя 12 (по умолчанию 11) бит.
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12
- Обратите внимание на размер файла out12.drc по сравнению с файлом bunny.drc, упомянутым в предыдущем разделе. Использование большего количества битов квантования может увеличить размер сжатого файла.
3. Следующая команда квантует позиции модели, используя 6 бит.
./draco_encoder -i ../testdata/bun_zipper.ply -o out6.drc -qp 6
- Обратите внимание на размер файла out6.drc по сравнению с файлом bunny.drc из предыдущего раздела. Использование меньшего количества битов квантования может уменьшить размер сжатого файла.
- Следующие параметры влияют на уровень сжатия модели. Используя флаг cl, вы можете настроить степень сжатия от 1 (минимальный коэффициент сжатия) до 10 (максимальный).
./draco_encoder -i ../testdata/bun_zipper.ply -o outLow.drc -cl 1
./draco_encoder -i ../testdata/bun_zipper.ply -o outHigh.drc -cl 10
Обратите внимание на выходные данные кодировщика Draco. Вы можете видеть, что существует компромисс между временем, необходимым для сжатия на самых высоких уровнях сжатия, и экономией битов. Правильный параметр для вашего приложения будет зависеть от требований к времени и размеру во время кодирования.
8. Поздравляем!
Вы успешно завершили лабораторную работу по коду сжатия сетки в Draco и изучили множество ключевых функций Draco!
Надеюсь, вам стало понятно, как Draco может помочь уменьшить размер ваших 3D-моделей и повысить эффективность их передачи через Интернет. Вы можете узнать больше о Draco и получить последнюю версию библиотеки на GitHub .