1. 개요
3D 그래픽은 게임, 디자인 및 데이터 시각화를 포함하여 많은 애플리케이션의 기본적인 부분입니다. 그래픽 프로세서와 제작 도구가 계속해서 개선됨에 따라 더 크고 복잡한 3D 모델이 보편화되고 몰입형 가상 현실 (VR) 및 증강 현실 (AR)에서 새로운 응용 분야를 발전시키는 데 도움이 될 것입니다. 모델의 복잡성이 증가하면서 저장용량 및 대역폭 요구사항이 폭발적으로 증가하는 3D 데이터를 따라잡을 수밖에 없게 되었습니다.
Draco를 사용하면 3D 그래픽을 사용하는 애플리케이션을 시각적 충실도의 저하 없이 상당히 줄일 수 있습니다. 사용자의 입장에서는 이제 앱을 더 빠르게 다운로드하고, 브라우저의 3D 그래픽을 더 빠르게 로드할 수 있으며, VR 및 AR 장면을 대역폭의 일부분으로도 전송할 수 있게 되었고 속도가 빠르고 멋지게 표현될 수 있게 되었습니다.
드레이코란 무엇인가요?
Draco는 3D 기하학적 메시와 점 구름을 압축하고 압축 해제하기 위한 라이브러리입니다. 3D 그래픽의 저장 및 전송을 개선하기 위한 것입니다.
Draco는 압축 효율성과 속도를 고려하여 설계 및 빌드되었습니다. 이 코드는 압축 지점, 연결 정보, 텍스처 좌표, 색상 정보, 노멀 및 도형과 관련된 기타 일반 속성을 지원합니다. Draco는 C++ 소스 코드로 출시되어 3D 그래픽은 물론 인코딩된 데이터를 위한 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로 인코딩된 파일을 출력합니다. 테스트를 위해 Stanford의 Bunny 메시를 포함했습니다. 기본 명령줄은 다음과 같습니다.
./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로 인코딩된 메시를 다운로드하는 함수를 추가합니다. 'downloadEncodingMesh' 함수는 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’ 함수를 사용하여 'downloadEncodedMesh'를 호출하는 Draco 디코더 모듈을 생성합니다. 함수를 사용하여 'decodeMesh'를 호출하는 인코딩된 Draco 파일을 다운로드합니다. 함수를 사용하여 인코딩된 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. third.js를 사용하여 Draco 파일 렌더링
이제 WASM을 사용하여 Draco 파일을 디코딩하는 방법을 알게 되었으므로 널리 사용되는 웹 3D 뷰어인 third.js를 사용해 보겠습니다. 이전 예에서와 같이 먼저 다음 코드 섹션을 복사하여 텍스트 편집기에 붙여넣습니다.
- 기본 HTML 파일로 시작
<!DOCTYPE html>
<html>
<head>
<title>Codelab - Draco three.js Render</title>
- third.js 및 Draco two.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/');
- 3.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 애셋을 더 작고 효율적으로 웹을 통해 전송하는 데 어떻게 도움이 되는지 알려주실 수 있기를 바랍니다. github에서 Draco에 관해 자세히 알아보고 최신 라이브러리를 확인하세요.