X Motion · Orbit
Orbit는 x-motion을 확장하며, 이를 대체하지 않습니다. 핵심 메서드(브리핑, 테제, 스토리보드, 비평)를 실행하고 이 파일을 아트 디렉션과 레시피로 사용하세요. 이 파일은 renderFrame(t)에서 헤드리스 Chromium과 소프트웨어 WebGL로 결정론적으로 렌더링되는 8–12초, 1920×1080, 30fps 필름을 위해 작성되었습니다.
시각적 테제
우주는 검고, 빛은 사건입니다. 하나의 광원(태양)과 그것이 닿는 물질: 대기, 바다, 구름, 금속. 모든 영화는 빛이 도착하고, 가장자리를 가로지르거나, 자유로워지는 단일 순간을 중심으로 구축됩니다.
스펙터클보다는 조용한 자신감. 프레임은 대부분 진정한 검정이며; 피사체는 크고 느린 질량(행성, 달, 금고 문)과 얇은 밝은 가장자리입니다. 프레임이 배경화면이나 게임 메뉴처럼 보인다면, 인내심 있는 카메라로 찍은 사진처럼 보일 때까지 요소를 제거하세요.
팔레트
선형 HDR에서 작업하고 마지막에 톤매핑하세요; 이것들은 눈이 도달해야 하는 디스플레이 참조 대상입니다.
| 역할 | Hex | 사용처 |
|---|---|---|
| 진정한 검정 | #000000 | 대부분 프레임의 60–80%. 헤이즈로 절대 밝히지 마세요. |
| 공허의 남색 | #050b18 | 깊은 우주 그라데이션, 빛에서 멀리 떨어진 곳. |
| 깊은 남색 | #0b1a33 | 밤의 바다, 그림자 진 금속, "들어올림" 이후의 어두운 하늘. |
| 레일리 블루 | #2f6fd8 | 낮 쪽의 대기 본체. |
| 대기 시안 | #8fd3ff | 프레넬 림, 얇은 가장자리 선. |
| 일출 금색 | #ffc46b | 태양 코어 감쇠, 경계선, 구름 꼭대기의 첫 빛. |
| 잿불 호박색 | #ffa448 | 밤 쪽의 도시 불빛(나트륨). |
| 코로나 진주색 | #ece8de | 코로나, 별, 종 모양 하이라이트. |
| 티타늄 | #8a8f96 | 브러시드 금속 본체. |
| 니켈 | #c3c6c8 | 금속 하이라이트, 베벨 평면. |
| 샴페인 | #e9d4a6 | 금속의 따뜻한 정반사 가장자리; 최대 2px 선. |
| 오로라 녹색 | #4ff0a0 | 산소 오로라; 전체 값의 20% 미만으로 유지. |
| H-알파 장미 | #ff4a6e | 태양 홍염과 채층 전용. |
빛과 재질
- 하나의 빛. 태양이 유일한 광원입니다. 광선, 림, 반짝임은 그 위치로 설명되어야 합니다. 도시와 오로라만이 유일한 방출원이며, 밤 쪽에 위치합니다.
- 별 원반의 가장자리 감광:
I(mu) = 1 - 0.6*(1 - mu),mu = sqrt(1 - r*r); 금색에서 흰색으로의 코어는 뜨겁게 읽히고, 평평한 원반은 스티커처럼 읽힙니다. - 대기는 선이 아니라 산란입니다. 빛이 닿는 가장자리의 파란색(레일리), 경계선을 스치는 금색, 태양이 행성 뒤에 있을 때의 전방 산란 광도. 림은 얇습니다: 행성 반경의 약 1.5%.
- 밤 쪽은 검지 않습니다: 차가운 달빛 채움은 바다를 깊은 파란색(결코 올리브색 아님)으로, 땅을 더 어두운 중성 색조로, 구름을 은백색으로, 원반 가장자리의 시안 프레넬 림, 해안선을 따라 호박색 도시 클러스터, 그리고 가장자리의 희미한 녹색 공기광선을 유지합니다. 따뜻한 금색은 태양이 실제로 닿는 곳에만 나타납니다.
- 바다 반짝임: 태양이 반사되는 부드러운 정반사 로브, 가장자리 쪽으로 길어짐; 바다 전용.
- 금속: 브러시드 티타늄은 이방성입니다. 하이라이트는 브러싱 방향으로 늘어나고, 베벨은 얇은 샴페인 가장자리를 포착하며, 이음새는 폐색을 얻습니다. 크롬 미러, 범프 맵 노이즈는 없습니다.
- 렌즈: 하나의 아나모픽 스트릭(수평, 얇음, 시안 색조), 프레임 중심을 통과하는 선을 따라 2~4개의 희미한 고스트. 고스트 불투명도 4% 미만. ACES 스타일 곡선으로 톤매핑; 몇 픽셀 이상을 평평한 흰색으로 클리핑하지 마세요.
구도
- 수평선은 3분할에 위치하며, 절대 중앙을 통과하지 않습니다. 행성 가장자리는 큰 호(반경 1.5–4 프레임 높이); 전체 작은 구체는 장난감처럼 보입니다.
- 빛 사건(태양의 정점, 다이아몬드 링, 첫 빛)은 중앙이 아닌 3분할에 위치합니다. 단, 샷이 대칭(금고 문, 일식)에 관한 경우는 예외입니다.
- 별은 드물게 유지(몇 백 개 보임), 크기 1–2px, 부드러운 감쇠, 온도에 따라 약간 따뜻하거나 차갑게. 프레임이 어두워지면 나타나고 밝아지면 사라집니다. 노출에 따라.
- 텍스트, 로고, HUD, 성운 배경화면, 렌즈 먼지 없음. 한 번에 하나의 피사체.
모션 어휘와 타이밍
동사: 봉인하다, 걸쇠를 풀다, 열리다, 떨어지다, 떠오르다, 정점에 이르다, 미끄러지다, 삼키다, 펼쳐지다, 벗어나다, 들어올리다. 카메라는 절대 흔들리지 않고 거의 컷하지 않습니다; 질량은 천천히 움직이고, 빛은 빠르게 움직입니다.
| 비트 | 일반적인 길이 | 곡선 |
|---|---|---|
| 봉인되거나 어두운 프레임 유지 | 1.0–1.5 s | 정적, 빛의 움직임만 |
| 기계적 걸쇠 해제 | 0.10–0.20 s | 빠른 이즈-아웃, 작은 안정화 |
| 문 열림 / 낙하 | 0.8–1.4 s | 느린 시작, 지수적 가속 |
| 워프(스트릭) | 1.2–2.0 s | 초기에 정점, 부드럽게 정지로 감쇠; 드물게, 프레임은 대부분 검정 유지 |
| 행성 상승 / 궤도 활공 | 3–6 s | 긴 이즈-인-아웃, 절대 선형 아님 |
| 태양 정점 또는 다이아몬드 링 | 0.3–0.6 s 전체 플레어까지 | 날카로운 시작, 느린 확산 |
| 해결 및 유지 | ≥ 1.5 s | 거의 정지; 코드가 울리도록 |
모션은 t로부터 폐쇄형으로 계산됩니다: 위치는 저작된 속도 곡선의 적분이며, 프레임별로 축적되지 않습니다. 워프 이동은 s(t) = integral of v이므로 스트릭 길이는 s(t) - s(t - shutter)입니다. 스트릭을 적게(레이어당 수십 개, 수백 개 아님) 유지하고, 길고 부드럽게, 먼 레이어는 가까운 레이어보다 흐릿하고 얇게; 밀집된 균일한 버스트는 재고 하이퍼스페이스처럼 읽힙니다.
사운드 팔레트와 믹스
- 서브 (30–60 Hz 사인파, 느린 팽창)는 질량을 전달합니다. 마스터를 약 25Hz에서 하이패스합니다(렌더링 후 JS에서; 오디오 마스터 레시피 참조).
- 금속: 모달 합성. 5–10 ms 대역통과 노이즈 클릭 + 4–6개의 비고조파 사인 부분음(예: f0의 1.00, 2.32, 3.86, 5.40 배)과 감쇠 0.1–0.8 s.
- 공기와 이동: 시드된 노이즈를 움직이는 대역통과에 통과, 영상에 따라 패닝. 재고 후시 소리 없음.
- 하모니: 긴장감 아래 서스펜디드 패드(sus2, sus4); 빛 사건에서 메이저 add9로 해결. 패드는 노트당 3개의 디튠드 톱니파를 통해 600–1800 Hz 로우패스.
- 종: 가산적 비고조파 부분음(1, 2.0, 2.76, 4.07, 5.4), 3–8 ms 어택, 부분음 인덱스가 증가함에 따라 감쇠가 짧아짐.
- 리버브: 하나의
ConvolverNode, 시드된 스테레오 임펄스(2.5–4.5 s 지수 감쇠, 20 ms 프리딜레이, 더 어두운 테일). - 침묵은 큐입니다. 이미지가 어두워지면 소리를 얇게 하세요; 빛 사건이 첫 번째 큰 순간을 차지하게 하세요.
- 타겟: 통합 −18 LUFS, 참 피크 ≤ −1.5 dBFS, 테일이 끝에서 0.3 s 전에 완전히 감쇠. 코드로 측정하고, 정규화한 다음, 리미터를 적용하세요.
기술 레시피
파이프라인. 소프트웨어 WebGL은 느리므로 작업을 분할하세요: 절반 해상도 패스는 부드러운 HDR 장면(행성, 대기, 코로나)을 RGBA16F 텍스처로 렌더링합니다; 전체 해상도 패스는 이를 업샘플링하고 선명한 디테일(별, 도시 불빛, 플레어, 금속 가장자리)을 추가한 다음 톤매핑과 디더링을 수행합니다. 초당 프레임 수를 측정하고 1080p에서 1.5초 미만으로 유지하세요.
구-광선. 해석적, 표면에 마칭 불필요:
vec2 sphere(vec3 ro, vec3 rd, float R) { // t 가까움, t 먼; t < 0은 빗나감
float b = dot(ro, rd), c = dot(ro, ro) - R*R, h = b*b - c;
if (h < 0.0) return vec2(-1.0);
h = sqrt(h); return vec2(-b - h, -b + h);
}
대기. 껍질 내부의 시선 광선을 따라 단일 산란(8–12 단계), 광 경로의 광학 깊이는 3–4 단계로 근사. 레일리 계수 vec3(5.8, 13.5, 33.1) (행성 반경에 맞게 스케일), 미에 산란은 헤니-그린스타인 위상 함수 g = 0.76. 광선이 껍질에 진입하지 않는 픽셀은 건너뜁니다.
도시 불빛. 클러스터 해시 노이즈, 육지와 밤으로 마스킹:
float night = smoothstep(0.05, -0.15, dot(n, sunDir));
float c = pow(max(fbm3(p*40.0) - 0.45, 0.0)*3.0, 2.0) * land * night;
col += c * vec3(1.0, 0.62, 0.28) * 6.0; // 호박색, HDR
별, 대역 제한. 그리드 셀당 별 하나, 지터링; 시그마가 최소 0.8px인 가우시안으로 그려 모션이 스트로브하지 않도록 함:
vec2 cell = floor(px / 24.0), f = px - (cell + hash22(cell)) * 24.0;
float star = exp(-dot(f, f) / 1.6) * pow(hash12(cell + 7.1), 18.0) * 3.0;
태양 정점 플레어. 모든 것은 태양의 화면 위치 s와 보이는 비율 v(JS에서 계산) 주변에서 해석적:
vec2 d = uv - s;
float core = exp(-dot(d, d) * 9000.0), halo = 0.04 / (1.0 + dot(d, d) * 400.0);
float streak = exp(-abs(d.y) * 900.0) * exp(-abs(d.x) * 2.2);
vec3 flare = v * (core * vec3(1.0, .9, .75) * 40.0 + halo * gold + streak * cyan * 2.0);
for (int i = 0; i < 3; i++) { vec2 g = -s * kGhost[i]; /* g에서 부드러운 원반, 2–4 % */ }
브러시드 티타늄. 브러싱 방향을 따른 접선을 갖는 이방성 하이라이트, 희미한 대역 제한 스트릭(파장 ≥ 3px) 추가:
float TH = dot(T, H);
float aniso = pow(sqrt(max(1.0 - TH*TH, 0.0)), 60.0);
float grain = 0.92 + 0.08 * noise(vec2(r * 300.0, angle * 3.0));
vec3 metal = base * (0.25 + 0.75 * diffuse) * grain + champagne * aniso;
일식. 달이 태양보다 약간 큼(1.04–1.08). 달의 가장자리에 약간의 노이즈를 주어 베일리의 구슬과 다이아몬드 링이 접촉 근처에서 자연스럽게 나타나도록 함. 코로나: 밝기 pow(r, -3)에 노이즈(각도, log r)의 스트리머, 높은 각주파수와 낮은 방사 주파수 노이즈의 미세 필라멘트를 곱합니다.
가장자리 프로파일을 정수 주파수 사인과 래핑된 가우시안 노치의 합으로 한 번 작성한 다음, JS와 GLSL 문자열로 모두 내보냅니다. JS는 프레임당 보이는 광구를 적분할 수 있습니다(태양 중심 광선당 하나의 이분법, 약 700 광선). 이를 통해 보이는 비율, 눈부심을 위한 구슬 중심, 점수를 위한 정확한 접촉 시간을 얻습니다. 구슬 눈부심은 비율의 로그 매핑이 필요합니다(예: log(1 + f*1e6) / log(1 + 1e6)). 거친 밉에서 그려진 넓은 눈부심은 HDR 소스에서 계단 현상을 보이므로, 반-텍셀 오프셋에서 네 개의 쌍선형 탭으로 각 레벨을 흐리게 합니다.
오디오 마스터(결정론적). startRendering() 후, JS에서 통합 LUFS(BS.1770 K-가중치 및 게이팅)를 측정하고, −18로 스케일링한 다음, 4배 오버샘플링된 피크에 대해 −1.5 dBFS에서 룩어헤드 피크 리미터를 실행합니다. 모든 노이즈 버퍼와 임펄스를 mulberry32로 시드합니다.
헤드리스 Chromium에서 이들은 비트-정확 반복 테스트에 실패합니다: 마스터 BiquadFilterNode 또는 DynamicsCompressorNode를 통한 스테레오 신호와 세 개 이상의 입력을 가진 노드는 합산 순서가 1 ULP만큼 다르기 때문입니다. 마스터 버스를 노드 없이 유지합니다(목적지로 게인). 하이패스와 버스 압축은 렌더링 후 JS에서 실행합니다. 리버브의 하이패스를 임펄스에 굽습니다. 모든 팬-인을 2-입력 게인을 통해 연결합니다. a + b는 정확하고 가환적이기 때문입니다.
function mulberry32(a){return()=>{a|=0;a=a+0x6D2B79F5|0;let t=Math.imul(a^a>>>15,1|a);
t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296;};}
결정론적 체크리스트
renderFrame(t)는 모든 유니폼을t만으로 설정합니다. 렌더 모드에서Date,performance.now,Math.random또는 프레임별 축적이 없습니다.- 시드된 해시와 PRNG만 사용; 그림과 소리가 일치해야 할 때 동일한 시드를 사용합니다.
- 뒤로 찾기는 동일한 픽셀을 재현합니다; 늦은 프레임 후 t = 0을 테스트합니다.
preserveDrawingBuffer: true,antialias: false;renderFrame끝에서gl.finish()를 호출합니다.- 미리보기 모드는
requestAnimationFrame으로 반복;?render=1은 자체적으로 아무것도 그리지 않습니다. renderAudio는 매 호출마다 동일한 버퍼를 반환하며, 두 렌더링에서 샘플 단위로 비교합니다. 음량과 참 피크는 추측이 아닌 측정됩니다.- 빛 사건, 그 이전 프레임 및 마지막 프레임에서 스틸을 검사합니다. 프레임당 타이밍을 확인합니다.
피해야 할 것
- 만화 윤곽선, 행성 주위의 빛나는 선, 채도 높은 보라색 성운, 육각형 고리가 있는 렌즈 플레어 프리셋.
- 회전하는 지구본, 빠른 카메라 움직임, 흔들림, 물리적 원인 없는 스피드 라인.
- 하이라이트를 평평한 흰색으로 클리핑, 검정 리프팅, 밴딩(출력 전에 서브-LSB 디더 추가).
- 프레임별 전체 화면 그레인 또는 1px 반짝임; 스트로브하고 H.264를 부풀립니다.
- 모든 움직임에 대한 사운드 효과, 싸구려 후시 소리, 아무 데도 가지 않는 라이저, 버퍼 가장자리의 클릭, 영화 끝에서 잘린 리버브 테일.
- 브리핑에서 요구하지 않는 한 텍스트, 로고 또는 인터페이스 크롬.