1. 개요
3D 그래픽은 게임, 디자인, 데이터 시각화 등 다양한 애플리케이션의 기본 요소입니다. 그래픽 프로세서와 제작 도구가 계속 개선됨에 따라 더 크고 복잡한 3D 모델이 일반화되어 몰입형 가상 현실 (VR)과 증강 현실 (AR)의 새로운 애플리케이션을 지원할 것입니다. 모델 복잡성이 증가함에 따라 스토리지 및 대역폭 요구사항이 3D 데이터의 폭발적인 증가에 발맞춰 증가할 수밖에 없습니다.
Draco를 사용하면 3D 그래픽을 사용하는 애플리케이션의 시각적 충실도를 저하시키지 않으면서도 크기를 크게 줄일 수 있습니다. 사용자에게는 앱을 더 빠르게 다운로드하고, 브라우저의 3D 그래픽을 더 빠르게 로드하고, VR 및 AR 장면을 이제 일부 대역폭으로 전송하여 빠르게 렌더링하고 멋지게 표시할 수 있다는 의미입니다.
Draco란 무엇인가요?
Draco는 3D 기하학적 메시와 포인트 클라우드를 압축하고 압축 해제하는 라이브러리입니다. 3D 그래픽의 저장 및 전송을 개선하기 위한 것입니다.
Draco는 압축 효율성과 속도를 위해 설계되고 빌드되었습니다. 이 코드는 점, 연결 정보, 텍스처 좌표, 색상 정보, 법선, 지오메트리와 연결된 기타 일반 속성의 압축을 지원합니다. Draco는 3D 그래픽을 압축하는 데 사용할 수 있는 C++ 소스 코드와 인코딩된 데이터용 C++ 및 JavaScript 디코더로 출시됩니다.
학습할 내용
- Draco를 사용하여 3D 모델을 압축하는 방법
- 다양한 압축 모델을 사용하는 방법과 모델 품질 및 크기에 미치는 영향
- 웹에서 3D 모델을 보는 방법
필요한 항목
2. 설정
다음 명령줄을 사용하여 GitHub 저장소를 클론합니다.
git clone https://github.com/google/draco
Draco 루트 디렉터리로 이동합니다.
cd draco
3. 인코더 빌드
Draco 인코딩 및 디코딩을 시작하려면 먼저 앱을 빌드하세요.
인코더 빌드
- 빌드 파일을 생성할 디렉터리에서 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. three.js로 Draco 파일 렌더링
이제 WASM을 사용하여 Draco 파일을 디코딩하는 방법을 알았으므로 널리 사용되는 웹 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
- Chrome에서 localhost:8000/DracoRender.html을 엽니다. 이제 브라우저에 Draco 파일이 렌더링되어 표시됩니다.
7. 다른 인코딩 매개변수 사용해 보기
Draco 인코더는 압축된 파일의 크기와 코드의 시각적 품질에 영향을 미치는 다양한 매개변수를 허용합니다. 명령줄에서 다음 명령어를 실행하고 결과를 확인해 보세요.
- 다음 명령어는 12비트 (기본값은 11)를 사용하여 모델의 위치를 양자화합니다.
./draco_encoder -i ../testdata/bun_zipper.ply -o out12.drc -qp 12
- 이전 섹션의 bunny.drc 파일과 비교하여 out12.drc의 크기를 확인합니다. 양자화 비트를 많이 사용하면 압축된 파일의 크기가 커질 수 있습니다.
3.다음 명령어는 6비트를 사용하여 모델의 위치를 양자화합니다.
./draco_encoder -i ../testdata/bun_zipper.ply -o out6.drc -qp 6
- 이전 섹션의 bunny.drc 파일과 비교하여 out6.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 메시 압축 Codelab을 완료하고 Draco의 여러 주요 기능을 살펴봤습니다.
Draco를 사용하면 3D 애셋을 더 작게 만들고 웹을 통해 더 효율적으로 전송할 수 있다는 점을 이해하셨기를 바랍니다. Draco에 대해 자세히 알아보고 github에서 최신 라이브러리를 다운로드할 수 있습니다.