簡而言之: 我們正在為 Unreal Engine 打造一套水系統,帶著兩個承諾:看起來對的水——因為光、色與泡沫是物理計算的, 而不是逐場景手工調出來的——以及會行為的水:把任意網格丟到水面上,它就會零設定地正確漂浮、傾覆或下沉。它正在積極開發中。 本文解釋它涵蓋什麼、我們如何用參考照片對自己負責、為何浮力是人人跳過的難點,以及它在工具箱其餘部分旁的位置。
要超越的標準。留意是什麼讓它真實:由破碎的浪生出的泡沫、吞噬崖壁的霧靄、貫穿整片湧浪的白冠統計——無一手工放置,全是物理。 這就是我們設下的那道杠。
為什麼又一套水系統?
大多數遊戲水只在恰好一種光照條件下看著極好——商店截圖裡的那種。移動太陽、切到陰天、把相機放到水線以下一半, 它就散架了。
還有第二個更安靜、同樣要緊的失敗:幾乎每套水系統都把漂浮物體當作事後想法。你得到一個船範本、一頁浮筒裝配說明,以及一個 不言自明的假設——沒人會往海裡隨手丟個箱子。玩家一直在往海裡丟箱子。
我們想要兩件目前不共存於同一個套件裡的東西:能熬過任何光照的電影級觀感,以及無需任何設定的物理行為。二者都不是靠擰參數 擰到某張截圖好看就能達成的——因為截圖是單一太陽下的單幀,而只要其中之一改變,憑口味調出來的水就會露出接縫。所以這個專案的 根基不是一張功能清單,而是一場人類無法爭辯的驗收測試:一張照片。
以照片為準繩評判,而非以口味
開發被參考照片所門控,它們帶著固定的相機與光照合約——物理光照單位、鎖定的色調映射器,以及一套決定通過或不通過 的感知差異度量,而非美術總監當天的心情。
有兩張參考照片是正典,它們被特意選為對立:
- 一片清澈的湖,相機在水線裡。 一半空氣,一半水,一條起伏的邊界,沒有偽影帶;一片綠色的近岸型水,其顏色隨距離加深;岩石上 與上方水面相符的焦散;水下的原木在介面處正確彎折。這一張同時考驗折射、水線穿越與水下顏色吸收。
- 全陰天下的一段風暴海岸。 沒有太陽,沒有閃光帶——大海必須靠柔和的天空反射、去飽和的灰綠、白冠統計以及崖上的霧靄來被讀出。 一個浮標以可信的週期與傾角騎著湧浪;行為是驗收的一部分,而不只是靜止圖像。
陰天參考被特意選為兩者之一。陽光下的水討好地球上每一個算繪器——高光閃爍掩蓋了眾多罪過。把太陽拿走,水就必須僅憑反射粗糙度、 顏色與運動來撐起整幀。那才是誠實的測試,也正是大多數系統悄悄迴避的那一個。只在陽光下好看的海洋,是不會發售的。
相機一側被指定得和水一側同樣嚴格,因為照片比較只有在相機無法作弊時才公平。這意味著真實的物理光照強度(正午太陽約 100,000 勒克斯, 而非任意的亮度滑桿)、固定的曝光,以及每張參考各自固定的色調映射與泛光設定。改一改色調映射器,任何水都能被做得去匹配任何照片 ——這正是色調映射器要最先被釘死的原因。
Drop-a-Mesh:不做功課也能漂
把任意網格拖到一處 Numivo 水體上,它立刻正確行為——系統自動建構一個物理代理,逐幀從真實波高計算排開體積,並從真實 密度推導漂浮還是下沉。
水下是一處地方,而非後期處理。顏色隨深度吸收,光以光柱濾下,頭頂的介面必須被乾淨地穿越——湖泊參考的存在,就是要把這三者一次性 都保持誠實。
一根原木漂浮並翻到它的長邊。一個箱子起伏。一尊石像下沉。沒有裝配,沒有浮筒擺放,沒有腳本。引擎蓋之下:
- 碰撞形狀被自動體素化——非同步進行,並按資產快取,所以只發生一次——以測量物體的真實體積;
- 浮力每幀被物理計算:排開體積對著水的密度;淡水與鹽水確有不同(鹽水更密,所以同一個箱子在海裡比在湖裡騎得更高);
- 漂浮還是下沉來自密度,質量除以代理體積——預設沒有「這個該漂嗎?」的勾選框,因為預設就是物理;
- 穩定性會湧現:來自代理體積如何分佈。頭重的箱子傾覆,龍骨壓重的船體自行扶正,一塊木板平躺;
- 漂浮物體回耦到水面——漣漪、尾跡、水線處的一圈泡沫,以及撞擊時的濺水效果。
Actor 上有一個用於覆蓋的小面板——強制漂浮、強制下沉、一個阻尼滑桿、尾跡與濺水開關——但覆蓋是縮放物理,而非替換它。強制讓一塊 巨石漂浮,它仍以正確的週期起伏、留下正確的尾跡;它只是表現得彷彿更輕。這個區別很關鍵:忽略求解器的強制結果看起來就像黏在平面上 的道具,玩家一眼就會注意到。
設計目標很直白,而且是一場我們想要能現場演示的 demo:有人把二十個隨機道具拖到海裡,一切就那樣行為起來——之前不打開哪怕一個 設定視窗。若那場 demo 需要教學,這個功能就失敗了。
它涵蓋什麼
近岸水、開闊海洋、水下與洞穴水潭全都是一等公民——基於譜的波,湧浪與交叉浪分離,來自真正破碎的浪的泡沫,驅動水下光柱 的焦散,以及在電影級效果下的穩定性。
若你在乎水,那些要緊的細節:
- 波來自海洋學譜(與描述真實海洋所用的相同統計模型),帶方向性擴散與可獨立控制的湧浪。海況變成一個天氣決定——「正在醞釀的 風暴,來自西方的長湧」——而非三十個互不相干、你一直推到看著像風暴為止的滑桿。
- 泡沫不是一張畫上去的遮罩。 它誕生於浪真正破碎之處,隨時間老化,並在風下拉出條紋。畫上去的泡沫是假水最常見的破綻,因為它 不隨它本該表示的物理一起運動。
- 水下是一處真實的地方。 按深度正確的顏色吸收(紅先走,然後綠,留下人人從潛水影像裡認得的深藍)、由照亮水底的同一焦散場 推導出的光柱,以及水線處一次沒有經典硬偽影帶的穿越。
- 洞穴水潭得到自己的處理——靜止或幾乎不動的水、滴水的擾動、近乎黑暗中的反射——因為一處平靜的室內水潭暴露的失敗與開闊海洋 不同。
- 過場是驗收標準,而非事後想法。 表面必須在景深、運動模糊與底片顆粒之下保持穩定——沒有只在加了顆粒後才出現的高光螢火,沒有 被慢速相機變成頻閃的微光。
為什麼浮力是人人跳過的部分
觀感可以用一個好著色器偽造,但行為不能——令人信服的漂浮與下沉需要一個即時體積估計和一個穩定的求解器,這實實在在地難, 所以大多數系統發一個船預製體就收手。
不那麼舒服的工程真相是:漂亮的水著色器是個已解決的問題,而一個通用的浮力求解器不是。偽造一道波的觀感是紋理與法線的問題;讓一個 任意的、前所未見的網格正確地坐在那道波裡,則是一個必須以幀率執行、熬過快速時間步、並且當一塊千三角形的岩石遇上風暴湧浪時不炸掉的 物理問題。正是這道鴻溝,讓「水」在大多數引擎裡意味著「一塊你沒法互動的漂亮平面」,也讓那個可互動的部分——當它存在時——是一艘手工做的船。
彌合這道鴻溝——讓行為像觀感一樣自動——就是這個專案存在的原因,也是它需要參考照片的紀律外加一個真正的求解器、而非一個週末的著色器 活兒的原因。
你什麼時候能用上?
它作為 Unreal Engine 擴充在開發中,分階段推出——一個運動學的漂浮預覽會先於完整的物理求解器落地,好讓場景能被提早填充。 我們不公布日期;參考影像來決定何時算完成。
分階段是刻意的。一個運動學預覽(物體跟隨波面而不做完整的力模擬)先到,好讓美術能在沉重的求解器仍在加固時丟下網格、填滿一片海—— 你遠在物理定稿之前就能感受到結果。完整的求解器、自動代理與完整面板隨後而來。進展與里程碑出現在公開路線圖上,而不是在 發布當天的驚喜裡。
它將隨之一同發售的工具箱——散布、網格混合、Grids、測量——今天就免費可試。若你想在一個公開水建置出現的那一刻就得到通知,站點上連結的 Discord 就是它會最先被宣布的地方,也是參考影像的通過/不通過對比在發生時被張貼的地方。
迷你 FAQ
它會要求 Numivo 的其他工具嗎? 不會——它是同一家族裡的一個擴充,被設計成獨立成立。不過它共享同一條原則:結果在物理上可能之處 一律烘焙成引擎原生資料,好讓你擁有你所做的東西。
哪些引擎版本? 當前的 Unreal Engine 5 版本。具體細節會隨著擴充接近一個公開建置而落到路線圖上,而不是現在承諾、以後修改。
這與引擎內建的水有何不同? 內建水系統強在觀感、弱在通用互動——浮力通常是一個獨立的、手工調過的元件。這裡的全部要點是,觀感與 行為都來自單一的、有物理根基的系統,而參考照片這道門在各種光照下把觀感保持誠實。
為什麼在發布前就宣布? 因為參考照片這套方法本身就是要點。我們寧願把那道杠公開亮出來、被它衡量,也不願揭曉一個沒人能審視的成品。 這篇文章就是那道杠,白紙黑字——請拿它來要求我們。