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,再修改输出变量”,再学习有条件地替换整个模块。只有真正需要改变底层模型时,才接触光照函数和较大的内部代码块。

练习(不附答案)

  1. 为“整体变红”“沿高度扫描”“完全不受光照的分形”分别选择实现方式并说明原因。
  2. 找出 MeshStandardMaterial 的三个现成属性,设计一个无需 GLSL 的湿润外观近似方案。
  3. 解释修改基础颜色、emissive、最终输出三者对阴影和高光的影响。
  4. 列出顶点弯曲以后仍需检查的 GPU 与 CPU 数据,避免只关注主画面。