← 地圖/CH.03 · SHADER_LANG/3.4 — UNIFORM_BUFFER
進度 38%
+50XP 進行中
▸ ACTIVE QUEST · Lesson 03.4 / 03.8

讓著色器
聽見時間。

Uniform buffer 是 CPU 對 GPU 講話的方式。這一節我們會把當前時間送進著色器,讓畫面動起來。

// 完成這節後
+ 通過 Uniform 概念
+ 解鎖時間動畫
+ 50 XP
▸ Lessons (8)
3.1WGSL 是什麼
4 min
3.2Vertex 與 Fragment 函式
6 min
3.3內建型別:vec2f, vec3f, mat4x4
5 min
3.4Uniform Buffer 與資料傳遞
5 min
3.5從 UV 開始畫圖
7 min
3.6結構與屬性 (struct, attributes)
6 min
3.7常用內建函式 (sin, mix, smoothstep)
4 min
3.8挑戰:改造著色器
8 min

# 概念

寫一個著色器,就是寫兩個函式:頂點函式(@vertex)決定形狀,片段函式(@fragment)決定顏色。但如果你只能寫死的形狀和顏色,畫面就不會動。

Uniform buffer 是 CPU 與 GPU 之間的小信箱。每一幀,你在 CPU 把資料(例如:當前時間、滑鼠位置、視窗大小)寫進這個信箱,著色器就能讀到。

⌬ KEY INSIGHT
Uniform 對著色器來說是唯讀的全域變數。同一幀內,所有的頂點 / 片段都看到同樣的值 — 這也是「uniform」這個名字的由來。

# 三步驟

01
宣告
DECLARE
在 WGSL 中宣告 struct 與 @binding
02
建立
CREATE
在 JS 中 createBuffer + createBindGroup
03
寫入
WRITE
每一幀 device.queue.writeBuffer 更新內容

# 在 JS 端

建立一個 16 bytes 的 buffer(一個 vec4 = 4 個 float),並把它綁定到 group 0 / binding 0:

const uniformBuf = device.createBuffer({
  size: 16,                  // time(4) + _pad(4) + res.xy(8)
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});

const bindGroup = device.createBindGroup({
  layout: pipeline.getBindGroupLayout(0),
  entries: [{ binding: 0, resource: { buffer: uniformBuf } }],
});

// every frame:
const t = (performance.now() - startMs) / 1000;
device.queue.writeBuffer(uniformBuf, 0, new Float32Array([
  t, 0, canvas.width, canvas.height,
]));

# 試試看

// 修改左側 WGSL,右側畫面會即時重新編譯
shader.wgslcmd+s · live reload
✓ compiled · 0 errors · pipeline ready
⌬ output buffer
fps
init…

# 練習挑戰

EASY+10 XP
把畫面變成單一漸層
// Replace the sin animation with a static linear gradient
MEDIUM+30 XP
讓圖案以滑鼠位置為中心
// Add mouse uniform & center the pattern there
HARD+60 XP
畫出自己的 plasma 效果
// Combine 3+ sin waves into a plasma pattern
← 3.3 — 內建型別
▸ 下一節 3.5 →