순서
영상 촬영 후 영상을 각 프레임 단위로 스크린샷 (이미지 생성)
이미지를 활용하여 3D 모델 생성 (USDZ 파일)
USDZ파일 > GLB 파일 변환
GLB 파일 웹에서 확인
환경
운영체제 : MacOS (M1)
서버 : NodeJS
클라이언트 : React (Web)
영상 촬영 후 영상을 각 프레임 단위로 스크린샷 (이미지 생성)
사전에 영상 준비 (.mp4 또는 .avi 또는 .mov 파일)
모듈 준비 (fluent-ffmpeg, ffmpeg-static)
yarn add fluent-ffmpeg ffmpeg-static
코드 작성
import * as ffmpeg from 'fluent-ffmpeg';
import * as ffmpegStatic from 'ffmpeg-static';
if (!ffmpegStatic) throw new Error('ffmpeg-static 경로를 찾을 수 없습니다.');
ffmpeg.setFfmpegPath(ffmpegStatic as unknown as string);
const videoToPicture = async (
inputVideoPath: string,
outputFolderName: string,
callback: () => void | Promise<void>,
): Promise<void> => {
ffmpeg(inputVideoPath)
.on('error', () => {})
.on('end', () => callback())
.screenshots({
count: 100,
folder: outputFolderName,
filename: 'input-%03d.png',
});
};
videoToPicture(영상경로, 이미지저장경로, () => {
// callback function
});
이미지를 활용하여 3D 모델 생성 (USDZ 파일)
Apple Open Source 사용 (Creating a Photogrammetry Command-Line App)
Download 후 XCode에서 Archive 후 실행파일 생성
CLI 명령어를 사용하여 코드 작성
이미지 > 3D 모델 (USDZ 파일)
import { execSync } from 'child_process';
// ~/HelloPhotogrammetry <이미지경로> <결과저장경로>/output.usdz -d raw -o sequential -f normal
let command = __dirname + '/../../../HelloPhotogrammetry "';
command += inputFolderPath + '" "';
command += outputFilePath + '.usdz" ';
command += '-d raw -o sequential -f normal';
execSync(command, { stdio: 'inherit' });
3D 모델 (USDZ 파일) > 3D 모델 (GLB 파일) 의 파일 변환 프로그램 설치 (Blender)
Download 후 터미널에서 설치 확인 테스트
blender --version
# Blender 4.4.1
# build date: 2025-04-15
# build time: 01:30:48
# ...
파일 변환 스크립트 작성
import bpy
import sys
# Node.js에서 전달된 인자 받아오기
input_path = sys.argv[-2]
output_path = sys.argv[-1]
# 초기화
bpy.ops.wm.read_homefile(use_empty=True)
# USDZ 불러오기
bpy.ops.wm.usd_import(filepath=input_path)
# glb로 내보내기
bpy.ops.export_scene.gltf(
filepath=output_path,
export_format='GLB',
export_apply=True
)
CLI 명령어를 사용하여 코드 작성
3D 모델 (USDZ 파일) > 3D 모델 (GLB 파일)
import { execSync } from 'child_process';
// ~/blender --background --python convert_usdz_to_glb.py -- input.usdz output.glb
const inputPath = outputFilePath + '.usdz';
const outputPath = outputFilePath + '.glb';
const blenderScript = 'convert_usdz_to_glb.py';
let command = 'blender --background --python ';
command += blenderScript + ' -- ' + inputPath + ' ' + outputPath;
execSync(command, { stdio: 'inherit' });
GLB 파일 웹에서 확인
모듈 준비
yarn add @google/model-viewer
코드 작성
import "@google/model-viewer";
interface Props {
src: string;
iosSrc: string;
poster: string;
}
export default ({ src, iosSrc, poster }: Props) => {
return (
<model-viewer
src={src}
ios-src={iosSrc}
poster={poster}
alt="3D 모델 미리보기"
auto-rotate
camera-controls
ar
ar-modes="webxr scene-viewer quick-look"
touch-action="pan-y"
intensity="1"
style={{ width: "100%", height: "100%" }}
/>
);
};