Material
所有材质的基类,定义表面的通用渲染行为:透明度、面朝向、深度测试、混合方式与着色器行为。
基类通用属性
| 属性 | 默认 | 说明 |
|---|---|---|
opacity | 1 | 不透明度,需要同时把 transparent 设为 true 才生效 |
transparent | false | 开启透明混合,会引入排序问题与额外开销 |
alphaTest | 0 | 低于该 alpha 的片元直接丢弃,适合植被、栏杆等镂空贴图 |
side | FrontSide | 正面、背面或双面渲染,双面会翻倍片元开销 |
depthTest | true | 是否参与深度比较 |
depthWrite | true | 是否写入深度缓冲,透明物体常设为 false |
colorWrite | true | 是否写入颜色,可做只写深度的预处理 |
blending | NormalBlending | 混合模式,发光效果常用 AdditiveBlending |
polygonOffset | false | 多边形偏移,用于压住共面闪烁(如贴地标线) |
toneMapped | true | 是否参与色调映射,UI 类元素可关闭以保持纯色 |
fog | true | 是否受场景雾影响 |
needsUpdate | — | 置 true 触发着色器重编译,见下文 |
常用材质与关键参数
| 材质 | 关键参数 | 适用 |
|---|---|---|
MeshBasicMaterial | color、map | 不受光,标注、辅助线、背景 |
MeshLambertMaterial | color、emissive | 漫反射,大范围地形 |
MeshStandardMaterial | roughness、metalness、map、normalMap | PBR 默认选择 |
MeshPhysicalMaterial | clearcoat、transmission、ior、thickness | 玻璃、水面、车漆 |
LineBasicMaterial | color、linewidth | 轨迹、经纬网、边框 |
PointsMaterial | size、map、vertexColors | 点云、粒子 |
SpriteMaterial | map、depthTest | 始终朝向相机的标签 |
linewidth 在绝大多数平台上固定为 1,WebGL 并不保证支持更宽的线。
需要粗线时要用 Line2 或把线做成管状几何体。
创建与修改
const material = new THREE.MeshStandardMaterial({
color: 0x4f9ef8,
roughness: 0.45,
metalness: 0.12,
transparent: true,
opacity: 0.9,
side: THREE.DoubleSide,
polygonOffset: true,
polygonOffsetFactor: -1,
polygonOffsetUnits: -1
});
// 改颜色、透明度:不需要重编译
material.color.setHex(0xff8844);
material.opacity = 0.6;
// 增删贴图、切换 vertexColors:需要重编译
material.map = newTexture;
material.needsUpdate = true;
什么时候需要 needsUpdate
材质的着色器是按「启用了哪些特性」编译的。改变数值(颜色、粗糙度、透明度)不会改变着色器结构,
直接赋值即可生效。改变结构(新增贴图、移除贴图、开关顶点颜色、切换是否受雾影响)
会改变着色器代码,必须置 needsUpdate = true,下一次渲染时重新编译。
重编译会造成一帧卡顿。批量场景里逐个切换材质结构,最好一次性完成, 避免在动画过程中零散触发。
透明与排序
透明物体默认按到相机的距离从远到近排序,但排序以对象中心为单位,不是逐片元。
相互穿插的透明面片、贴地的半透明图层,经常出现前后关系错误。
常见处理是:透明面片关闭 depthWrite,叠加图层用
AdditiveBlending,并手动控制 renderOrder。
大面积半透明面(如云层、热力面)如果看得出明显的三角形接缝, 多半是深度写入与混合顺序导致,而不是着色器有错。
贴图与色彩空间
颜色贴图(map、emissiveMap)应标为 sRGB;
数据贴图(normalMap、roughnessMap、metalnessMap)
保持线性。标错会让光照方向或表面粗糙度整体偏移。
释放
material.dispose() 释放材质关联的着色器程序。材质里的贴图要单独调用
texture.dispose()。两者都不在网格移除时自动触发。
同一材质才能合批。大量外观相同的小物件共享一份材质,渲染器的状态切换最少。
如果每个对象都要独立颜色,优先考虑顶点色或 InstancedMesh 的实例颜色,
而不是逐个克隆材质。
经纬志(2026)。《Material》。https://www.jingweizhi.com/three/api/material.html(访问日期 2026-11-03)。