Skip to content

滤镜

序列化类型里带有 FilterAttributes 的节点 — 当前为 rectellipsepathiconfont,以及可在 ref 实例上覆盖的对应字段 — 支持 filter 字符串,语义上接近浏览器 CSS filter。引擎把字符串解析为内部效果列表,在需要时对图形的包围盒做光栅化,再执行 GPU 后处理。

渲染管线与渲染图的整体说明见 课程 30 - 后处理与渲染图

节点上的 filter

与填充、描边一样写在序列化节点上;多个函数可写在同一字符串里,以空白分隔,顺序即应用顺序。

示例:

ts
api.updateNodes([
    {
        ...node,
        filter: 'blur(4px) brightness(-0.1)',
    },
]);

下文各小节未列出的函数名不会被 parseEffect 识别(无对应分支)。权威实现:@infinite-canvas-tutorial/ecsparseEffect / formatFilterutils/filter.ts)。

当前支持的 filter 函数

每个 ### 对应 filter 字符串里的函数名内部类型Effect['type'](与函数名不同时会标明)。除另有说明外,逗号列表均按逗号分割、trim 后按下标取值(见 filter.ts 各分支)。

formatFilter 回写:仅已实现序列化的效果会写回;仅饱和度的 adjustmentsaturate(…),其余 adjustment 字段会被省略

blur

字段解析来源默认 / 限制
内部类型blur
value对括号内整体 parseFloat(如 4px4非有限值在后续 GPU 路径可能被处理;建议写有限数值与 px

示例: blur(6px)

brightness

字段解析来源默认 / 限制
内部类型brightness
valueparseFloat(params.trim()) 后经 clampGlfxBrightness钳制到 [-1, 1]0 为不变;不是 CSS brightness() 倍数(见 clampGlfxBrightness 上方注释)。

示例: brightness(-0.15)

contrast

字段解析来源默认 / 限制
内部类型contrast
valueparseFloat + clampGlfxContrast先按 brightness 同类钳制,正分支再限制 ≤ 0.999,避免 shader 中 (1 - contrast) → 0

示例: contrast(0.2)

saturate

字段解析来源默认 / 限制
内部类型adjustment(与 ADJUSTMENT_DEFAULTS 合并)
saturationparseCssFilterScalar若以 % 结尾则 parseFloat / 100,否则直接 parseFloat。其余通道保持默认(gammacontrastbrightness、RGB、alpha 均为 1)。

示例: saturate(1.2)saturate(50%) → 饱和度字段 0.5

hue-rotate

字段解析来源默认 / 限制
内部类型hueSaturation
huedegreesToGlfxHue(parseHueRotateDegrees)支持 deg / rad / turn / grad 子串,否则按解析;映射到 glfx 色相 [-1, 1](±1 ≈ ±180°)。
saturation单独写 hue-rotate 时恒为 0(饱和度由 saturate() 另条 token 提供)。

示例: hue-rotate(90deg)

drop-shadow

空白切分;前导连续可 parseFloat 的片段为数值(5px 可解析);其后全部拼成 color(缺省为 black)。

字段来源说明
x, y, blur, spread第 1 ~ 4 个数值 token缺省尾部数值视为 0
color最后一个数值 token 之后的所有 token可为 rgb(...) 等多词颜色

示例: drop-shadow(2px 4px 6px red)drop-shadow(1px 1px 2px 3px rgba(0,0,0,.4))

noise

字段解析来源说明
内部类型noise
value对整体 parseFloat单一标量

pixelate

字段解析来源说明
内部类型pixelate
sizeparsePixelBlockSize去掉 px(大小写不敏感)后 parseFloat;非有限或 ≤ 0 时默认为 1

示例: pixelate(12px)

dot

逗号分隔。缺省项用解析器内建默认并通过 parseFloat / > 0.5 处理灰度开关。

下标属性默认
0scale1
1angle(弧度)5
2grayscale缺省等价 1 → 解析为 1(灰度半调)

示例: dot(1, 5, 1)

color-halftone

分支参数 → 字段
4 个及以上数值(centerX, centerY, angle, size)size 必须 > 0 否则回落为 4
2 个数值(size, angle),无中心(GPU 用上传时纹理中心)
1 个数值(size)angle 默认 0

angle 在效果对象上为弧度size 为点径像素(GPU:scale = π / size,对齐 glfx)。

halftone-dots

逗号分隔,下标对应 HalftoneDotsEffect,默认值见 HALFTONE_DOTS_DEFAULTS

下标属性解析说明
0size钳制 0–1
1radius0–2
2contrast0–1
3gridhex / 11;否则数值 > 0.51(六方格),否则 0(方格)
4dotStyleclassic / gooey / holes / soft 或整数 0–3
5originalColorsfalse/0/nofalsetrue/1/yestrue;否则数值 > 0.5true

fluted-glass

内部类型: flutedGlass17 个逗号分隔数值,均 parseFloat,非有限则用 FLUTED_GLASS_DEFAULTS

下标属性默认GPU 侧(简述)
0size0.50–1
1shadows0.60–1
2angle(度)450–180
3stretch0.20–1
4shape1整数 1–5GlassGridShapes
5distortion0.50–1
6highlights0.40–1
7distortionShape1整数 1–5GlassDistortionShapes
8shift0-1–1
9blur0.150–1
10edges0.30–1
1114四边 margin*00–1
15grainMixer00–1
16grainOverlay00–1

tsunami

内部类型: tsunami11 个数值 → TSUNAMI_DEFAULTSstripeCount 在 GPU 路径钳 1–256stripeAngle,转弧度且 ±180°blend> 0.51 否则 0drift[-1, 1]

下标属性默认
0stripeCount45
1stripeAngle(度)0
2distortion0.32
3reflection0.17
4disturbance0.03
5contortion0.13
6blend0
7dispersion0.22
8drift0
9shadowIntensity0.5
10offset0

burn

内部类型: burn0–4 为数值;颜色与布尔:

下标属性规则
0burn默认 0.5,GPU 钳 0–1
1density默认 1,GPU 最小 0.01
2softness默认 0.2
3dispersion默认 0.1
4distortion默认 0.3
5edgeColorCSS 颜色;parts.length ≥ 7 时读取
6maskColorCSS 颜色;parts.length ≥ 7 时读取
7invertMask若存在:parseFloat > 0.5
8transparent若存在:parseFloat > 0.5

crt

内部类型: crt。设 n = parts.lengthtimeIdx = n >= 11 ? 7 : 4timeIdx 处为 auto/engine(忽略大小写)则 useEngineTime: true,否则为数值 time

下标属性默认(CRT_DEFAULTS
0curvature1
1lineWidth1(GPU ≥ 0
2lineContrast0.25
3verticalLine0> 0.5 为竖向扫描线)
timeIdxtime / 引擎0 或引擎时钟

布局: 5 段时时间在索引 411 段及以上为旧 Pixi 布局,时间在索引 7

vignette

内部类型: vignette。两个数值;GPU 将 sizeamount 钳到 [0, 1]

下标属性默认
0size0.5
1amount0.5

ascii

内部类型: ascii

下标属性规则
0sizeparseFloat,GPU 限制在 1..min(纹理宽, 纹理高)
1replaceColor若存在:parseFloat > 0.5
2+color从索引 2 起逗号拼接;默认 #ffffff

glitch

内部类型: glitch。与 formatFilter 一致,逗号顺序为 jitterrgbSplittimeblocks

下标属性规则
0jitter缺省默认 0.17
1rgbSplit缺省默认 0.24
2time / 引擎parts.length < 3useEngineTime: true;否则 auto/engine 为引擎时间,否则为数值 time
3blocks仅当 parts.length ≥ 4 时读取,否则默认 0.2

liquid-glass

内部类型: liquidGlass17 个数值 → LIQUID_GLASS_DEFAULTS

下标属性默认
0powerFactor4
1fPower3
2noise0.1
3glowWeight0.3
4glowBias0
5glowEdge00.06
6glowEdge10
710a, b, c, d0.7, 2.3, 5.2, 6.9
11centerX0.5
12centerY0.5
13scaleX1
14scaleY1
15ellipseSizeX1
16ellipseSizeY1

liquid-metal

内部类型: liquidMetal0–7 为数值;索引 7shape 取整后限制 0–4

下标属性规则
8useImageparts.length > 8 时:parseFloat(parts[8]) > 0.5
9colorBacklength === 10≥ 11 时读字符串
10colorTintlength ≥ 11
11time / 引擎length ≥ 12auto/engineuseEngineTime;否则数值。若 < 12 且默认 useEngineTime 为真则走引擎时间
12usePoissonparts.length > 12parseFloat > 0.5

默认:repetition 2(GPU 1–10)、shape 3colorBack transparentcolorTint #ffffff,默认对象里 useEngineTime: true

heat-map / heatmap

内部类型: heatmapheat-mapheatmap 同一分支。

下标属性规则
04contour, angle, noise, innerGlow, outerGlow数值 / 默认
5useImageparts.length > 5
6usePreprocessparts.length > 6
7time / 引擎parts.length > 7auto/engine 或数值
8colorBackparts.length > 8
917colors[]至多 9 个渐变色段(循环 c < 18

默认渐变见 HEATMAP_DEFAULTS.colors(7 档)。

gem-smoke / gemSmoke

内部类型: gemSmoke0–6 数值;7shape,取整 0–4

下标属性规则
8useImageparts.length > 8
9usePoissonparts.length > 9
10time / 引擎parts.length > 10
11colorBackparts.length > 11
12colorInnerparts.length > 12
1318colors[]至多 6 个颜色(c < 13 + 6

lut / LUT

内部类型: lut。由 parseLutFilterParams 解析:

形式lutKeystrength
lut(url("…"), 0.5)引号内路径闭括号后首段逗号内容,钳 [0, 1],缺省 1
lut(name("…"), 1)name() 内名称同上
lut(fuji, 1)匹配 ^[a-zA-Z_][a-zA-Z0-9_-]*$ 的标识符第二段
lut("key", 1)首段引号内字符串第二段

注册与采样见 三维 LUT

fxaa

内部类型: fxaa。无参即可:fxaa();解析器不依赖括号内内容。

解析与格式化

编写工具或迁移存量数据时可用:

ts
import { parseEffect, formatFilter } from '@infinite-canvas-tutorial/ecs';

const effects = parseEffect('blur(2px) lut(fuji, 0.65)');
const again = formatFilter(effects);
  • parseEffect(filter: string) 返回类型化的 Effect[](缺省或无效时为空数组)。
  • formatFilter(effects: Effect[]) 再序列化为 filter 字符串;LUT 段在 key 不是简单标识符时会保留为 lut(url("…"), strength) 形式。

三维 LUT(.cube

lut(…) 段使用三维颜色立方体做调色,采样与 three.js LUTPass 一致(半像素内缩与 intensity 混合)。

对每个 WebGPU Device 与逻辑名注册一次 .cube 文本:

ts
import { registerCubeLutFromText } from '@infinite-canvas-tutorial/ecs';

const text = await fetch('/luts/grade_sRGB.cube').then((r) => r.text());
registerCubeLutFromText(device, 'fuji', text);

节点上引用:

ts
filter: 'lut(fuji, 1)',

解析器支持的 key 写法还包括:

  • 命名:lut(myKey, 0.8) — 必须与 registerCubeLutFromTextlutKey 一致。
  • URL 形式:lut(url("./grade.cube"), 1) — key 为 url("…") 内的路径字符串(仍需用同一字符串作为 key 完成注册)。

可用 listRegisteredCubeLutKeys(device) 查看当前已注册的 key;未注册时运行时会针对每个缺失 key 在控制台输出一次性警告。

RegisterCubeLutOptions.atlasFormat'u8' | 'f16' | 'f32')可选,用于控制 GPU 体积纹理像素格式,便于 HDR 或宽 DOMAIN 的 cube。

引擎时间动画

部分滤镜(如 crtglitch)会读取引擎时间做动画。包内导出 filterStringUsesEngineTimeCrtfilterStringUsesEngineTimeGlitchfilterStringUsesEngineTimePost,可在导出前判断。视频导出见 导出图片 中的 WEBM / GIF 参数。

Released under the MIT License.