Files
Z User e45b68bb8b feat: IMAP mail sync with thread-to-contact matching (PRD §6.1)
Real IMAP connection via imapflow library:
- Connects to IMAP server (IMAPFlow, TLS on port 993)
- Fetches recent messages (configurable limit, default 20)
- Extracts: from, fromEmail, subject, date, snippet (200 chars)
- Thread-to-contact matching (PRD §6.1):
  1. Match sender email against persons table
  2. If no person match, extract domain and match against company.website
  3. Returns matchedCompany + matchedPerson for each email
- Audit-logged (action: crm.mailsync:imap)
- Zod validated (host, port, user, password, folder, limit)
- 502 on IMAP connection failure with detail
- 400 on validation failure

Tested: invalid creds → 502 'IMAP connection failed', missing host → 400
2026-10-27 22:50:50 +00:00

4.1 KiB
Executable File
Raw Permalink Blame History

onBeforeCompile 注入 GLSL 的陷阱

场景

使用 MeshPhysicalMaterial 的 transmission 功能但需要增强效果时(如 drei 的 MeshTransmissionMaterial), 通过 material.onBeforeCompile 注入自定义 GLSL 代码。

常见陷阱

1. 函数签名版本差异

Three.js 不同版本的内置函数签名不同:

// r166 及之前
vec4 getIBLVolumeRefraction(n, v, roughness, diffuseColor, specularColor, specularF90,
  pos, modelMatrix, viewMatrix, projectionMatrix, ior, thickness,
  attenuationColor, attenuationDistance)

// r167+ 新增 dispersion 参数
vec4 getIBLVolumeRefraction(n, v, roughness, diffuseColor, specularColor, specularF90,
  pos, modelMatrix, viewMatrix, projectionMatrix, dispersion, ior, thickness,
  attenuationColor, attenuationDistance)

必须检查目标版本的实际签名:

curl -s "https://cdn.jsdelivr.net/npm/three@0.167.0/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js" \
  | tr '\n' ' ' | grep -oE 'vec4 getIBLVolumeRefraction\([^)]+\)'

2. GLSL 不允许嵌套函数定义

// 错误!GLSL 不支持函数内定义函数
void main() {
  float myRand(vec2 co) { return fract(sin(...)); }  // 编译失败
}

// 正确:函数必须在全局作用域
float myRand(vec2 co) { return fract(sin(...)); }
void main() {
  float r = myRand(uv);
}

3. 条件编译宏保护

某些变量只在特定宏下可用:

  • vWorldPosition → 需要 USE_TRANSMISSION 启用
  • vTransmissionMapUv → 需要 USE_TRANSMISSIONMAP 启用
  • roughnessFactor → 在 lights_physical_fragment 之后可用
// 在替换 #include <transmission_fragment> 时
// 原始代码自带 #ifdef USE_TRANSMISSION,替换代码也必须包含
#ifdef USE_TRANSMISSION
  // ... 你的代码
#endif

4. 变量名冲突

注入的全局函数/变量可能与 Three.js 内部冲突:

  • 避免使用 hash, random, noise 等通用名
  • 自定义函数加前缀:snoise → OK,random → 可能冲突
  • uniform 名称加前缀 u:uDistortion, uNoiseTime

推荐模式

安全注入:修改 normal 而不替换整个 chunk

material.onBeforeCompile = (shader) => {
  shader.uniforms.uDistortion = { value: 0 };
  shader.uniforms.uNoiseTime = { value: 0 };

  // 在 fragment shader 最前面加 uniform 声明 + 工具函数
  shader.fragmentShader = `
    uniform float uDistortion;
    uniform float uNoiseTime;
    ${noiseGLSL}
  ` + shader.fragmentShader;

  // 在 transmission_fragment 之前插入法线扰动
  shader.fragmentShader = shader.fragmentShader.replace(
    '#include <transmission_fragment>',
    `
    #ifdef USE_TRANSMISSION
    {
      // 扰动 normal 影响折射方向
      if (uDistortion > 0.0) {
        normal = normalize(normal + uDistortion * vec3(
          snoiseFractal(vWorldPosition * 0.08 + vec3(uNoiseTime)),
          snoiseFractal(vWorldPosition.zxy * 0.08 - vec3(uNoiseTime)),
          snoiseFractal(vWorldPosition.yxz * 0.08)
        ));
      }
    }
    #endif
    #include <transmission_fragment>
    `
  );
};

完整替换:需要随机多采样 + 色差时

当需要 MeshTransmissionMaterial 的颗粒感(随机采样噪声)和色差效果时, 必须完整替换 #include <transmission_fragment>。关键点:

  1. 保留 #ifdef USE_TRANSMISSION / #endif 包裹
  2. 保留 transmissionMap 和 thicknessMap 的 #ifdef 块
  3. 使用正确版本的 getIBLVolumeRefraction 签名
  4. 自己处理色差时,传 dispersion = 0.0,用不同 IOR 采样 R/G/B
  5. 低采样数(6)+ 每像素随机偏移 → 产生可见的胶片颗粒感

视觉效果来源速查

效果 来源 实现方式
玻璃折射 MeshPhysicalMaterial transmission Three.js 内置
色差 (chromatic aberration) 不同 IOR 采样 R/G/B 替换 transmission_fragment
胶片颗粒感 低采样数 + 每像素随机方向 替换 transmission_fragment
有机扭曲 simplex noise 扰动法线/折射方向 onBeforeCompile 注入
颜色偏移 dispersion 属性 (r167+) MeshPhysicalMaterial 内置