BabylonJS 20회차 : 에셋 관리 전략(폴더/네이밍/버전)
목표: 프로젝트가 커져도 관리 가능한 구조 만들기
핵심 개념: assets/, scenes/, materials/, prefabs 개념
실습: 기본 템플릿 구조 확정
산출물: “내 Babylon 프로젝트 템플릿 레포”
요약
초반에는 파일이 몇 개 없어서 폴더 규칙이 없어도 잘 굴러갑니다. 하지만 모델(GLB), 텍스처, 머티리얼, 씬이 늘어나면 “어디에 뭐가 있는지”와 “어떤 게 최신인지”가 바로 생산성을 갉아먹습니다. 이번 회차에서는 폴더 구조, 네이밍 규칙, 버전 관리를 미리 고정하고, 이를 그대로 복사해 쓸 수 있는 “Babylon 프로젝트 템플릿 레포” 형태로 정리합니다.
목차
- 1) 핵심 포인트(오늘 고정할 규칙)
- 2) 폴더 전략: assets/, scenes/, materials/, prefabs
- 3) 네이밍 규칙: 파일명만 봐도 용도를 알게 만들기
- 4) 버전 전략: “최신/호환/변경”을 추적하는 방법
- 5) 실습: 기본 템플릿 구조 확정(레포 뼈대)
- 6) 운영 체크리스트
- 7) 추가로 생각해볼 점
- 8) 블로그 최적화 정보
1) 핵심 포인트(오늘 고정할 규칙)
- “소스”와 “런타임”을 분리: Blender 원본(.blend)과 엔진에서 로딩하는 GLB/텍스처를 같은 폴더에 섞지 않습니다.
- 폴더 역할을 고정:
assets/(리소스),materials/(머티리얼 팩토리),prefabs/(조립 단위),scenes/(씬 엔트리)로 나눕니다. - 파일명 규칙은 “보는 즉시” 판단 가능해야: 타입/용도/버전이 드러나게 하고, 케이스는 단일 규칙(kebab-case 등)으로 통일합니다.
- 버전은 2트랙으로 관리: 코드(semver)와 에셋(리비전/리비전+체인지로그)을 분리해 생각합니다.
- 최종 목표는 템플릿화: 매 프로젝트마다 고민하지 않고 “복사 → 시작”이 되도록 레포 구조를 확정합니다.
2) 폴더 전략: assets/, scenes/, materials/, prefabs
폴더는 “파일을 담는 상자”가 아니라 “팀/미래의 내가 사고하는 방식”입니다. 따라서 폴더 이름은 기능과 책임이 분명해야 합니다. 아래는 초보자에게도 확장성이 좋은 기본 구조입니다.
| 폴더 | 역할 | 예시 파일 | 운영 규칙 |
|---|---|---|---|
public/assets/ |
런타임 로딩 대상(GLB/텍스처/환경맵) | models/, textures/, env/ |
여기 있는 파일은 “브라우저가 직접 접근”하는 정적 리소스만 둡니다. |
source-assets/ |
원본 제작물(Blender/PSD 등) | .blend, .psd |
배포 대상이 아니며, 내보내기(export) 결과만 public/assets로 이동합니다. |
src/scenes/ |
씬 엔트리(장면 시작점) | MainScene.ts, ViewerScene.ts |
“게임/뷰어 흐름”의 진입점만 두고, 조립 로직은 prefabs로 내려보냅니다. |
src/materials/ |
머티리얼 팩토리(재사용 단위) | createCarPaint.ts |
“재사용” 가능한 머티리얼만 둡니다(씬에서 즉석 생성 금지 규칙을 추천). |
src/prefabs/ |
프리팹(조립 단위: 모델+머티리얼+애니메이션) | CarPrefab.ts, RobotArmPrefab.ts |
엔진에서 “조립 후 반환”하는 단위를 표준화합니다(부모자식/피벗 포함). |
2-1) 왜 public/assets 아래로 모으나요?
- 브라우저에서 로딩하는 파일은 URL로 접근 가능한 정적 경로에 있어야 합니다.
- 빌드 도구(Vite/Webpack 등)에서도
public은 “그대로 복사”되는 영역으로 취급되는 경우가 많아 관리가 단순합니다. - “어디가 런타임 경로인지”가 명확해져, Import/SceneLoader 경로 문제를 줄일 수 있습니다.
2-2) assets 내부 세부 구조(권장)
에셋 폴더도 ‘성격’에 따라 하위 폴더를 고정하면 찾기 쉬워집니다.
public/
assets/
models/
vehicles/
characters/
props/
textures/
vehicles/
characters/
props/
shared/
env/
studio-hdr/
audio/
manifest/
초보자 단계에서는 models/와 textures/만 먼저 시작해도 충분합니다. 프로젝트가 커질 때 env/, audio/를 확장하면 됩니다.
3) 네이밍 규칙: 파일명만 봐도 용도를 알게 만들기
네이밍 규칙의 목표는 “검색/정렬/충돌 방지”입니다. 특히 GLB/텍스처는 파일 개수가 빠르게 늘어나기 때문에, 초반에 규칙을 잡지 않으면 금방 정리가 어려워집니다.
3-1) 기본 규칙(권장)
- kebab-case(소문자-하이픈) 통일: 운영체제/호스팅 환경 차이를 줄이고, URL에서도 안전합니다.
- 의미 단위로 구분:
[카테고리]-[이름]-[변형]-[버전]같은 패턴을 고정합니다. - 약어는 최소화: 팀원이 늘어날수록 약어는 해석 비용이 됩니다(orm, normal 같은 표준 약어만 예외).
| 종류 | 권장 패턴 | 예시 | 설명 |
|---|---|---|---|
| GLB 모델 | [name]-v###.glb |
car-sedan-v003.glb |
버전은 정렬을 위해 3자리 숫자 권장 |
| 텍스처(Base Color) | [name]__basecolor.png |
car-sedan__basecolor.png |
채널 의미가 명확해야 합니다 |
| 텍스처(Normal) | [name]__normal.png |
car-sedan__normal.png |
노멀은 포맷/색공간 관리가 중요합니다 |
| 텍스처(ORM) | [name]__orm.png |
car-sedan__orm.png |
Occlusion/Roughness/Metallic 패킹 텍스처 |
| Babylon 코드(씬) | PascalCase.ts |
ViewerScene.ts |
TS/JS는 관례적으로 PascalCase를 자주 사용합니다 |
3-2) “latest”는 파일명으로 관리하지 말고, 코드에서 선택
초보자 때 흔한 실수는 car-sedan-final.glb, car-sedan-final2.glb처럼 ‘감정’이 담긴 파일명이 쌓이는 것입니다. 대신 다음 방식 중 하나를 추천합니다.
- 버전 파일만 유지:
car-sedan-v001.glb,car-sedan-v002.glb처럼 숫자로만 쌓습니다. - manifest에서 “현재 사용 버전”을 지정: 코드는 manifest를 읽어 최신을 선택합니다.
- 릴리스 폴더 분리: 검증된 버전만
public/assets/models/release/로 복사합니다.
4) 버전 전략: “최신/호환/변경”을 추적하는 방법
버전 관리는 크게 두 종류입니다.
- 코드 버전: semver(예: 1.2.0)처럼 의미 있는 규칙으로 릴리스합니다.
- 에셋 버전: GLB/텍스처는 “작업 과정상” 자주 바뀌므로, 숫자 리비전(v001, v002)과 변경 기록이 중요합니다.
4-1) 에셋 버전이 필요한 순간
- 같은 이름의 모델이 스케일/피벗/UV가 달라져서, 엔진 쪽 코드(피벗/애니메이션)가 갑자기 깨집니다.
- 텍스처가 교체되어 색공간/노멀 방향 등이 달라져 렌더링이 달라집니다.
- 최적화(폴리곤 감소/텍스처 압축)로 파일이 바뀌었는데, 품질 이슈가 생겨 이전 버전으로 롤백이 필요합니다.
4-2) 추천: 에셋 매니페스트(manifest)로 “사용 중인 버전”을 고정
프로젝트가 커지면 “현재 씬이 어떤 GLB를 쓰는지”가 코드 곳곳에 하드코딩되기 쉽습니다. 이를 줄이려면 간단한 manifest를 두고, 씬/프리팹이 그 값을 참조하도록 만들면 안정적입니다.
{
"models": {
"car_sedan": {
"path": "/assets/models/vehicles/car-sedan-v003.glb",
"rev": 3,
"note": "pivot fixed, wheel hierarchy separated"
},
"robot_arm": {
"path": "/assets/models/props/robot-arm-v002.glb",
"rev": 2,
"note": "scale applied, materials updated"
}
},
"env": {
"studio_hdr": {
"path": "/assets/env/studio-hdr/studio-1k.env"
}
}
}
이 방식의 장점은 간단합니다. 파일 교체(버전 업) 시 수정 지점이 한 곳으로 모입니다. 또한 note를 남기면 “왜 바뀌었는지”도 함께 남습니다.
4-3) 변경 기록(Changelog) 최소 구성
- 에셋별로 note를 남기기: 위 manifest의
note처럼 “무엇이 바뀌었는지”를 1줄로 남깁니다. - 큰 변경은 별도 문서로: 예:
docs/assets-changelog.md에 주간 단위로 기록합니다. - 호환성 파손은 표시: 피벗/본 구조가 바뀌면 프리팹 코드가 바뀌어야 하므로, “Breaking” 표시를 권장합니다.
5) 실습: 기본 템플릿 구조 확정(레포 뼈대)
이제 “내 Babylon 프로젝트 템플릿 레포”를 목표로, 복사해서 바로 시작할 수 있는 구조를 확정합니다. 빌드 도구는 무엇이든 가능하지만, 여기서는 “폴더/규칙” 자체가 핵심이므로 도구에 종속되지 않는 형태로 제시합니다.
5-1) 템플릿 폴더 트리(최종안)
my-babylon-template/
public/
assets/
manifest/
assets-manifest.json
models/
vehicles/
characters/
props/
textures/
shared/
env/
source-assets/
blender/
textures/
src/
app/
bootstrap.ts
scenes/
MainScene.ts
ViewerScene.ts
prefabs/
CarPrefab.ts
materials/
createDefaultMaterial.ts
loaders/
assetRegistry.ts
docs/
export-checklist.md
naming-rules.md
.gitignore
README.md
5-2) prefabs는 “조립 단위”로 생각합니다
prefab은 게임엔진에서 흔히 “재사용 가능한 오브젝트 조립품”을 의미합니다. BabylonJS는 유니티처럼 프리팹 파일이 고정된 형태로 존재하는 것은 아니지만, 코드 레벨에서 프리팹 개념을 만들 수 있습니다.
- CarPrefab은 “차체 GLB 로딩 + 바퀴 피벗 연결 + 머티리얼 적용”을 한 번에 수행하고, 루트 노드를 반환합니다.
- 씬은 CarPrefab을 호출해 배치만 합니다(조립 로직이 씬으로 새지 않게).
- 이렇게 분리하면 씬이 많아져도 구조가 유지됩니다.
5-3) 실습 코드: assetRegistry(매니페스트 기반 경로 관리)
아래 코드는 “경로 하드코딩”을 줄이는 최소 골격입니다. 초보자 단계에서는 이 정도만 있어도 폴더 구조의 장점이 바로 체감됩니다.
// src/loaders/assetRegistry.ts
export type AssetManifest = {
models: Record<string, { path: string; rev?: number; note?: string }>;
env?: Record<string, { path: string }>;
};
let cached: AssetManifest | null = null;
export async function loadManifest(url = "/assets/manifest/assets-manifest.json") {
if (cached) return cached;
const res = await fetch(url);
if (!res.ok) throw new Error("Failed to load manifest: " + res.status);
cached = await res.json();
return cached;
}
export async function getModelPath(modelId: string) {
const manifest = await loadManifest();
const item = manifest.models[modelId];
if (!item) throw new Error("Unknown modelId: " + modelId);
return item.path;
}
위 코드의 포인트는 단순합니다. 씬/프리팹 어디에서도 /assets/models/...를 직접 쓰지 않고, modelId로만 접근하게 만드는 것입니다. 프로젝트가 커질수록 이 차이가 누적됩니다.
5-4) 템플릿 README에 넣을 “규칙 요약” 예시
# My Babylon Template Rules
* Runtime assets live in: public/assets/
* Source files live in: source-assets/ (never loaded by the app)
* Model files: kebab-case + -v###.glb (e.g. car-sedan-v003.glb)
* Textures: [name]__basecolor / __normal / __orm
* Don't hardcode paths in scenes/prefabs. Use assets-manifest.json + assetRegistry.
* Prefabs assemble (load + hierarchy + materials) and return a root node.
6) 운영 체크리스트
템플릿이 있어도, 운영 중 규칙이 깨지면 다시 혼란이 생깁니다. 아래 체크리스트는 “늘어나는 프로젝트”를 안정적으로 유지하기 위한 최소 점검 항목입니다.
| 구분 | 체크 항목 | 권장 기준 | 놓치면 생기는 일 |
|---|---|---|---|
| 폴더 | 런타임/소스 분리 | public/assets vs source-assets |
경로 혼란, 배포 파일 누락/과포함 |
| 네이밍 | kebab-case 통일 | 소문자+하이픈, 의미 있는 접미사 | OS/호스팅에 따라 경로가 깨짐 |
| 버전 | 모델 리비전 관리 | -v### + 변경 노트 |
최신 추적 불가, 롤백 어려움 |
| 로딩 | 경로 하드코딩 금지 | manifest 기반 로딩 | 씬마다 수정, 버그 발생 확률 증가 |
| 조립 | prefab로 조립 로직 격리 | 씬은 배치만 담당 | 씬이 커지고 복잡해져 유지보수 어려움 |
7) 추가로 생각해볼 점
- 압축/최적화 파이프라인: 프로젝트가 커지면 GLB 최적화(메시 압축, 텍스처 압축, 환경맵 크기) 단계가 필요해집니다. 이때도 “source-assets → public/assets” 흐름을 유지하면 작업이 안전합니다.
- 에셋 ID 설계: manifest의 키(
car_sedan같은 modelId)는 “프로젝트 내부 API”가 됩니다. 한 번 정한 ID는 가급적 바꾸지 않는 규칙이 장기적으로 유리합니다. - 팀 합류를 대비한 문서:
docs/naming-rules.md,docs/export-checklist.md같은 문서는 초보자에게 특히 도움이 됩니다. 규칙이 글로 남아 있으면 품질 편차가 줄어듭니다. - 프리팹 테스트: prefabs가 늘어나면 “프리팹만 단독으로 로딩해보는 ViewerScene”이 품질 게이트 역할을 합니다(이전 회차의 로딩 UI 뷰어와 연결하면 효과가 큽니다).
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

0 댓글