Blender 제품 영상은(는) 무엇을 하나요?
소리 없이도 이해되는, 45~75초 제품 영상을 위한 방법과 실제 동작하는 예제입니다. 사실적인 셋(잔디, 나무 문, 실제 하늘)이 하나의 시각적 은유를 전달합니다. 짧은 텍스트 오버레이는 화면만으로는 전달하기 어려운 내용을 말해줍니다. 영상의 끝은 평평한 컬러 블록 격자로 변하며, 해당 블록들이 뒤집히면서 헤드라인과 콜투액션을 철자합니다.
모든 것은 코드로 이루어집니다: 셋, 애니메이션, 합성. GUI는 전혀 열지 않습니다.
이 폴더의 구성
| 경로 | 설명 |
|---|---|
film.json | 팔레트, 타이밍이 포함된 오버레이 텍스트, 엔딩 라인. 먼저 수정하세요. |
scripts/blender/build.py | 셋: 헤어 입자 잔디가 있는 언덕, 문, 서리 낀 블록, 하늘, 헤이즈, 렌더 설정. |
scripts/blender/mascot.py | 예제 캐릭터: 울타리 기둥 위에 앉을 수 있을 만큼 작은 복셀 올빼미. |
scripts/blender/film.py | 샷, 카메라, 프레임별 애니메이션. plates 및 layers 렌더링. |
scripts/post/comp.py | 합성기: plates + layers, 2D 카메라 움직임, 텍스트, 그레이딩, 2D 블록 엔딩, ffmpeg 인코딩. |
assets/ | 두 개의 하늘 플레이트(황금빛, 흐림). 직접 교체하세요. |
examples/ | 이 파이프라인으로 제작된 영상의 프레임 예시. |
예제 영상은 "The Gate"입니다: 동일한 블록들이 열린 문을 통해 일정한 속도로 굴러 들어오다가, 크기가 다양해지고, 마침내 떼를 이룹니다. 문이 닫히고, 그 후 블록들은 통과되거나, 계산되거나, 멈춰집니다. 구조 참조용으로 사용하고, 제품에 맞는 은유로 교체하세요.
작업 흐름
다음 순서대로 진행하세요. 각 번호 단계에서 승인을 받은 후 다음 단계의 렌더링 시간을 투자하세요.
- 브리프(Brief). 각각 한 문장씩: 대상, 문제, 전환점, 약속, 콜투액션. 영상 길이(45~75초), 화면비율, 재생될 환경을 결정합니다. 음소거 재생을 가정합니다.
- 은유(Metaphor). 문제에 대한 하나의 물리적 그림과 제품에 대한 그 그림의 변화 하나를 고릅니다. 한 장소, 하나의 주요 소품, 한 종류의 움직이는 오브젝트. 설명이 필요하면 다시 고르세요.
- 비트 시트(Beat sheet). 6~8개의 샷. 각 샷마다: 지속 시간, 움직이는 것, 오버레이 라인 (8단어 미만, 하나의 아이디어), 카메라 위치와 렌즈. 문제 액트는 차갑고 흐린 빛, 제품 액트는 따뜻한 빛. 표로 만들어 승인을 받으세요.
- 캐릭터(선택 사항). 작은 주인공은 시선이 머물 곳을 제공합니다. 모델링 전에 평면 스케치로 3~4개의 옵션을 제시하세요. 셋과 크기를 맞추세요: 주요 소품 위에 들어맞아야 합니다. 간단한 원시 형태로 만드세요(올빼미는 1cm 큐브입니다).
- 코드로 셋 만들기.
build.py를 수정하세요. 미터 단위를 유지하고 주요 소품을 원점에 두세요. 각 샷의 스틸 한 장을 낮은 샘플로 렌더링하고, 애니메이션 전에 모두 확인하세요. - 애니메이션.
film.py에서 각 샷은setup_X(오브젝트를 한 번 생성)와update_X(t)(영상 초t에 모든 것을 배치)를 가집니다. 순수 시간 함수이며 키프레임이 없으므로, 어떤 프레임이든 단독으로 렌더링할 수 있고 중단된 렌더는 중단된 지점부터 재개됩니다. - 2패스 렌더.
python scripts/blender/film.py plates, 그 다음... layers. 아래 참조. - 합성.
python scripts/post/comp.py out.mp4 --draft로 빠른 확인(매 6번째 프레임), 그 후--draft없이 실행. 엔딩 튜닝 중에는--only-ending을 사용하세요. - 확인. 각 오버레이의 중간 지점에서 스틸을 뽑아 확인: 텍스트를 읽을 수 있는지,
텍스트가 지칭하는 것이 프레임 안에 보이는지, 샷 간에 튀는 것이 없는지. 문제가 있는 샷만
수정하고 다시 렌더링하세요(해당 샷의
layers/파일을 삭제).
2패스 렌더
사실적인 잔디는 느립니다. 움직이는 오브젝트는 저렴합니다. 그래서 분리하여 렌더링합니다.
- Plates. 각 샷의 전체 셋(잔디, 소품, 하늘)에 대한 스틸 하나, 예제에서는 1280x720, 36 샘플. 빛이 변하는 샷은 합성기가 크로스페이드하는 두 개의 플레이트를 가집니다.
- Layers. 움직이는 것만, 투명 배경, 낮은 해상도와 샘플로. 지면은 섀도우 캐처이므로 오브젝트가 그림자를 드리웁니다. 정적 소품은 홀드아웃이므로 오브젝트가 그 뒤를 올바르게 통과합니다. 하늘은 조명을 위해 남겨두되 카메라에서는 숨깁니다.
- Compositor. 레이어를 플레이트 위에 놓고, 샷별로 느린 2D 푸시 또는 드리프트로 카메라 움직임을 가짜로 만듭니다. 고정된 3D 카메라가 플레이트를 재사용 가능하게 만듭니다.
세 가지 요소가 비용을 낮춥니다:
- 루프(Loops). 샷이 일정한 흐름이라면, 움직임을 주기적으로 만들고(간격 0.84m, 속도 0.84m/s는
매초 반복), 한 주기만 렌더링합니다.
film.py와comp.py의LOOP가 이러한 샷을 나열합니다. - On twos. 레이어는 매 두 번째 프레임(
STEP = 2)으로 렌더링되고 유지됩니다. 스톱 모션처럼 읽히며, 작은 블록 오브젝트에 적합합니다. - Resume. 파일이 존재하면 모든 프레임을 건너뜁니다.
규모 참고: 예제 영상(51초 3D + 12.5초 엔딩)은 8개의 플레이트와 456개의 레이어 프레임입니다. CPU 전용으로 렌더링되었습니다.
2D 엔딩
comp.py가 Blender 없이 직접 그립니다. 팔레트 색상의 64x36 둥근 사각형 격자가 마지막 3D 프레임
위로 6열 너비로 날아들고, 카메라는 64개 열이 모두 보일 때까지 뒤로 물러난 후, 대각선 파동이 각
블록(중간 지점에서 색상이 바뀌며 수직으로 0으로 스쿼시되었다가 다시 펼쳐짐)을 최종 색상으로
뒤집습니다. 최종 색상은 3x5 픽셀 폰트에서 비롯되므로, 블록이 텍스트가 됩니다.
카피 계획 시 제한 사항: 최대 4줄, 각 줄 12자(11자가 더 좋아 보임), 대문자, 숫자, . - / !.
film.json의 ending에 그리드 행과 팔레트 키로 설정하세요.
film.json 편집하기
palette: 7개의 16진수 색상.primary,accent,warm,soft,deep,paper(엔딩과 기본 블록의 배경),alarm("문제 발생" 색상).overlays:[시작, 끝, "텍스트", x](영상 초 단위).x는 선택 사항으로, 피사체가 가운데 정렬 텍스트에 가려질 때 텍스트의 수평 위치(0~1)입니다. 두 줄은\n을 사용하세요.ending: 블록이 철자할 라인들.font: 오버레이용 .ttf 또는 .otf 경로. 대체 폰트로 Inter, DejaVu, Helvetica 또는 Arial이 사용됩니다.
샷 지속 시간은 film.py와 comp.py 상단의 SHOTS에 있습니다. 동일하게 유지하세요.
설정
python -m venv venv && . venv/bin/activate
pip install bpy==5.3.0 numpy pillow # bpy는 Blender 휠; 일치하는 Python이 필요합니다.
# ffmpeg는 PATH에 있어야 합니다.
TEST=1 python scripts/blender/film.py plates # 480x270, 샷당 한 프레임, 몇 분 소요
TEST=1 python scripts/blender/film.py layers
python scripts/post/comp.py draft.mp4 --draft
FILM_OUT=/some/dir는 plates/와 layers/를 이 폴더 대신 해당 디렉토리에 씁니다. FILM_CONFIG는
다른 film.json을 가리킵니다. GRASS_NEAR 및 GRASS_MID(백분율)는 잔디의 밀도를 조절합니다.
휠 대신 데스크탑 Blender 사용 시: blender -b -P scripts/blender/film.py -- plates.
실제 시간을 낭비하는 함정들
- 잔디 길이. 헤어 파티클 시스템의
normal_factor를 설정하면hair_length가 초기화됩니다.hair_length를 마지막에 설정하지 않으면 모든 잔디가 수 미터 길이가 되어 필드가 모션 블러된 것처럼 보입니다. - 부모-자식 관계. 부모 설정은
matrix_parent_inverse를 설정하지 않으면 자식을 움직입니다. 힌지 부분이 소품에서 떨어져 나갈 수 있습니다. - 하늘. UV 실린더의 하늘 이미지는 늘어납니다. 대형 실린더에 미러링된 패널을 사용하거나, 카메라가 팬하지 않는다면 평면을 사용하세요. 실제 빛을 위해 물리적 태양을 유지하세요.
- 피사체 위의 텍스트. 모든 오버레이를 그 아래 프레임과 확인하세요. 카메라를 움직이기 전에
x로 텍스트를 옮기세요. - 확대(펀치 인)는 물체를 숨깁니다. 오버레이가 무언가를 지칭한다면("차단됨."), 2D 크롭이 여전히 그것을 포함하는지 확인하세요.
- 색상 탈색. AgX 아래에서 칠해진 표면은 브랜드 16진수보다 어두운 기본 색상이 필요합니다. 화면이나 정확한 색상으로 읽혀야 하는 모든 것은 emission을 사용하세요.
- GPU 없음. 프레임별로 예산을 세우세요: 레이어 프레임 하나의 시간을 측정하고, 곱한 후, 해상도, 샘플 또는 샷 길이를 줄여서 맞추세요. 시간을 측정하지 않은 렌더를 시작하지 마세요.
- 컨테이너 재시작. 긴 렌더는 중단됩니다. 파일 존재 시 건너뛰기 검사가 당신을 구합니다.
이 파이프라인이 하지 않는 일
상대방이 기대하기 전에 솔직히 알려주세요.
- 움직이는 3D 카메라. 샷은 고정되어 있고 2D 움직임이 위에 추가됩니다. 실제 시차는 매 프레임 셋을 렌더링해야 하며, GPU가 필요합니다.
- 모션 블러와 레이어의 24fps 모션. 하드웨어가 허용할 때 샘플을 높이고,
STEP = 1로 설정하고render.use_motion_blur를 켜세요. - 오브젝트는 잔디 위에 앉고, 잔디 안에 있지 않습니다. 잔디는 플레이트에 있기 때문입니다.
- 사운드. 영상은 무음으로 작동하도록 제작되었습니다. 필요시 나중에 음악과 효과를 추가하세요.
- 3D 세계의 화면, UI 또는 로고. 의도적으로 제외했습니다: 사실적인 필드 속 제품 UI는 가짜로 읽힙니다. 제품 시각 자료는 2D 엔딩이나 별도 컷에 넣으세요.
최종 품질 패스를 위해
1920x1080 이상, 128+ 샘플 및 노이즈 제거, GPU 렌더링(OptiX 또는 Metal), STEP = 1, 모션 블러 켜기,
comp.py의 W, H를 일치하도록 높이세요. 프레임 번호별로 여러 머신에 분할하세요;
모든 프레임은 독립적입니다.