Files
mantle-ai-trader/skills/web-shader-extractor/references/shaders-com.md
2026-06-06 05:21:10 +00:00

191 lines
6.7 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# shaders.com 提取工作流
shaders.com 是一个 shader 设计工具,使用 Nuxt.js + Three.js r183 TSL + Supabase。
## 识别特征
- URL: `shaders.com/collection/{slug}/{presetId}``shaders.com/preset/{id}`
- Canvas: `data-renderer="shaders"` + `data-engine="three.js r183"`
- Nuxt.js (`_nuxt/` 路径)
- Clerk 认证
- Supabase 存储 (`data.shaders.com/storage/v1/`)
## 关键架构差异
与 Unicorn Studio 完全不同:
- **不使用 GLSL** — 使用 Three.js TSL (Three Shader Language) 节点系统
- **87 种组件类型** — 每种有自己的 TSL `fragmentNode` 函数
- **定义数据是 XOR + base64 编码的**
- **组件可嵌套** — 树形结构Glass 的 children 是其内部效果)
## 数据获取
### API 端点
```bash
# 集合变体(含编码定义)— 公开,无需认证
curl -s "https://shaders.com/api/collections/{slug}/{variantId}"
# 预览 API含编码定义 + 水印注入)
curl -s "https://shaders.com/api/preview/preset/{presetId}"
# Nuxt payload只含元数据不含 shader 定义)
curl -s "https://shaders.com/collection/{slug}/{id}/_payload.json"
```
### 定义解码
定义使用 XOR + base64 编码,有两套密钥:
1. **网站 API**`/api/collections/`
- 混淆密钥: `a5e7244ad0973f07e10285bfa75ddbe4`(来自 Nuxt runtime config
- 组件/属性名用短代码(`C52`=Plasma, `p06`=angle, 等)
- 解码: `JSON.parse(XOR(base64decode(encoded), keyBytes))`
- 然后需要 code→name 映射表还原可读名称
2. **预览 API**`/api/preview/`
- 密钥: `shaders-preview-key`
- 使用人类可读属性名(无需映射)
- 注意:会注入水印 `ImageTexture` 组件
### 代码映射表
87 种组件按字母排序编号 `C00-C86`233 种属性按字母排序编号 `p00-p232`
映射表可从 JS bundle 中提取。
## 已知陷阱
### Y 轴翻转(反复出现!)
**SDF 纹理和 UV 坐标系统性 Y 翻转** — 已在多次提取中确认:
shaders.com 的 SDF 二进制(`.bin`)使用**图像坐标系**Y=0 在顶部),
而 WebGL 纹理坐标 Y=0 在底部。直接加载会导致形状上下翻转。
```glsl
// 错误:直接用 shapeUV 采样
float sdf = texture(tSDF, shapeUV).r;
// 正确:翻转 Y
vec2 sdfUV = vec2(shapeUV.x, 1.0 - shapeUV.y);
float sdf = texture(tSDF, sdfUV).r;
// 注意:梯度的 Y 分量也需要取反
float dSdy = -(texture(tSDF, sdfUV - vec2(0, eps)).r - sdf) / eps;
```
同样,组件定义中的 `center.y` 使用 DOM 坐标Y=0 在顶部),
在 Glass shader 中需要翻转:`center.y = 1.0 - center.y`
### SDF 二进制格式
- 格式512×512 Float32 单通道1,048,576 bytes = 512² × 4
- 值域:有符号距离,负值=内部,正值=外部(如 [-0.065, 0.486]
- **不需要重映射**(不要做 `*2-1`),直接使用原始值
- 需要 `OES_texture_float_linear` 扩展做线性过滤
- WebGL2 加载:`gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, 512, 512, 0, gl.RED, gl.FLOAT, data)`
## 组件类型速查
| 类别 | 组件 | 复杂度 |
|------|------|--------|
| 纹理 | Plasma, Godrays, SimplexNoise, LinearGradient, RadialGradient | 中 |
| 形状 | Glass, Blob, Circle, Ring, Star, RoundedRect, Polygon | 高Glass 最复杂) |
| 畸变 | WaveDistortion, ChromaticAberration, Liquify, Twirl, Bulge | 低-中 |
| 风格化 | FilmGrain, Halftone, Ascii, Dither, Glow, Bloom | 低-中 |
| 后处理 | Blur, ProgressiveBlur, BrightnessContrast, HueShift | 低 |
## 渲染管线
```
Three.js r183 TSL 渲染器
├─ 优先尝试 WebGPU降级到 WebGL
├─ 正交相机 + 单个全屏四边形
├─ 组件树从底到顶合成
├─ 有 children 的组件用 RTT (render-to-texture) 捕获子内容
├─ blend mode 用自定义混合函数
└─ Glass 组件最复杂SDF 评估 → 梯度法线 → 折射 → 色差 → 模糊 → 着色 → 高光 → 菲涅尔 → 合成
```
## 移植策略
1. **TSL 不能直接复制** — 需要翻译为 GLSL
2. **从 JS bundle 提取 TSL `fragmentNode`** → 反混淆 → 翻译为 GLSL
3. **组件树 → multi-pass FBO 管线**
4. **SDF 纹理需要 Y-flip**(见上方陷阱)
5. **Glass 组件参数多**20+),需要精确匹配每个值
## 颜色空间处理(关键)
shaders.com 的 Three.js 渲染器全程在 **linear 空间** 工作:
- 组件定义中的 hex 颜色(如 `#2c2c42`)是 **sRGB**
- TSL 的 `color()` 函数自动将 sRGB→linear
- 所有中间 FBO 均存储 linear 值
- 最终由渲染器做 linear→sRGB 输出编码
移植时:
```glsl
// 1. 颜色定义时sRGB hex → linear
vec3 colorA = pow(vec3(0.173, 0.173, 0.259), vec3(2.2)); // #2c2c42
// 2. 中间 pass全部在 linear 空间计算,不做 gamma
// 3. 最终输出 pass仅一次linear → sRGB
fragColor = vec4(pow(color.rgb, vec3(1.0/2.2)), color.a);
```
**常见错误**:在中间 pass 做 gamma 校正,导致后续 pass 在错误空间累加高光/菲涅尔。
## 参数精确对齐原则
**绝对禁止手动调参**。所有参数必须严格匹配 TSL 翻译中的公式和乘数:
```
TSL 原始乘数 → GLSL 必须使用的值
aberration * 0.06 → 不能改为 0.12
fresnelSoftness * 0.06 → 不能改为 0.12
fresnel (0.17) → 不能改为 0.4
SDF gradient eps = 0.01 → 不能改为 0.005
```
如果视觉效果不匹配,应检查:
1. 颜色空间是否正确sRGB/linear 混乱是最常见原因)
2. 噪声函数实现差异Perlin 实现 vs `mx_noise_float`
3. 时间基准是否正确
4. FBO 管线顺序是否与组件树匹配
**不要**通过修改乘数来"补偿"视觉差异 — 这会在其他参数配置下崩溃。
## TSL 时间约定
`timerLocal(speed)` = 每秒递增 `speed` 单位。移植时:`uTime = seconds * speed`
然后 shader 内部再乘自己的系数:
| 组件 | speed 参数 | shader 内部乘数 | 实际速率/秒 |
|------|-----------|----------------|------------|
| Plasma | 2 | × 0.125 | 0.25 |
| Godrays | 0.7 | × 0.2 | 0.14 |
| WaveDistortion | 0.8 | × 0.5 | 0.4 |
| FilmGrain | — | 无时间(静态) | 0 |
## TSL→GLSL 标识符映射SPCVwBqR.js
常用映射(随构建版本变化,需动态提取):
| 本地名 | TSL 函数 | GLSL |
|--------|---------|------|
| C / z | vec4() | vec4 |
| x / D | vec2() | vec2 |
| q / N | vec3() | vec3 |
| P / J | resolution | u_resolution |
| A / $ | uv | vUv |
| se / Oe | sin() | sin() |
| W / I | cos() | cos() |
| ne | mix() | mix() |
| D | smoothstep() | smoothstep() |
| fe | clamp() | clamp() |
| ar | mx_noise_float() | perlinNoise3D() |
| dr / Gt | timerLocal() | u_time × speed |
| Me / wt | rtt() | FBO pass |
| Ce | renderOutput() | fragColor |