Three.js/기초튼튼

three.js 3D 모델을 glTF 파일로 다운로드하기(.glb or .gltf)

carrotweb 2023. 10. 29. 19:44
728x90
반응형

이어서 추출된 glTF 정보를 .glb 파일(바이너리) 또는 .gltf 파일(JSON)로 다운로드하여 저장할 수 있게 헤보겠습니다.

 

glTF 정보를 스크립트에서 다운로드하기 위해서는 URL.createObjectURL() 메서드를 사용하면 됩니다.

 

URL.createObjectURL() 메서드에 대한 영문 설명은 다음과 같습니다.

The URL.createObjectURL() static method creates a string containing a URL representing the object given in the parameter.

번역해 보면 URL.createObjectURL() 정적 메서드는 파라미터로 전달받은 객체를 가리키는 URL이 포함된 문자열을 생성합니다.

URL.createObjectURL(object)
  • object: File, Blob, MediaSource 객체입니다.

 

즉, File 객체 또는 Blob 객체 또는 MediaSource 객체를 URL로 접근할 수 있게 아래와 같이 Blob URL를 생성하여 리턴하게 됩니다.

blob:http://localhost:5173/c95eb15c-3c2d-4ca1-b327-8e25a8bfe73e

 

그리고 URL.createObjectURL() 정적 메서드를 사용할 때마다 새로운 Blob URL를 생성되기 때문에 생성된 Blob URL은 URL.revokeObjectURL() 정적 메서드를 사용하여 해제해줘야 합니다.

 

그러나 생성된 Blob URL를 해제하지 않아도 웹 브라우저가 unload(다른 경로로 이동하거나 웹 브라우저가 종료될 때)가 되면 웹 브라우저가 자동으로 해제해 줍니다.

 

추가적으로 URL.createObjectURL()와 URL.revokeObjectURL() 정적 메서드로 blob URL를 생성하고 해제하는 방법은 W3C의 Creating and Revoking a blob URL를 참고하시기 바랍니다.

 

 

URL.createObjectURL() 정적 메서드로 Blob URL를 생성하기 위해서는 먼저 glTF 정보를 Blob 객체로 만들어야 합니다.

 

Blob(Binary Large Object, 비랍/블랍)은 대용량의 바이너리로 저장된 객체입니다.

new Blob(array, options)
  • array: ArrayBuffer[] 또는 TypedArray[] 또는 DataView[] 또는 USVString(UTF-8로 인코딩 된 string[]) 또는 다른 Blob 배열 객체이거나 객체 또는 여러 개의 타입이 혼합된 배열 객체입니다.
  • options: 데이터의 type과 endings을 설정하는 옵셥입니다.

options은 다음과 같이 설정할 수 있습니다.

  • type: 저장될 데이터의 MIME 타입입니다. 기본값 ""(빈 문자열)
  • endings(transparent, native): array 타입이 USVString(UTF-8로 인코딩 된 string[])일 때  개행 문자("\n")를 사용 중인 OS에 맞춰서 개행 문자를 변환할지(native) 아니면 변환하지 않을지(transparent) 선택합니다. 기본값 transparent

 

 

그럼 추출된 glTF 정보를 Blob(Binary Large Object, 비랍/블랍)으로 만들고 Blob URL를 생성하여 파일로 다운로드해 보겠습니다.

 

1. 추출된 glTF 정보를 파라미터로 받아 바이너리 형식과 JSON 형식의  Blob 객체를 만드는 함수를 만듭니다.

 

바이너리 형식으로 변환하기 위해서 options의 type를 "application/octet-stream"으로 설정합니다.

// 바이너리 형식으로 변환
function downloadBinary(buffer) {
    const blob = new Blob([buffer], {type: 'application/octet-stream'});
    console.log("Blob:", blob);
}

 

JSON 형식으로 변환하기 위해서 추출된 glTF 정보를 JSON 문자열로 변환하고 options의 type를 "application/json"으로 설정합니다.

// JSON 형식으로 변환
function downloadJSON(buffer) {
    const blob = new Blob([JSON.stringify(buffer)], {type: 'application/json'});
    console.log("Blob:", blob);
}

 

2. 기존 ExportglTF() 함수에 downloadBinary()와 downloadJSON()를 추가합니다. glTF 정보가 ArrayBuffer[]이면 downloadBinary() 함수를 호출하고 그렇지 않으면 downloadJSON() 함수를 호출하게 합니다.

function ExportglTF() {
    // GLTF익스포트 생성
    const exporter = new GLTFExporter();

    // GLTF익스포트 옵션 - 바이너리 형식으로 추출
    const options = {
        binary: false
    };

    exporter.parse(
        box2,
        function (gltf) {
            if (gltf instanceof ArrayBuffer) {
                console.log("export gltf:", gltf);
                downloadBinary(gltf);
            } else {
                console.log("export gltf:", gltf);
                downloadJSON(gltf);
            }
        },
        function (error) {
            console.error("exporter error:", error);
        },
        options
    );
}

 

Controls에서 "Export" 버튼을 클릭하면 콘솔에 Blob 객체 정보가 출력됩니다.

 

만약 glTF 익스포트 옵션의 binry가 flase이면 JSON 형식으로 다음과 같이 콘솔에 출력됩니다.

// GLTF익스포트 옵션 - JSON 형식으로 추출
const options = {
    binary: false
};

 

 

3. 파일로 다운로드하기 위해서 Blob 객체를 파라미터로 받는 다운로드 함수를 만듭니다.

 

다운로드 URL를 생성하기 위해서 URL.createObjectURL() 메서드를 사용합니다.

// 다운로드
function download(blob) {
    const blobURL = URL.createObjectURL(blob);
    console.log(blobURL);
}

 

기존 downloadBinary()와 downloadJSON()에 다운로드 함수를 추가합니다.

// 바이너리 형식으로 변환
function downloadBinary(buffer) {
    const blob = new Blob([buffer], {type: 'application/octet-stream'});
    console.log("Blob:", blob);
    download(blob);
}

// JSON 형식으로 변환
function downloadJSON(buffer) {
    const blob = new Blob([JSON.stringify(buffer)], {type: 'application/json'});
    console.log("Blob:", blob);
    download(blob);
}

 

Controls에서 "Export" 버튼을 클릭하면 콘솔에 Blob URL이 출력됩니다.

blob:http://localhost:5173/b8c1b2f5-f4ee-4a9d-b286-7aed8af4dd47

 

만약 glTF 익스포트 옵션의 binry가 flase이면 JSON 형식으로 다음과 같이 Blob URL이 콘솔에 출력됩니다.

// GLTF익스포트 옵션 - JSON 형식으로 추출
const options = {
    binary: false
};

blob:http://localhost:5173/b86e8950-8d45-4b8c-8822-16703dc678c2

 

4. 생성된 Blob URL로 다운로드하기 위해서 A 태그를 생성하고 href 속성 값으로 Blob URL를 설정합니다. 그리고 생성된 A 태그를 페이지에 추가하고 click() 메서드로 A 태그를 클릭하여 다운로드하게 합니다. 다운로드 후 생성된 Blob URL를 해제하고 페이지에 추가된 A 태그를 삭제합니다.

// 다운로드
function download(blob) {
    const blobURL = URL.createObjectURL(blob);
    console.log(blobURL);
    // 다운로드를 하기위해 Blob URL로 A 태그 생성
    const link = document.createElement('a');
    link.href = blobURL;
    // 다운로드 파일 명
    link.download = "test.glb";
    // A 태그 추가
    document.body.appendChild(link);
    // A 태그를 클릭하여 다운로드
    link.click();
    // 다운로드 후 Blob URL 해제
    URL.revokeObjectURL(blobURL);
    // A 태그 삭제
    document.body.removeChild(link);
}

 

Controls에서 "Export" 버튼을 클릭하면 콘솔에 glTF 파일이 다운로드됩니다.

 

그럼 glTF 익스포트 옵션과 다운로드되는 파일 명을 변경할 수 있게 처리해 보겠습니다.

 

5. Controls에서 glTF 익스포트 옵션을 변경하고 다운로드 파일명을 변경할 수 있게 객체(exporter1)에 추가합니다.

const exporter1 = {
    ExportglTFFileName : 'test.glb',
    ExportglTFFilebinary : true,
    ExportglTFFunction : ExportglTF
};

 

그리고 glTF 익스포트 옵션의 binary를  exporter1의 ExportglTFFilebinary로 설정합니다.

function ExportglTF() {
    // GLTF익스포트 생성
    const exporter = new GLTFExporter();

    // GLTF익스포트 옵션 - 바이너리/JSON 형식으로 추출
    const options = {
        binary: exporter1.ExportglTFFilebinary
    };

    exporter.parse(
        box2,
        function (gltf) {
            if (gltf instanceof ArrayBuffer) {
                console.log("export gltf:", gltf);
                downloadBinary(gltf);
            } else {
                console.log("export gltf:", gltf);
                downloadJSON(gltf);
            }
        },
        function (error) {
            console.error("exporter error:", error);
        },
        options
    );
}

 

그리고 다운로드 함수에서 다운로드 파일명을 exporter1의 ExportglTFFileName으로 설정합니다.

// 다운로드
function download(blob) {
    const blobURL = URL.createObjectURL(blob);
    console.log(blobURL);
    // 다운로드를 하기위해 Blob URL로 A 태그 생성
    const link = document.createElement('a');
    link.href = blobURL;
    // 다운로드 파일 명
    link.download = exporter1.ExportglTFFileName;
    // A 태그 추가
    document.body.appendChild(link);
    // A 태그를 클릭하여 다운로드
    link.click();
    // 다운로드 후 Blob URL 해제
    URL.revokeObjectURL(blobURL);
    // A 태그 삭제
    document.body.removeChild(link);
}

 

그리고 Controls에 추가합니다.

folder2.add(exporter1, 'ExportglTFFileName');
folder2.add(exporter1, 'ExportglTFFilebinary');
folder2.add(exporter1, 'ExportglTFFunction').name('Export');

 

 

그리고 Controls에 ExportglTFFileName과 ExportglTFFilebinary가 추가됩니다.

 

6. ExportglTFFilebinary가 체크되면 ExportglTFFileName의 확장자를 ".glb"로 변경시키고 ExportglTFFilebinary가 체크되지 않으면 ExportglTFFileName의 확장자를 ".gltf"로 변경되게 함수를 만듭니다.

// 파일 저장 형식에 따른 파일 확장자 변경
function updatesglTFFileName() {
    let fileName = exporter1.ExportglTFFileName;
    const pos = fileName.lastIndexOf('.');
    if (pos > 0) {
        if (exporter1.ExportglTFFilebinary) {
            exporter1.ExportglTFFileName = fileName.substring(0, pos) + ".glb";
        } else {
            exporter1.ExportglTFFileName = fileName.substring(0, pos) + ".gltf";
        }
    }
}

 

확장자를 변경하는 함수를 ExportglTFFilebinary에서 onChange()로 처리되게 추가하고 Controls에 있는 ExportglTFFileName이 변경된 확장로 변경되도록 listen() 함수를 추가합니다.

folder2.add(exporter1, 'ExportglTFFileName').listen();
folder2.add(exporter1, 'ExportglTFFilebinary').onChange(updatesglTFFileName);
folder2.add(exporter1, 'ExportglTFFunction').name('Export');

 

Controls에서 ExportglTFFilebinary를 선택할 때마다 ExportglTFFileName의 확장자가 변경되는 것을 확인할 수 있습니다.

 

그리고 Controls에서 "Export" 버튼을 클릭하면 변경된 확장자로 다운로드되는 것을 확인할 수 있습니다.

728x90
반응형