왜 만들었나
조명 위치, 렌즈와 거리, 카메라 높이가 결과에 어떻게 영향을 주는지 비전문가는 촬영 현장에서야 알게 됩니다. 피사체·무드·조명 수를 고르면 컷별 세팅을 계산하고 평면도·측면도로 보여 줍니다.
주요 기능
- 피사체·무드·조명 수에 따라 컷 5~6개 콘티와 키·필·림 조명 배치 자동 생성
- 평면도 캔버스에서 조명을 끌어 옮기면 조명 패턴(루프·렘브란트 등)과 노출 안내가 바로 바뀜
- 야외 모드에서 도시·날짜·시각으로 태양 방위·고도를 계산해 키 조명으로 사용
- 참고 사진을 올리면 MediaPipe로 얼굴·자세를 찾아 프레이밍·앵글·조명 패턴·색감 태그를 추정하고 IndexedDB에 저장
- 목적별 촬영 계획서와 골든아워 기준 시간표 생성
숫자로 보면
피사체 7종 × 무드 6종, 피사체별 기본 컷 5개
조명 패턴 7종, 목적별 촬영 계획 9종
예시 사진 306장(37개 분류), 태양 계산 지원 도시 8곳
어떻게 동작하나
설정 선택
피사체·무드·조명 개수·모드(스튜디오/야외 스냅)를 고르면 state에 담아 localStorage에 저장합니다.
index.html컷 생성
buildShots()가 피사체별 컷 템플릿에 무드의 조명 각도와 조명 수 규칙을 적용해 컷마다 키·필·림 각도와 명암비를 정합니다.
index.html기하 계산
geom()이 프레이밍 높이와 초점거리로 촬영 거리(d = 화면 높이 × 초점거리 / 36)와 앵글별 카메라 높이를 계산합니다.
index.html태양 위치 반영
야외 모드에서는 sunPos()가 날짜·시각·위경도로 태양 방위·고도를 계산하고 applySun()이 이를 피사체 기준 키 조명 각도로 바꿉니다.
index.html시뮬레이션 렌더
drawSim()이 평면도·측면도 캔버스를 그리고 classify(방위, 고도)로 조명 패턴을 판정해 노출값·주의사항·예시 사진을 함께 보여 줍니다.
index.html참고 사진 역추정
올린 사진에서 MediaPipe 얼굴 랜드마크 주변 밝기를 재어 명암비와 조명 패턴을 추정하고, 그 값을 시뮬레이터 설정으로 불러옵니다.
index.html
핵심 코드
const upLeft = aIsLeft ? upA : upB, upRight = aIsLeft ? upB : upA;
const fore = at([151, 9]), philtrum = at([164]);
const faceMean = (leftL + rightL + fore)/3;
const bright = Math.max(leftL, rightL), darkC = Math.min(leftL, rightL);
const ratio = lin(bright)/Math.max(lin(darkC), .002);
const keyLeft = leftL >= rightL;
let pat;
if (bgMean > faceMean*1.6 && faceMean < 70) pat = faceMean < 40 ? 'silhouette' : 'rim';
else if (ratio < 1.35) pat = (lin(philtrum) < lin(fore)*.55) ? 'butterfly' : 'flat';
else if (ratio < 2.6){ const upDark = keyLeft ? upRight : upLeft; pat = lin(upDark) > lin(darkC)*1.9 ? 'rembrandt' : 'loop'; }
else if (ratio < 5){ const upDark = keyLeft ? upRight : upLeft; pat = lin(upDark) > lin(darkC)*1.9 ? 'rembrandt' : 'split'; }
else pat = 'split';얼굴 양쪽 볼과 이마·인중 밝기를 선형광으로 바꿔 비교해 사진의 조명 패턴을 추정하는 부분입니다.
어려웠던 점
사진 한 장에서 조명 방향과 패턴을 거꾸로 추정하는 부분입니다. 얼굴 랜드마크 주변 픽셀 밝기를 감마 보정한 선형광으로 비교해 명암비를 구하고, 배경 대비와 볼 위쪽 그림자로 실루엣·림·렘브란트를 구분합니다.


