feedback shader 是什麼?
想像你在紙上滴了一滴墨汁,然後用 吹風機 對著它吹。
墨水會沿著風的方向 流動、擴散,邊緣會變得模糊,中間會出現有趣的紋路。
feedback shader 就是那台「數位吹風機」——它每一幀(每秒 60 次)都對你畫的墨跡吹一下,讓墨水自然地動起來。
Shader feedback.frag 的工作方式
每一幀,feedback shader 做三件事:
關鍵的一行程式碼:
// min = 取較暗的那個 → 墨水只會擴散,不會消失
用 min()(取最小值 = 取最暗的)確保墨水 只會擴散,不會無中生有。如果偏移位置有墨水而原位置沒有,墨水就「流」過來了。
📖 更多閱讀:關於將繪畫材質分解為「介質流動」與「顏料擴散」的思路,推薦 kynd 的《Codifying materials》
力場:看不見的風
概念 forceMap — 風向圖
力場(forceMap)是一張跟畫布一樣大的「風向圖」。上面每一個點都記錄了:
- X 方向的風速(往左還是往右吹?吹多強?)
- Y 方向的風速(往上還是往下吹?吹多強?)
想像你在一張大紙上,每個位置都放了一個小風扇。每個風扇朝不同方向、吹不同強度的風。
當你在紙上滴墨水的時候,墨水會被 附近的風扇吹動,往風的方向流動。
這就是為什麼墨水不是均勻地向四面八方擴散,而是會有「方向感」——因為力場決定了風的方向。
力場的風向是用什麼決定的?有兩種來源:
1. 筆觸帶來的力場
你畫畫的時候,滑鼠移動的方向和速度會產生力場。快速往右揮,力場就指向右邊。
2. Flow Effect 力場
如果你開啟了 Flow Effect,程式會用數學噪波產生一個持續變化的力場——像一陣一陣的風。
forceMap 的值 = (0.5, 0.5) → 無風(靜止)
forceMap 的值 = (0.8, 0.5) → 往右吹
forceMap 的值 = (0.2, 0.7) → 往左下吹
// 轉換方式:
實際風力 = (forceMap值 - 0.5) × force × 0.2
噪波入門:隨機的藝術
概念 什麼是噪波(Noise)?
在六種墨水效果裡,你會一直看到「噪波」這個詞。它是所有自然質感的基礎。
想像你從飛機上往下看 山脈地形:
🏔️ 從遠處看,整座山脈有大的起伏(低頻噪波 = 大波浪)
⛰️ 靠近一點,看到山坡上有中等的丘陵(中頻噪波)
🪨 更近看,地面有小石頭和砂礫的細節(高頻噪波 = 小碎波)
把這三種尺度的起伏 疊在一起,就是自然界的地形。
墨水效果也是這樣——把不同頻率的噪波疊加,產生自然的紋路。
程式中用的噪波有兩種:
Hash 噪波(快速隨機)
像擲骰子一樣,給一個座標就吐出一個「看起來隨機」的數字。速度極快,但結果比較「碎」。
// 用三角函數的小數部分產生「假隨機」
用途:顆粒感、斑點、快速噪點
Smooth 噪波(平滑過渡)
不像 hash 那麼碎,而是 鄰近的點會互相影響,產生連續的、山丘般的起伏。
// 結果是柔和的、連續的波浪
用途:雲霧、水漬、纖維紋路、大面積色彩變化
頻率 = 細節程度
噪波的「頻率」控制紋路的大小:
| 頻率 | 效果 | 用在哪 |
|---|---|---|
| 低(2~15 Hz) | 大塊的明暗變化 | 大範圍暈染、雲霧 |
| 中(30~80 Hz) | 中等的紋路 | 纖維、水漬邊緣 |
| 高(100~400 Hz) | 細小的顆粒 | 砂紙質感、炭筆粒子 |
| 超高(400~600 Hz) | 極細的噪點 | 底片顆粒、微細紋路 |
六種墨水效果的差異,很大一部分就是它們 選用了不同頻率的噪波組合。
Mode 0 — 墨汁入水
useSharpen < 0.5
想像你把一滴墨汁滴進一杯水裡。墨汁會慢慢 散開,邊緣變得模糊,整體變得淡淡的。
如果你同時輕輕吹一口氣(力場),墨汁會往某個方向多擴散一點。
Mode 0 是最基本的墨水擴散模式。它做了這些事:
1. 基礎擴散
取原位置和力場偏移位置中 較暗的那個,讓墨水沿力場方向流動。
2. 四方向擴散
不只沿力場方向,還會往上、下、左、右四個方向 加權平均。加權方式考慮:
- 鄰居跟自己的 墨水密度差(差越大 → 擴散越強)
- 方向是否跟力場 同向(同向 → 額外加速)
3. 密度梯度
根據力場方向產生 明暗對比——力場指向的那一側稍微亮一點,背面稍微暗一點。就像真正的墨水被推動時,前端比較薄(淡)、後端比較厚(深)。
4. 邊緣輕微變亮
墨水密度低的地方(邊緣)會稍微提亮,模擬真實墨水在紙上邊緣變淡的效果。
Mode 1 — 炭筆粗紙
useSharpen < 1.5
想像你拿一支 炭筆 在粗糙的水彩紙上畫畫。炭筆碰到紙面凸起的地方會留下痕跡,凹下去的地方就留白。
結果就是充滿 顆粒感 的質地——靠近看每個點都不一樣,遠看又是一整片的色塊。
Mode 1 是顆粒感最強的模式,它的處理方式很特別:
白色筆刷 vs 普通筆刷的分流
Mode 1 會先判斷是不是白色筆刷。如果是白色筆刷,就用 四層 hash 噪波 產生純粒子質感;如果是普通筆刷,則多加了 光暈採樣 和 Laplacian 銳化。
四層顆粒疊加
這是 Mode 1 的招牌效果。程式用四種不同頻率的 hash 噪波,從粗到細疊在一起:
| 層級 | 頻率 | 強度 | 效果 |
|---|---|---|---|
| 粗顆粒 | 25~50 Hz | 0.15 | 大塊的明暗斑點 |
| 中顆粒 | 110~180 Hz | 0.12 | 中等的紋路 |
| 細顆粒 | 320 Hz | 0.10 | 細小的砂粒感 |
| 超細顆粒 | 480~620 Hz | 0.08 | 像底片的微細噪點 |
最後再加一層 smooth 噪波(120 Hz),把一切柔和地混在一起。
光暈 + 銳化(普通筆刷限定)
程式用噪波把畫面分成兩個區域:
- 噪波值 > 0.5 的區域 → 做「光暈」(模糊採樣),讓墨色擴散柔和
- 噪波值 < 0.5 的區域 → 做「銳化」(Laplacian 邊緣增強),讓線條更清晰
這個隨機切換讓同一筆裡有 柔和的部分 也有 銳利的部分,非常像真實的碳筆效果。
Mode 2 — 水彩暈染
useSharpen < 2.5
想像你用 水彩筆 在溼溼的紙上畫一筆。墨水的 邊緣 會特別深(因為水分蒸發時把墨水推到邊緣),中間反而比較淡。
這個現象叫做「邊緣沉積」,是水彩最迷人的特色之一。
Mode 2 的核心就是模擬這個邊緣沉積效果:
1. 邊緣偵測
程式往上下左右四個方向 採樣,看亮度的變化有多大。如果亮度變化劇烈,就代表這裡是 邊緣。
// gradient 越大 = 邊緣越明顯
2. 邊緣變暗、中間變亮
偵測到邊緣之後:
- 邊緣區域 → 變暗(模擬墨水沉積)
- 中間區域 → 稍微變亮(模擬水分帶走了墨水)
白色筆刷和普通筆刷的強度不同——白色筆刷的效果比較輕微。
3. 有機噪波紋路
在邊緣效果之上,再加一層 有機噪波,讓暈染不是均勻的,而是有自然的濃淡變化。噪波的頻率會隨時間(mouseCount)慢慢改變,讓紋路持續「活著」。
4. 流動紋路
最後加一層「流動噪波」——根據隨機方向產生的細微紋路,像水在紙上流動的痕跡。
Mode 3 — 宣紙毛筆
useSharpen < 3.5
想像你在 宣紙 上寫毛筆字。宣紙有明顯的 纖維方向——墨水順著纖維的方向會滲得比較遠,垂直纖維的方向滲得比較短。
結果就是墨跡邊緣呈現出「毛毛的」、有方向性的紋路。
1. 柱狀紋路(Column Texture)
Mode 3 用一個特殊的「柱距離場」函數,產生 垂直方向的纖維紋路:
dist = sdColumn(座標 × 100, 18.0, 20.0)
// 距離柱子越近 → 越暗(模擬纖維)
力場方向也會影響纖維的傾斜角度,讓紋路跟筆觸方向一致。
2. 兩層纖維疊加
粗纖維(40~80 Hz)產生大的纖維束,細纖維(200~400 Hz)產生纖維內部的細微紋路。
兩層疊在一起,就是宣紙那種「粗中有細」的質感。
3. 灰度變化
最後加上三層 smoothNoise(50、100、200 Hz),讓墨色有自然的濃淡不均勻——就像真正在宣紙上寫字,有些地方墨多一點、有些地方墨少一點。
Mode 4 — 高級水彩
useSharpen < 4.5
如果 Mode 0 是「入門水彩」,Mode 4 就是「專業水彩」。它把好幾種水彩特有的現象全部模擬出來:
留白斑點、邊緣沉積、顆粒感、方向性流動——全都有!
核心差異:三樣本位移
Mode 4 不是簡單地把墨水往力場方向推。它在力場方向的基礎上,額外加了兩個偏移方向(用噪波產生的隨機角度)。
然後取三個位置中 最暗的那個,讓擴散更加自然、不規則。
sB2 = texture2D(偏移方向 2)
sB3 = texture2D(偏移方向 3)
結果 = min(sB1, min(sB2, sB3))
// 三取一,結果更豐富、更不規則
白點留白
用三層噪波(2 Hz + 50 Hz + 400 Hz)產生「留白斑點」——墨水中隨機出現白色的小洞,像水彩紙的紋路讓墨水沒辦法完全覆蓋。
邊緣沉積 + 四層顆粒
如果偵測到有新的筆觸正在畫(力場強度足夠),就會啟動:
- 邊緣偵測 → 邊緣變暗(同 Mode 2 的原理)
- 四層 hash 顆粒(同 Mode 1 的原理)
- 有機噪波 + 流動紋路(同 Mode 2 的原理)
Mode 4 可以說是 集合了前面三種模式的精華!
力場強度調節
Mode 4 有一個獨特的機制:它會根據力場的 實際強度 來調整效果的強弱。
力場弱 → 效果輕微(只有 30%)
力場強 → 效果完整(最高 150%)
這讓你用力畫的時候效果最明顯,輕輕畫的時候效果很淡——非常自然。
Mode 5 — 慢暈水彩
useSharpen < 5.5
Mode 5 就像 Mode 4 的「慢動作版」。想像你把水彩顏料滴在很厚的紙上——墨水慢慢地、慢慢地滲透,每一步都很細膩。
跟 Mode 4 的差異
| 項目 | Mode 4 | Mode 5 |
|---|---|---|
| 擴散速度 | 正常 | × 0.3(慢三倍) |
| 質感強度 | × 1.0 | × 2.0(白色筆刷加倍) |
| 時間計算 | mouseCount(循環) | 累積 mouseCount(不循環) |
技術重點:為什麼要用「累積 mouseCount」?
原本的 mouseCount 每 40 幀會 循環歸零(39 → 0)。在 Mode 4 中這不太明顯,但在 Mode 5 因為擴散很慢,循環歸零的瞬間會造成 紋路突然跳一下(因為時間噪波的輸入值突然改變)。
解決方式:使用「累積的 mouseCount」(mouseCountAccumulated),它只會一直往上加,不會歸零。這樣時間噪波的變化就是 平滑、連續的。
六種模式對照總表
| Mode | UI 名稱 | 核心技術 | 特色 | 適合畫什麼 |
|---|---|---|---|---|
| 0 | 飛白 | 方向擴散 + 密度梯度 | 最基礎的墨水擴散 | 潑墨、抽象 |
| 1 | 擠壓 | 四層 hash 顆粒 + 光暈/銳化 | 顆粒感最強 | 炭筆素描、粉彩 |
| 2 | 麥克筆 | 邊緣偵測 + 明暗偏移 | 邊深中淡的水彩感 | 水彩人像、風景 |
| 3 | 鹽巴 | 柱距離場 + 方向纖維 | 纖維紋路、方向性 | 書法、水墨畫 |
| 4 | 暈染 | 三樣本位移 + 白點 + 全套效果 | 最豐富、最自然 | 專業水彩、插畫 |
| 5 | 毛 | 同 4 但速度 ×0.3 | 慢速細膩、持續演化 | 細膩暈染、背景 |
邊緣沉積效果
Shader applyEdgeEffect — 共用的邊緣處理函數
除了 Mode 2 自己做邊緣偵測以外,feedback shader 還有一個 通用的邊緣沉積函數,可以被任何模式調用。
這個函數就像一個「邊緣加強器」——它會找到墨跡的邊緣,然後讓邊緣 變得更暗。
就像水彩乾了之後,邊緣那圈深色的痕跡。
它的工作流程:
Step 1:空間遮罩(40% 覆蓋)
用噪波決定哪些區域有邊緣效果、哪些沒有。只有約 40% 的區域 會被影響,讓效果更自然而不是整圈都暗。
Step 2:邊緣偵測
往四個方向採樣(採樣距離 1.5~2.3 像素,帶隨機變化),計算亮度梯度。梯度超過門檻值的地方就是邊緣。
Step 3:只在最強邊緣作用
用 smoothstep(0.85, 0.95, edgeMask) 確保只在 最明顯的邊緣 才加深,中間的墨色完全不受影響。
Step 4:向黑色混合
最後把邊緣的顏色往黑色方向混合(變暗量 0.3~0.7),產生深色的邊緣沉積效果。
InkField 教學系列 — 墨水效果全圖鑑