X Motion:稜鏡
Prism 是核心 x-motion 方法的主題。請遵循該方法(簡介、論文、分鏡、動態腳本、製作、限定評論)。此檔案增加了使主題可識別並保持其真實性的藝術指導、物理和聲音。
視覺論文
讓一種光學現象感覺精確且靜默地神奇,透過像拍攝靜物般在淺色攝影棚中捕捉它,使觀者注意到光實際上的行為。
- 每部影片一個英雄現象。 色散、焦散、透鏡成像、全內反射、菲涅爾邊緣。其他一切都只是讓它降落的平靜表面。
- 物理決定色彩的歸屬。 世界是消色差的:紙張、石頭、石墨。光譜色僅在波長分離處出現(離開稜鏡的光扇、透鏡的邊緣、焦散的邊緣),而非其他地方。
- 亮度即是情緒。 這與黑暗空間主題相反。陰影是柔和的石墨色,絕非黑色;亮部是光,絕非霓虹。
- 相機是腳架。 鎖定或幾乎無法察覺的推移。現象在動;觀察者不動。
調色盤
| 角色 | 十六進位碼 | 用途 |
|---|---|---|
| 紙張 | #f2efe9 | 主導表面,環境日光 |
| 陰影中的紙張 | #d9d4cb | 主光源區域外的部分 |
| 淺色石頭 | #e6e1d8 | 地板、水池、基座(以低頻噪聲 ±3% 變異) |
| 石墨 | #5d5b57 | 印刷線條、接觸陰影(透明度 20–60%) |
| 深石墨 | #3a3936 | 允許的最暗值,僅用於接觸摺痕 |
| 水色調 | #d8e6e4 | 在石頭上方以「相乘」模式疊加,用於淺層清水 |
| 光譜 | 計算得出 | 僅來自波長至 RGB 的函數,絕非手選的彩虹 |
線上性光中工作,累加光能量,然後進行色調映射並一次轉換為 sRGB。在明亮背景上的疊加光譜色會變淡,因此需在色彩需呈現飽和處局部降低背景亮度(在英雄現象周圍創造柔和陰影區域,約 45–60% 線性),並保持畫面其餘部分通透。
光線與材質
- 主光: 一個來自左上方、與畫面軸線約 30–45° 的柔和日光光源。陰影長、柔和且略帶暖灰色。
- 玻璃: 清澈、無色、無瑕。其存在僅透過四件事體現:背後物體的折射、一條細菲涅爾邊緣、一個柔和窗戶反射,以及它所投射的焦散或光譜光。無倒角光暈、無色調玻璃、無綻放光暈。
- 折射率: Cauchy 色散公式,
n(λ) = A + B/λ²,λ 單位為 µm。皇冠玻璃:A = 1.5046, B = 0.0042。當色散需要在螢幕上可讀時,可將B誇大約 3 倍,並在你的筆記中說明。 - 紙張與石頭: 霧面,極低對比紋理(亮度變化 2–4%),靜態於時間中。精細印刷線條為 1.2–2 px 的石墨色,帶有柔和衰減。
- 接觸: 每個接觸表面的物體都會獲得一個緊繃、更暗的接觸陰影,加上一個寬廣柔和的陰影。這正是讓玻璃感覺穩固而非漂浮的關鍵。
構圖
- 寬闊的負空間:英雄現象約占畫面三分之一;其餘為帶有柔和光線漸層的紙張或石頭。
- 將事件置於三分線或黃金點上,除非影片主題是對稱,否則絕不置中。
- 用光線引導視線:光束、滾動方向或漣漪應朝向回報發生的地方。
- 保持畫面邊緣寧靜且略暗(來自光源的 6–10% 暗角,非黑色環)。
- 無文字、UI、標誌或裝飾性粒子。若現象需要比例參考,請使用印刷網格、石頭接縫或陰影。
運動詞彙與節奏
動詞:進入、彎曲、展開、掃掠、對焦、漣漪、沉降。 移動的名詞:光、水、單一物體。不要同時移動相機和主體。
| 拍點 | 佔 9–10 秒影片的典型比例 | 行為 |
|---|---|---|
| 靜止 | 10–15% | 空的、點亮的場景。讓觀者閱讀表面。 |
| 抵達 | 15–20% | 光線或物體沿著清晰路徑以減速緩動進入。 |
| 現象 | 35–45% | 英雄效果緩慢發展變化(旋轉幾度、滾動、漣漪)。 |
| 沉降 | 20–25% | 運動以物理方式衰減(摩擦、阻尼、波浪擴散)並保持。 |
| 釋放 | 5–8% | 光線變暗或影像靜止,以便循環和音頻尾聲能閉合。 |
- 使用物理閉合形式的運動:滾動用恆定減速,沉降用阻尼餘弦,擴散環用
1/sqrt(r)振幅,旋轉用緩動角度。 - 當你動畫化光束頭時,光在玻璃內的速度明顯慢於空氣中(
v_glass = v_air / n)。這是一個觀者能感受到的微小真實。 - 偏好一個長手勢勝過數個短手勢。一整圈太多;4–10° 就足以讓光譜掃掠。
聲音調色板與混音
聲音是玻璃、空氣和水,經過調音。它應該感覺像一個有著堅硬、清潔表面的房間。
- 玻璃泛音: 模態合成,搭配少量非諧波泛音(對於敲擊玻璃,比例接近
1, 2.32, 4.25, 6.63),每個都有自己的指數衰減;較高泛音消失得更快。 - 手指擦玻璃聲: 一兩個正弦波,帶有 0.3–0.6 秒的緩慢膨脹、4–5 Hz 的顫音(±0.15%)以及一絲在同音高上的帶通濾波噪聲。
- 空氣聲: 帶粉紅色種子的噪聲,通過帶通濾波器(300–2500 Hz),非常低,緩慢呼吸。這是房間的聲音,不是風聲。
- 水聲: 泡泡「噗通」聲是頻率在 30–80 毫秒內指數上升約 30–60% 的正弦波;柔和沖洗聲是低通濾波噪聲。
- 和聲: 選擇一個調性並保持(開放五度、附加九度、利地安調式色彩)。將現象映射到音高:光譜位置映射到音階音級,速度映射到濾波器截止頻率,停止映射到解決的鍾聲。
- 空間: 一個使用種子生成的合成卷積混響(2.5–4.5 秒,尾部變暗),由所有聲音共享,乾濕比約 60/40。
- 目標: 綜合響度約 -18 LUFS,真實峰值等於或低於 -1.5 dBFS,0.3 秒淡入,且每個尾部在結束前衰減 0.4 秒。
技術配方
純時間函數。 每一格都從 t 重新計算整個場景:物體姿態、光束頭、波相位。僅使用種子隨機性。
const mulberry32 = s => () => { s |= 0; s = s + 0x6D2B79F5 | 0;
let t = Math.imul(s ^ s >>> 15, 1 | s); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
return ((t ^ t >>> 14) >>> 0) / 4294967296; };
解析場景,少量渲染通道。 相交少量解析形狀(平面、球體、作為一組平面的凸稜鏡),而非光線步進。將時間推導狀態(角度、位置、光線路徑)作為在 JavaScript 中計算的統一變數傳遞。將畫面分割成幾個小型單一用途的通道(地板、半解析度的光場進入 RGBA16F 目標、覆蓋其上的玻璃),而非一個帶有分支的著色器。
來自波長的光譜色。 使用平滑的解析擬合,使光扇讀起來像光,而非漸層色票。總和多個波長樣本並歸一化,使總和為中性白。
float gauss(float x, float m, float s) { float u = (x - m) / s; return exp(-u * u); }
vec3 spectral(float nm) { // 平滑擬合,線性 RGB,可見窗口 372-712 nm
float w = smoothstep(372., 392., nm) * (1. - smoothstep(690., 712., nm));
return w * vec3(gauss(nm, 606., 46.) + 0.14 * gauss(nm, 420., 22.), // 紅光在紫光處返回
gauss(nm, 543., 44.),
gauss(nm, 452., 34.));
}
在明亮背景上,紫光端呈現為淡薰衣草色;這是誠實的,因此應給予它一個更暗的局部區域,而非增強它。
每個波長的折射。 使用不同折射率(紅、綠、藍或更多)追蹤同一條光線兩三次。結果一致處,你得到清晰的中性細節;結果分歧處,你得到正好物理預測處的色差邊緣。
vec3 col;
for (int k = 0; k < 3; k++) {
float n = 1.5046 + B * 3.0 / pow(LAMBDA[k], 2.0);
col[k] = traceThroughGlass(ro, rd, n)[k]; // 折射進入,折射離開,採樣地板
}
無模擬的焦散。 對於一個由幾個解析波構成的水面 h(x, t),到達其下方地板上某一點的光線強度與 1 / |det(I + d · Hess h)| 成比例,其中 d 是深度除以折射率。解析計算 Hessian 矩陣(正弦波和徑向環包兩者皆有閉合形式),用 1 / sqrt(det² + ε²) 軟化奇異點,並以三個稍微不同的 d 值評估它,以獲得薄光譜邊緣。
平面上的光線。 掠過紙張的光束是一個沿其軸線的 1D 高斯分佈,exp(-(dist/w)²),加上一個更寬、更淡的光暈。光束頭沿著路徑以緩動距離前進;用一個短 smoothstep 裁切,而非硬邊緣。
帶限印刷。 根據到最近線條的距離對上螢幕空間足跡(命中點的 fwidth)繪製網格線,使線條在任何放大倍率下(包括在透鏡內部)保持 1.5–2 px 的柔和度。當單元格縮小到低於幾個像素時,淡出到印刷的平均色調,而非空白紙張。給予放大的墨水一個最小柔和度(約其寬度的一半),否則球面透鏡下的線條會變成剃刀邊緣的楔形。
float lines(vec2 p, float s, float w, vec2 fw) {
vec2 d = abs(fract(p / s + .5) - .5) * s, a = max(fw * .8, vec2(w * .55)), wd = max(vec2(w), a);
vec2 l = (1. - smoothstep(wd - a, wd + a, d)) * clamp(vec2(w) / wd, 0., 1.);
return mix(max(l.x, l.y), 4. * w / s, smoothstep(.18, .42, max(fw.x, fw.y) / s));
}
玻璃需要一些暗的東西來折射。 在白色攝影棚中,完美球體會變成乳白色。為環境提供接近地平線的灰色牆壁、一個緊湊的柔光箱和一面黑色旗幟;球體內翻轉的地平線和窗戶便描繪出其形狀。計算所有路徑而不分支,以使 fwidth 保持有效,並將解析覆蓋率(光線到中心距離除以半徑,以像素為單位)輸出為 alpha。
色調與完成。 指數肩部 1 - exp(-1.85 x) 使紙張保持在 #f2efe9 附近,同時焦散峰值柔和滾降;然後 sRGB。每個通道的肩部會將明亮光譜帶漂白成柔和色調,因此對於有色光,約一半量地混合到色調保持曲線(對最大通道進行色調映射並縮放),由色度門控,使紙張不受影響。完全保持色調,或銳化頻帶顏色,會將橙色、黃色和青色壓平為平坦的紅、綠和藍色條帶。數值檢查光扇:對其進行橫向採樣,確認色調僅上升一次,從紅色(約 10°)到紫色(約 270°),沒有環繞。僅添加靜態的子-最低有效位抖動(±0.6/255)以打破蒼白漸層中的條帶;永遠不要逐幀動畫化它。
速度。 SwiftShader 是軟體渲染,著色器中的每一條指令都要付出代價,包括沒有像素會取用的分支。保持每個通道單一用途,以半解析度渲染柔和光場,並將昂貴的通道(玻璃、稜鏡內部)裁剪到物體的投影邊界框,使用 SRC_ALPHA, ONE_MINUS_SRC_ALPHA 與地板混合。在打磨前,測量 1920×1080 解析度下每秒幀數;最多使用 5 個八度的不規則雜訊函數。
確定性音頻圖。 Chromium 以未指定的順序將三個或更多連接加總到一個 AudioNode 中,因此兩次渲染會有約 1e-6 的差異,並導致字節檢查失敗。在 JavaScript 中合成每個聲音到一個立體聲 Float32 混合中(相位累加正弦波、基於種子噪聲的 RBJ 雙二階濾波器、樣本精確包絡),然後圖形僅用於一個單一源信號進入乾增益和一個卷積器,兩者再進入一個高通濾波器(兩個輸入可交換),然後是一個溫和壓縮器(約 2.5:1, -20 dB 閾值)和一個線性淡出。
const M = A.mix(sr, D); // { L, R } Float32Arrays
A.glass(M, 6.6, hz(81), 0.15, { decay: 2.8, pan: 0.2 }); // 模態泛音,在 JS 中加總
const buf = await A.render(M, { seed: 31, room: 3.4, wet: 0.45, fade: [8.25, 8.8] });
return A.master(buf, { lufs: -18, ceiling: -1.7 });
在頁面中進行母帶處理。 在 startRendering() 之後,測量緩衝區(K 加權、門控積分響度和 4 倍過採樣峰值),應用一個增益以達到目標響度,並在峰值限制需要時應用較低增益。確定性且簡單。
確定性渲染核對清單
window.motion宣告寬度、高度、時長、幀率和在最美麗幀上的海報時間。renderFrame(t)僅從t設定每個統一變數;在渲染模式中無Date、performance.now、Math.random、計時器或累積狀態。- 向後然後向前搜尋能產生相同的像素;第一幀和最後一幀捕獲都是有效的。
- 預覽模式(無
?render=1)以requestAnimationFrame循環;點擊播放相同的渲染音頻緩衝區,並保持同步。 renderAudio在 JavaScript 中混合聲音,然後在OfflineAudioContext中透過一個使用種子生成的卷積器渲染一個源信號;兩次調用返回位元組相同的樣本(無節點有三個或更多輸入)。- 提示映射表是一個由圖片和聲音共享的時間表(撞擊、停止、釋放),且混響尾巴在最後 0.3 秒低於 -45 dB。
- 無網路、字體、圖片或樣本;每個紋理和聲音都是程式生成的。
避免
- 橫跨畫面的彩虹漸層、彩虹文字、彩虹色「全息」表面。
- 霓虹色、紫藍色「AI」漸層、黑色背景、鏡頭光暈和變形鏡頭條紋。
- 光澤的 3D 渲染玻璃:厚亮倒角、色調玻璃、HDRI 鍍鉻反射、萬物皆綻放。
- 無接觸陰影的浮動物體;非來自物理原因的顏色。
- 相機繞行、快速剪輯、粒子、閃光、咻聲和上升音。
- 逐幀隨機雜訊和在 H.264 壓縮後閃爍的單像素線條。
- 削波的聲音、與調性衝突的和弦疊加、在結尾被截斷的混響尾巴。