遊戲裡的水為什麼看起來像真的

發表時間:2026 年 11 月 02 日 | 更新日期:2026 年 11 月 02 日 | 編輯:雅寶社區編輯團隊
遊戲裡的水為什麼看起來像真的 - 雅寶社區 · 頂客論壇

於是有了 Gerstner 波(又稱擺線波、trochoidal wave)。它的關鍵差別在於:頂點不只上下移動,還會水平移動。當波峰處的質點往浪尖方向擠、波谷處的質點往兩側散,波峰就會被「擠尖」、波谷被「攤平」,形成真實海浪那種上方銳利、下方平緩的剖面。這也是為什麼你在遊戲裡看到的海浪,尖端總是有那麼一點要碎掉的感覺——那是 Gerstner 波的數學本性,不是美術刻意雕的。

實務上,一款遊戲通常會同時跑四到八組不同方向、不同波長、不同速度的 Gerstner 波,稱之為「波譜疊加」。波長長的是大涌浪,波長短的是細碎風浪,疊起來就有層次感。缺點是:這種做法本質上是週期性的,玩久了會看出重複,而且波的數量一多,頂點著色器(vertex shader)的成本就上來了。

2. FFT 海洋:把一整片海交給 GPU 的頻譜

想要真正「一整片海」的規模感,就得請出 FFT 海洋模擬(Fast Fourier Transform Ocean)。這個方法的思路很反直覺:它不在世界空間裡逐點算波,而是在「頻率空間」裡用一張頻譜圖描述這片海有多少能量分佈在哪個波長、哪個方向上,然後用反快速傅立葉轉換,一次把整張高度圖算出來。

這套方法在 2001 年由 Jerry Tessendorf 整理成經典論文《Simulating Ocean Water》,至今仍是 3A 海洋的標準做法之一。它的好處是:

一次運算就能得出數百、數千個波的疊加結果,效能遠優於逐波疊加。

頻譜可以隨風速、風向即時調整,天氣一變,海象立刻跟著變。

高度圖、法線、甚至泡沫遮罩,都可以從同一組頻譜推導出來。

它的問題是「週期性重複」——因為本質上是在一張有限的貼圖上做循環,遠看壯闊,近看會發現同一片浪花每隔幾十公尺就出現一次。所以實務上還會搭配其他手法,例如把不同尺度的 FFT 圖層疊起來、加上世界座標偏移、或在近景另外補細節。

像《盜賊之海》那種偏風格化的水,雖然視覺上不走寫實路線,但底層同樣是靠波形與頻譜撐起整體動態,只是把顏色與泡沫的比例調成卡通感。而《深海迷航》這種以水下為主的作品,則更重視水面的「透光」與水下粒子,波形反而不是重點。

3. 法線貼圖與細節層:小於網格的波紋不用真的建模

再怎麼模擬,網格的解析度終究有限。那些公分級的細碎波紋——風一吹就出現、陽光下閃閃發亮的小鱗片——如果每一個都建模型,顯示卡會直接罷工。

所以這些細節全部交給法線貼圖處理。做法通常是:準備兩到三張無縫的雜訊法線圖,讓它們以不同速度、不同方向卷動(scroll),再疊加起來。因為速度與方向不同,兩層的干涉會讓肉眼覺得圖案永遠不重複,這是遊戲水面最經典的小魔術之一。

更講究的做法會加入 flow map(流向圖),讓波紋沿著預設的流場方向彎曲,而不是呆呆地直線漂移;或是用高度差做出「粗糙度變化」,讓某些區域比較亮、某些區域比較霧,模擬風吹過水面的不規則感。

值得一提的是「時間縮放」。真實的水波頻率有一定的範圍,遊戲如果照真實速度播,遠景的浪會看起來像慢動作。所以多數遊戲會讓大浪放慢、小波加快,這種「不合理但順眼」的調整,是美術與程式一起調出來的手感。

三、讓水「亮」起來:菲涅耳、反射與折射

水面之所以好看,一半以上來自它跟光的互動。這裡有三個核心機制:菲涅耳、反射、折射。

1. 菲涅耳效應:為什麼低頭看水是透明的,遠看是鏡面

你有沒有注意過:站在湖邊低頭看腳下的水,可以看到水底的石头;但抬頭望向遠方湖面,卻只能看到天空的倒影。這個現象叫菲涅耳效應(Fresnel effect)。

物理上,光從空氣進入水時,入射角越小(越接近垂直),穿透的比例越高;入射角越大(越接近掠射),反射的比例越高。在著色器裡,通常用 Schlick 近似式來算:F = F0 + (1 − F0) × (1 − cosθ)⁵,其中水的 F0 大約是 0.02(也就是垂直入射時只有 2% 的光被反射)。

那個五次方是關鍵。它讓反射率在大部分角度都很低,只有在非常接近掠射的角度才急速拉高。這正好對應人類的視覺經驗:水面遠方像鏡子,近處像玻璃。遊戲只要把這個曲線算對,水面的「說服力」立刻上升一個檔次;算錯了,水就會變成一片塑膠膜,遠近都亮得一樣。

2. 反射的實現層級:從立方貼圖到光線追蹤

反射聽起來很簡單,但「要反射什麼」是遊戲效能的無底洞。業界大致有四種做法,成本由低到高:

  • 立方體貼圖(Cubemap):事先烘焙好天空或環境的六面圖,水面直接查表。超便宜,但反射內容是靜態的,旁邊走過的船不會出現在倒影裡。
  • 平面反射(Planar Reflection):把攝影機沿水面對稱翻轉,再渲染一次場景,得到真實倒影。效果好,但等於場景畫兩次,成本翻倍,通常只在大片靜水或主角水面上使用。
  • 螢幕空間反射(SSR):拿已經渲染好的畫面,沿反射方向做射線搜尋。成本中等、效果不錯,但看不到螢幕外的東西,畫面邊緣的反射會憑空消失,而且被遮蔽的物件會反射出錯誤內容。
  • 光線追蹤反射:最準,能正確處理遮擋與離屏物件,但目前仍屬高階顯卡或特定模式的專利。
  • 多數遊戲其實是「混搭」:遠景用 cubemap,近景用 SSR,主角船附近補一次平面反射,然後用 roughness 把不同來源的接縫糊掉。你在遊戲裡看到完美無瑕的倒影,通常是三種技術接力演出的結果。

    3. 折射與深度:水面下的東西為什麼會「錯位」

    折射讓水下的東西看起來位置偏移、比例變形,這是水感的另一大半。遊戲的做法通常是「螢幕空間折射」:把畫面上水下的像素,依照法線方向做 UV 偏移,看起來就像光線被折彎了。

    但這裡有個經典破綻:如果只是無腦偏移,水面邊緣會把岸上的東西也「吸」進水裡,變成诡异的扭曲。所以還需要一張深度圖(depth texture),比較水面深度與水下物件深度,只有在「確實位於水下」的區域才做折射,並且在物體與水面交界處做柔化(soft intersection),模擬水與固體接觸時的薄薄一層過渡。

    這個「水深」資料還能拿来做很多事:水深越深,水下顏色越濃;水深接近零,就開始出現泡沫與透明度變化。可以說,深度圖是整個水面系統的骨架,沒有它,後面所有效果都會穿幫。

    四、讓水有厚度:吸收、散射與水色

    很多人以為水是藍色的,其實純水幾乎無色。海是藍的、湖是綠的、溪是透明的,差別來自「光在水裡走多遠」。

    1. 為什麼海水是藍的,湖水是綠的

    水對不同波長的光吸收率不同。紅光最快被吸收(大約幾公尺就吃掉大半),藍光穿透最遠。所以當水夠深、光走得夠遠,回來的散射光就偏藍。這是海水藍的主因,跟天空倒影只是次要因素。

    湖水偏綠,通常是因為懸浮的藻類與有機物會散射特定波段,加上湖通常較淺、底部泥沙反射,混合出黃綠色。至於高山溪流清澈見底,是因為水太淺,光根本還沒被吸收多少就到底了。

    遊戲要重現這件事,就不能只給水面一個藍色,而是要在著色器裡實作吸收係數(absorption coefficient)與散射係數(scattering coefficient),讓顏色隨「光在水中的行進距離」變化。這套模型通常用 Beer–Lambert 定律描述:光強度隨深度呈指數衰減,而且 RGB 三個通道的衰減率不同。

    實務上,美術會用一張「水色漸層」或體積霧來近似,效能比較友善;講究一點的會直接做單次散射(single scattering)積分。但不論哪種,核心觀念都一樣:水色是「距離的函數」,不是一張固定貼圖。

    2. 浪尖的透光:次表面散射的功勞

    你有沒有注意過,逆光看浪頭時,浪尖會透出一種青綠色的光?那不是反射,而是光穿透薄薄的水體再散射出來,也就是次表面散射(subsurface scattering,SSS)。

    遊戲通常用一個簡單的近似:偵測波峰、偵測逆光角度、給浪尖加一層額外的透光色。成本不高,但效果驚人,因為那是人類判斷「這是一團半透明液體」而不是「一塊藍色塑膠」的關鍵線索之一。

    3. 焦散:水底那層晃動的光網

    焦散(caustics)是光穿過水面後,被波浪的凹凸聚焦,在水底形成的一張會游動的亮網。這是游泳池與淺海最鮮明的視覺記憶。

    早期做法是把一段動畫貼圖投影到水底;進階做法是用螢幕空間的折射方向去扭曲一張預先算好的焦散圖;最高階則是光線追蹤即時計算。不論哪種,它的重點都在「跟水面波形同步」——浪怎麼動,光網就怎麼晃。如果兩者不同步,大腦會立刻察覺「這水是假的」。

    五、讓水有性格:泡沫、互動與濕潤感

    到目前為止,水已經會動、會亮、有顏色了。但距離「像真的」還差最後一哩:它還沒跟世界發生關係。

    1. 泡沫:不是亂撒,是有邏輯的

    泡沫看起來很隨機,其實生成條件相當明確。常見的判定有幾種:

  • 波峰陡度:當波浪的斜率超過臨界值(或者用雅可比行列式判斷壓縮程度),代表水被擠得太厲害,該起白沫了。
  • 深度差:水面與水下物件的距離接近零,代表水碰到岸或礁石,這裡會出現拍岸泡沫。
  • 物件互動:船尾、泳圈、角色涉水的位置,額外注入泡沫遮罩。

  • 風速與時間:泡沫會隨時間衰減,所以需要一個「泡沫生命週期」的緩衝貼圖來記錄哪裡剛起泡、哪裡快消散。
  • 好的泡沫系統會讓白沫「有記憶」:浪打過的地方會留下一層慢慢消退的白,而不是瞬間出現瞬間消失。這個衰減曲線調得好不好,直接決定水看起來是「活的」還是「特效貼上去的」。

    2. 角色涉水與漣漪:即時互動的說服力

    當玩家踩進水裡,水面應該要有一圈一圈擴散的波紋,而且波紋要跟腳步節奏對上。這件事在技術上比想像中麻煩:你不能真的去模擬整片水,只能在水面材質上「寫入」一個扰动。

    常見做法是用 render texture 當作「涟漪地圖」,角色每走一步就往上面畫一個環形扰动,然後水面著色器讀取這張圖來偏移法線。進階一點會用波動方程(wave equation)在 GPU 上做局部傳播,讓涟漪真的會互相干涉、反射。

    《薩爾達傳說:王國之淚》這類作品在這方面就下了不少功夫,漣漪的擴散、衰減、與地形邊界的互動,都讓「踏進水裡」這個動作變得有重量。

    3. 濕潤感:出水之後的那層水膜

    角色從水裡走上岸,衣服會變深、會貼身、會有水珠滴落,地面會留下濕腳印。這些細節跟水面本身無關,卻是「這世界有水」的重要旁證。技術上通常是切換材質參數:降低粗糙度(roughness)、加深基礎色、加上一層隨時間淡出的水膜遮罩。

    同理,岸邊的岩石在浪打過之後會有一層濕亮,過一會才乾掉。這種「事件後的餘韻」,比水面本身更難做,也更難被玩家明確指出來——但少了它,整個場景就會有一種說不出的乾燥感。

    六、後期與鏡頭語言:最後一公里的欺騙

    水面算完之後,其實還沒結束。整個畫面還要經過一輪後期處理(post-processing),而這一步往往決定了「看起來像遊戲」還是「看起來像照片」。

    1. 色調映射與高動態範圍

    真實世界的光強範圍遠超螢幕能顯示的範圍,所以渲染時通常用 HDR(高動態範圍)計算,最後再用色調映射(tone mapping)壓回可顯示範圍。水面的鏡面反射往往是最亮的部分,如果色調映射曲線調得好,那些過曝的亮點會自然滾降成柔和的白色,而不是硬生生的死白方塊。

    再加上泛光(bloom),陽光打在水面上的碎光就會暈開成一種「眼睛被閃到」的感覺。這個效果很容易做過頭,變成整片湖在發光,所以多數遊戲會用亮度閾值搭配多層模糊來控制。

    2. 水下後處理與光束

    玩家潛入水中後,畫面通常會切換成一組水下參數:偏藍綠的色偏、邊緣暗角、體積霧、漂浮粒子,加上從水面射下來的「上帝光束」(god rays)。這些光束多半是螢幕空間的後期效果,用徑向模糊假造,而不是真的做體積光追。

    另外還有鏡頭水珠:角色從水裡冒出來時,螢幕上會有一層水珠與水痕,隨著時間滑落。這個效果完全是在「攝影機」上做的,跟水體本身無關,但它大幅強化了「我剛剛真的在水裡」的沉浸感。這也說明了遊戲水面為什麼這麼難做——它不只是物理,還是攝影與心理學。

    七、效能取捨:為什麼手機的水和主機的水不一樣

    同一款遊戲在不同平台上的水面常常差很多,這不是偷懶,而是取捨。水面是整個場景裡最吃效能的材質之一,因為它同時牽涉頂點運算、像素運算、額外渲染通道(反射)、以及大量透明混疊。

    常見的降級策略包括:

    網格 LOD:遠景水面用低解析度網格,甚至直接改用平面加高度貼圖。

  • 反射降級:手機端通常只用 cubemap 或低解析度 SSR,不做平面反射。
  • 解析度減半:反射與折射的 render target 常常只有畫面的一半甚至四分之一解析度,再放大使用。
  • 簡化波形:用兩三組 Gerstner 波取代整張 FFT,或把 FFT 更新頻率降低。
  • 泡沫簡化:用預先烘焙的泡沫貼圖取代即時計算。

    這也是為什麼技術美術(Technical Artist)在水面專案裡的角色那麼關鍵:他們要在「看起來夠真」與「跑得動」之間找到那條線。很多時候,玩家覺得「這水好真」的那一刻,其實是美術用最便宜的手段,精準地騙到了最關鍵的那個感官。

    八、實戰觀察清單:怎麼判斷一款遊戲的水做得好不好

    如果你想訓練自己對遊戲水面的鑑賞力,可以帶著這份清單去湖邊蹲點:

  • 看遠近反射的過渡:從腳邊往遠方看,反射是否隨著角度自然增強?有沒有突然「跳」成鏡面的接縫?
  • 看折射邊緣:水下物體與水面交界處是否柔和?有沒有把岸上東西吸進水裡的扭曲?
  • 看水深變化:從淺灘走到深水,顏色是否連續變化?還是突然換一張貼圖?

    看泡沫生命週期:浪打過之後,白沫是慢慢消退,還是瞬間消失?

    看互動:角色涉水、船隻移動、下雨時,水面有沒有即時反應?

  • 看逆光浪尖:有沒有那層透光的青綠色?這是 SSS 有沒有做的分水嶺。
  • 看焦散:水下光網的晃動頻率,是否跟水面波形同步?

    對想踏入技術美術或圖形程序的讀者,建議的入門路徑是:先玩 Unity 的 Shader Graph 或 Unreal 的 Material Editor,做一個最簡單的 Gerstner 波加卷動法線;接著加菲涅耳與螢幕空間折射;最後再挑戰 FFT 或 SSR。把這幾塊拼起來,你就會擁有一片「自己的海」。

    九、結語:真正的水,藏在細節的總和裡

    回到最初的問題:遊戲裡的水為什麼看起來像真的?答案不是某一個劃時代的演算法,而是幾十個各自只負責一小塊的技術,被美術與程式細心地調到彼此不打架。波形讓它動得對,法線讓它亮得對,吸收讓它有厚度,泡沫讓它有脾氣,後期讓它有鏡頭感。缺了任何一塊,大腦就會在某一瞬間說「這怪怪的」,即使你說不出哪裡怪。

    所以下次你在遊戲裡看到一片讓你忍不住停下腳步的湖,不妨想想:那片水面底下,可能正跑著一張 FFT 頻譜、三層卷動法線、一次平面反射、還有十幾個參數在被人來回微調。它看起來像真的,是因為有太多人花了太多時間,只為了讓你在那一秒鐘,忘記它其實只是螢幕上的一堆數字。

    而這,大概就是遊戲畫面最浪漫的地方。

    🏠 返回首頁