01 · 为什么定制内置材质
本系列面向 Three.js r185 / 0.185.1 的 WebGLRenderer。你会学习如何定制 MeshPhongMaterial、MeshStandardMaterial、MeshPhysicalMaterial,而不必重写整套光照、阴影和颜色输出代码。ShaderChunk 是内部实现模块,版本升级时需要核对;这里的名字和顺序不是永久兼容协议。
1. 先看你需要改变哪一层
假设设备从正常状态变成报警状态。如果只是整体从蓝色变成红色,直接修改 material.color 就足够了。如果要求红色扫描带沿设备局部高度移动,同时仍能看到金属高光、阴影和粗糙度细节,单一颜色属性就不够,需要在每个片元处计算不同的基础颜色。
import * as THREE from 'three';
const material = new THREE.MeshStandardMaterial({
color: 0x4687a8,
roughness: 0.45,
metalness: 0.2
});
material.color.set(0xd84f35); // 已有属性可以表达时,无须注入 GLSL。
另一方面,如果你正在画完全不受光照的二维分形,用 ShaderMaterial 往往更直接。保留复杂 PBR 管线却在最后覆盖全部颜色,会付出没有意义的计算成本。
| 方案 | 适合的需求 | 需要承担的职责 |
|---|---|---|
| 内置材质属性和贴图 | 颜色、粗糙度、金属度、现成纹理变换 | 理解属性和贴图通道 |
onBeforeCompile 注入 |
局部材质参数变化、顶点动画、定制采样 | 维护锚点、缓存、变量和额外渲染通道 |
| ShaderMaterial | 高度独立的自定义着色逻辑 | 自己组织输入、坐标、着色及需要的输出处理 |
| 节点材质 / TSL | 使用对应渲染器和节点工作流的项目 | 学习节点体系及迁移约束,不沿用字符串替换假设 |
Three.js 当前源码推荐新项目考虑节点材质和 TSL,但本项目使用的 WebGLRenderer 定制需求仍可按本系列实现。不要期待 onBeforeCompile 在 WebGPURenderer 中以同样方式工作。
2. 你要修改的是计算数据,而不只是字符串
内置材质把“表面是什么”和“受到什么光”分成不同阶段。概念链路是:
几何位置 / UV / 法线
→ 表面基础颜色、粗糙度、金属度、透明度
→ 直接光、间接光、环境反射
→ outgoingLight
→ 色调映射、输出颜色空间、雾等
给基础颜色乘上扫描遮罩,会让扫描带参与材质反射;给 emissive 加一项,会形成不依赖入射光的发光外观;在最终输出后直接覆盖 RGB,则可能绕过光照甚至颜色管理。三段代码都能让画面“变红”,但视觉意义完全不同。
因此每次定制先写清四件事:输入是什么;在哪个坐标空间计算;想改变哪个中间量;后续哪些内置行为还需要保留。然后才找 replace 的锚点。
3. 一个像素的颜色为什么不只来自 material.color
MeshStandardMaterial 中,基础颜色通常由材质 diffuse、颜色贴图和顶点颜色共同构成;粗糙度和金属度影响反射分配,法线决定方向,灯光和环境提供入射辐射。最终还会进行色调映射与输出颜色空间转换。
把 diffuseColor.rgb 设为纯红,并不保证屏幕像素恰好等于红色 (1,0,0),因为它仍受到光照与输出处理。要验证材质参数补丁,必须在已知灯光、相机和颜色管理设置下比较。
没有灯光或环境时,金属材质可能很暗。这不一定是补丁失败。初次调试建议用非金属、适中粗糙度、明确的方向光与半球光;待逻辑稳定后再加入复杂环境。
4. 内置材质帮你保留了什么
保留原始模块可以继续获得骨骼动画、morph、实例化、灯光、阴影接收、雾和颜色输出等路径。但“用了内置材质”并不意味着所有新效果会自动进入这些路径。
如果顶点补丁让旗帜弯曲,阴影生成时使用的深度或距离材质不会自动收到相同补丁;CPU 上的包围盒与射线查询也不会因为 GPU 位移而更新。它们需要分别设计,第 24、25 章会处理。
5. 本系列的使用方式
基础章节给出小型补丁,场景章节提供完整核心代码。公共 runtime.js 负责场景和循环,patch-utils.js 负责严格替换检查,使用方法见 README。uniform 状态由应用持有,不藏在一次编译回调的局部变量中。
先学会“保留 include,再修改输出变量”,再学习有条件地替换整个模块。只有真正需要改变底层模型时,才接触光照函数和较大的内部代码块。
练习(不附答案)
- 为“整体变红”“沿高度扫描”“完全不受光照的分形”分别选择实现方式并说明原因。
- 找出 MeshStandardMaterial 的三个现成属性,设计一个无需 GLSL 的湿润外观近似方案。
- 解释修改基础颜色、emissive、最终输出三者对阴影和高光的影响。
- 列出顶点弯曲以后仍需检查的 GPU 与 CPU 数据,避免只关注主画面。