作品概述
InkField 將繪畫從「圖像」轉回「行為」。
在這個系統中,每一次筆觸的路徑、速度與方向都被完整記錄,使繪畫成為一段可被保存與重新演算的時間結構。
這些運動資料被送入筆刷與墨水的生成系統之中。畫面因此不再只是被回放,而是在既有軌跡上持續生成。墨水的暈染、顆粒與飛白會因隨機種子的微小差異而改變,使每一次重現都保持細微的偏移。
作品既是紀錄,也是系統。
它保存了藝術家身體運動的痕跡,同時允許演算法在同一條路徑上不斷生成新的變化。
在影像生成日益自動化的時代,InkField 將注意力重新放回創作中的「意圖」。
那些短暫存在於手與大腦之間的停頓、轉折與節奏,被轉化為可以被觀看與分析的資料。
繪畫因此不再只是靜止的結果,而是一段持續流動的時間。
技術管線
整個繪畫管線由 10 支 GLSL 著色器與 27 個離屏緩衝區組成:
→ typeMapEncode.frag(逐像素記錄筆刷類型)
→ feedback.frag(6 種墨水物理模式)
→ flow.frag(8 種噪聲混合算法)
→ composite.frag(讀取 typeMap 判斷筆刷身份)
→ distort.frag(FBM / 共振波 / 細胞紋理 / 白點 / 顆粒)
→ 螢幕輸出
技術規模
| 項目 | 數值 |
|---|---|
| JavaScript | 10,871 行(5 個核心模組) |
| GLSL 著色器 | 2,775 行(10 支自訂著色器) |
| 緩衝區 | 14 個 Framebuffer + 13 個 createGraphics |
| WebGL Context | 3 個(從最初的 16 個優化而來) |
| 技術棧 | p5.js、WebGL、GLSL、p5.easycam |
| 部署 | 可打包為 index.html + script.js + shader.js |
筆刷系統 — 7 種模式與彈簧力學
物理模型
筆刷移動以彈簧力學模型(spring force + damping)模擬毛筆的慣性與彈性。滑鼠位置作為目標點,筆頭經由加速度插值追蹤,產生自然的延遲與回彈。
| 模式 | 名稱 | 特性 |
|---|---|---|
| 1 | 毛筆 | 帶噴灑變化的書法筆觸,力道控制墨色深淺 |
| 2 | 麥克筆 | 硬邊方塊筆刷,適合大面積塊面表現 |
| 3 | 噴漆 | 液態流動效果,墨跡帶有動態延展 |
| 4 | 枯筆 | 噪聲驅動的線寬變化,模擬技術筆繪圖 |
| 5 | 噴灑點 | 點狀飛濺效果,密度隨筆速變化 |
| 6 | 刷筆 | 逐幀動畫的進階書法筆刷(flyBrushOnBuffer) |
| 7 | 毛邊筆刷 | 不帶噴灑的精細筆觸,線條乾淨俐落 |
其他參數
- 筆刷大小:7 級預設(0.1 / 0.25 / 0.5 / 1 / 2 / 3 / 5 倍基礎值)
- 路徑旋轉:無旋轉 / 5-10° 隨機 / 10-25° 隨機
- 混合模式:Mix(線性混合)/ Multiply(加深)/ Darken(最暗值)
- 色彩選擇:35 色預設色板(7×5 格局)+ 自訂顏色
墨水擴散效果 — feedback.frag 的 6 種模式
Shader feedback.frag — 回饋擴散
每一幀畫面更新時,feedback shader 對 newBufferBlack 進行物理擴散模擬。它讀取「力場地圖」(forceMap)上每個點的方向和大小,將墨水往該方向推移,模擬真實墨水在紙上的自然流動。
| 模式 | 名稱 | 效果 | 感覺像什麼 |
|---|---|---|---|
| Mode 0 | MIX 基礎混合 | 大範圍擴散 + 模糊 | 墨汁掉進水裡 |
| Mode 1 | SHARP 銳化 | 顆粒質感 + 光暈 | 炭筆在粗糙紙上 |
| Mode 2 | FLYING 飛白 | 多尺度噪聲驅動的乾筆效果 | 宣紙上的飛白書法 |
| Mode 3 | WET 暈染 | 水彩般的滲透與暈開 | 水彩暈染 |
| Mode 4 | SALT 鹽巴 | 模擬撒鹽產生的結晶紋理 | 高級水彩撒鹽技法 |
| Mode 5 | HAIR 慢暈 | 帶方向性條紋的緩慢擴散 | 慢慢暈開的水墨 |
你放開滑鼠後,墨水還會繼續擴散一小段時間(力道漸漸減弱到零),模擬真實墨水的「餘韻」。
流場變形系統 — flow.frag 的 8 種混合算法
Shader flow.frag — 流場變形
長按觸發的流場效果以 Perlin/Simplex 噪聲為基底,疊加不同的混合算法,將靜態筆觸轉化為動態的有機形態。每種 blendType 產生截然不同的視覺風格。
| Type | 符號 | 名稱 | 效果 |
|---|---|---|---|
| 0 | ~ | 基礎波形 | Perlin/Simplex 噪聲位移 |
| 2 | ◎ | 同心漣漪 | 從中心擴散的圓環波紋 |
| 3 | ‖ | 垂直波動 | 垂直方向的波浪位移 |
| 4 | ≡ | 水平位移 | 水平方向的波浪位移 |
| 5 | ✿ | 龜裂花紋 | 細胞/龜裂紋理圖案 |
| 6 | □ | 馬賽克碎片 | 方塊碎裂的鑲嵌效果 |
| 7 | 🌀 | 漩渦 | 向中心捲入的螺旋 |
| 8 | ◇ | 細胞紋理 | 有機細胞狀的變形 |
關鍵功能:「僅最後一筆」模式
開啟 Last Stroke Only 後,流場效果只作用於最新一筆筆觸,不影響已有筆跡。
技術上需要在 GPU 層面同步位移 TypeMap 身份緩衝區,確保筆刷類型資訊不因變形而錯位——流場的 typeMap pass 使用相同的噪聲偏移量,讓身份跟隨顏色一起移動。
金屬蝕刻效果 — scanAndMarkDarkPoints
JS metallic.js — 蟲咬蝕刻模擬
模擬傳統版畫中的蟲咬(bug bite)蝕刻技法:系統掃描畫面暗部像素,以加權隨機選取 10 個目標點,在其上生成程序化的有機形狀。
觸發模式
- GLOBAL:掃描整張畫布
- EACH:逐筆掃描新筆觸
- RANDOM:隨機觸發
- EACHR:逐筆掃描 + 隨機強度
| Shape Type | 名稱 | 形態 |
|---|---|---|
| C | Circle 圓形 | 圓形穿孔 |
| RE | Rectangle 矩形 | 方形切口 |
| LE | Lightning 閃電 | 小型鋸齒裂紋(回放時放大 1.3 倍確保可見) |
| BE | Big Lightning 大閃電 | 大型分支狀裂紋 |
材質預設
6 種金屬材質:金 Gold / 銀 Silver / 銅 Copper / 玫瑰金 Rose / 黑鐵 Black / 鑽石 Diamond。透過 metallic.frag 著色器模擬材質光澤和顏色。
錄製與回放系統 — 確定性重現
JS recording.js — 事件錄製
完整的事件錄製系統將每一個滑鼠位置、時間戳、筆刷參數編碼為 JSON。配合自製的 crandom 種子隨機數包裝器(js/crandom.js),追蹤每一次 random() 呼叫的計數,實現近乎 100% 的回放一致性。
錄製功能
- 事件導向的 JSON 捕捉(每筆觸 35+ 欄位)
- 自動壓縮停頓時間(跳過繪畫間的等待)
- 蟲咬效果的 targetPoints 直接錄入事件資料,消除回放時像素掃描的不確定性
- 回放路徑保留與錄製相同的距離檢查(minDistance),確保 bite 數量一致
回放功能
- 完整筆觸重建(保留原始物理參數)
- 自動循環播放(可設定等待時間)
- 播放偏移(X/Y 平移)
- 進度條百分比顯示
- 支援 JSON 匯入/貼上(Agent JSON Panel)
一致性保障:crandom 系統
crandom(js/crandom.js)包裝 p5.js 的 random(),為每次呼叫計數。回放時透過比對 randomCount 驗證 PRNG 序列是否對齊。
關鍵設計:shapeSeed = floor(target.x × 1000 + target.y × 333 + shapeSeedRand)——形狀由目標位置決定。generateOrganicShape 內部呼叫 randomSeed(seed) 重置 PRNG,確保相同 seed 產生相同形狀。
雙模式設計 — 創作者 vs 收藏者
創作者模式(Artist Mode)
完整的三面板 UI:
- Art System Log(📋):錄製、回放、開關面板(Paper / Grid / Camera / Loop / Distort / fBM / RS / Cellular / WhiteDot / Grain / Path / Fit)
- Brush Control(🖌️):筆刷模式 1-7、墨水效果 0-5、筆刷大小、路徑旋轉、混合模式、35 色色板
- Effect Control(✨):蟲咬觸發模式、金屬材質、流場效果按鈕 + 強度滑桿
所有面板可拖曳移動,位置存於 localStorage。點擊任何面板自動提到最上層。
收藏者模式(Collector Mode)
純粹的動態展演裝置——隱藏所有介面,自動載入作品 JSON 並循環播放。
- 自動載入
/lib/demo.json - URL hash 切換作品:
#1、#2、#3→ 載入/lib/1.json、/lib/2.json… - 畫布尺寸從 JSON 同步
- 自動循環開啟
URL 參數系統
格式:?_panel1:value_panel2:value_...
?_artist:1 // 強制開啟創作者模式
#1, #2, #3 // 收藏者模式載入指定作品
渲染管線速覽
想像你在美術課畫水彩畫:
第一步 — 你拿鉛筆在一張 白紙 上畫草稿(深淺代表力道大小)。
第二步 — 老師幫你用吹風機吹一吹,讓墨水自然擴散、有水彩的感覺。
第三步 — 草稿完成後,你用 特殊密碼 把草稿翻譯成一個「編碼版本」,存進保險箱。
第四步 — 每次要展示作品,機器從保險箱讀出編碼,解碼 成漂亮的顏色,貼在有紋路的紙上。
第五步 — 最後灑上一點特效(扭曲、顆粒),完成!
以下是每個階段涉及的 Shader 與 Buffer,以及對應的詳細教學:
| 階段 | Shader / Buffer | 做什麼 | 詳細教學 |
|---|---|---|---|
| ① 黑白草稿 | newBufferBlack | 筆刷在白紙上留下灰度痕跡,深淺代表力道 | 顏色的旅程 → |
| ② 墨水擴散 | feedback.frag | 每幀讀取力場地圖,讓墨水自然流動擴散 | 墨水效果全圖鑑 → |
| ③ 編碼存檔 | encode.frag | 將灰度草稿翻譯為顏色編碼,存入 finalBuffer | 顏色的旅程 → |
| ③b 身份記錄 | typeMapEncode.frag | 同步寫入筆刷類型到獨立的 typeMapBuffer | 顏色的旅程 → |
| ④ 解碼合成 | composite.frag | 查身份證 → 選混合模式 → 疊上紙張紋理 | 混色與力場 → |
| ⑤ 即時預覽 | realtime.frag | 繪畫進行中的即時顏色預覽 | 顏色的旅程 → |
| ⑥ 後處理特效 | distort.frag | FBM 扭曲 / 漣漪 / 細胞紋理 / 白點 / 顆粒 | 特效工廠 → |
完整流程圖
從你按下滑鼠到看到畫面,整個流程如下:
Buffer 總覽表
程式裡有很多「畫布」(Buffer),每一個負責不同的事。可以想成 美術教室裡的不同桌子,每張桌子放不同的東西:
| Buffer 名稱 | 功能 | 比喻 |
|---|---|---|
| newBufferBlack | 正在畫的黑白草稿 | 你面前的白紙 |
| pingPongBuffer | feedback 擴散的暫存區(專用) | 吹風機旁邊的臨時托盤 |
| finalBuffer | 所有筆觸的「編碼」版本 | 保險箱(密碼本) |
| typeMapBuffer | 每個像素的筆刷身份(R=類型, G=白色不透明度) | 身份證本 |
| oldBuffer | 所有筆觸的灰度疊加 | 備份影印本 |
| screenBuffer | 合成 + 即時預覽的工作區 | 展示桌(可以擦掉重來) |
| realtimeIntermediateBuffer | composite → realtime 的中間拷貝(避免同一 FBO 同時讀寫) | 展示桌的影印版 |
| paperTextureBuffer | 有紋路的背景紙 | 畫室裡的好紙 |
| lastStrokeBuffer | 最後一筆的快照(flow 效果用) | 最後一筆的照片 |
| img(forceMap) | 力場地圖,驅動 feedback 擴散方向 | 風向圖 |
| finalOut | 最終輸出(加了特效的) | 裱框好的作品 |
| cursorBuffer | 游標和路徑預覽(已遷移為 framebuffer) | 玻璃板上的標記 |
技術細節:createFramebuffer
所有需要 shader 處理的 buffer(以及 cursorBuffer)都使用 p5.js 的 createFramebuffer() 建立。
這跟早期的 createGraphics(WEBGL) 不同 —— framebuffer 共享主畫布的 WebGL context,
不會建立額外的 GL context。Safari 對 GL context 數量有嚴格限制,使用 framebuffer 讓效能從 ~10 FPS 恢復到流暢。
原本的 16 個 WebGL context 已減至 3 個(主 canvas + 2 個 UI/debug overlay)。只有 P2D blur buffer 和 setup-time 紋理仍使用 createGraphics。
教學系列 — 深入閱讀
以上章節是功能摘要與管線速覽。以下是各主題的完整教學文章:
InkField 墨域 — 技術文件
首頁整理:2026-03-10(精簡重複內容,重構為 Hub 導覽架構)