Three.js 材质完全入门指南:让你的 3D 物体「活」起来

1 阅读5分钟

01.png

一、材质是什么?

简单来说,材质定义了物体表面的视觉属性——颜色、光泽度、透明度、对光的反应方式等等。在 Three.js 中,材质是 Material 类的实例,它和几何体(Geometry)一起构成了网格(Mesh):

const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshPhongMaterial({ color: 0xFF0000 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

二、设置材质属性的两种方式

方式一:创建时传入配置对象

const material = new THREE.MeshPhongMaterial({
  color: 0xFF0000,    // 红色
  flatShading: true,  // 平面着色
});

方式二:创建后动态修改

const material = new THREE.MeshPhongMaterial();
material.color.setHSL(0, 1, 0.5);  // 红色
material.flatShading = true;

颜色的多种设置方式

Three.js 的颜色系统非常灵活,THREE.Color 支持多种赋值方式:

material.color.set(0x00FFFF);            // 十六进制
material.color.set('purple');             // CSS 颜色名
material.color.set('#F32');               // CSS 缩写
material.color.set('rgb(255, 127, 64)'); // RGB 函数
material.color.set('hsl(180, 50%, 25%)'); // HSL 函数
material.color.setHSL(h, s, l);          // h, s, l 范围 0~1
material.color.setRGB(r, g, b);          // r, g, b 范围 0~1

创建材质时也一样灵活:

new THREE.MeshBasicMaterial({ color: 0xFF0000 });          // 十六进制
new THREE.MeshBasicMaterial({ color: 'red' });             // 颜色名
new THREE.MeshBasicMaterial({ color: '#F00' });            // CSS 缩写
new THREE.MeshBasicMaterial({ color: 'rgb(255,0,0)' });    // RGB
new THREE.MeshBasicMaterial({ color: 'hsl(0,100%,50%)' }); // HSL

三、六大核心材质类型详解

02.png

1. MeshBasicMaterial —— 基础材质

特点:不受光照影响。

这是最简单的材质,物体始终以纯色显示,不管场景中有没有灯光。适合用于不需要光影效果的场景,比如 UI 元素、线框展示、或者你只是想快速看到一个物体。

const material = new THREE.MeshBasicMaterial({ color: 0x44aa88 });

2. MeshLambertMaterial —— Lambert 材质

特点:在顶点处计算光照。

Lambert 材质使用 Lambertian 反射模型,只在几何体的顶点处计算光照,然后在三角面内做插值。它能表现出基本的明暗效果,但不支持高光(specular highlight)

const material = new THREE.MeshLambertMaterial({ color: 0x44aa88 });

由于只在顶点计算光照,在低多边形(Low-Poly)模型上可能会看到明显的色块分界。

3. MeshPhongMaterial —— Phong 材质

特点:在每个像素处计算光照,支持高光。

Phong 材质比 Lambert 更精细,它在每个像素上都计算光照,因此能产生平滑的光照过渡和镜面高光(specular highlight)效果。

const material = new THREE.MeshPhongMaterial({
  color: 0x44aa88,
  shininess: 100, // 高光强度,默认 30
});

shininess 参数控制高光的集中程度:

  • shininess: 0 —— 没有高光,效果类似 Lambert
  • shininess: 30 —— 默认值,柔和的高光
  • shininess: 150 —— 强烈集中的高光,类似抛光表面

emissive 属性的妙用

MeshLambertMaterialMeshPhongMaterial 都有 emissive(自发光)属性。当你把 color 设为黑色,emissive 设为某个颜色时,效果会和 MeshBasicMaterial 几乎一样:

// 以下三种方式视觉效果基本相同
new THREE.MeshBasicMaterial({ color: 'purple' });

new THREE.MeshLambertMaterial({ color: 'black', emissive: 'purple' });

new THREE.MeshPhongMaterial({ color: 'black', emissive: 'purple', shininess: 0 });

4. MeshToonMaterial —— 卡通材质

特点:类似 Phong,但使用渐变贴图实现卡通风格的色阶着色。

卡通材质不会平滑过渡光影,而是使用渐变贴图将光照分成几个离散的色阶,营造出二维卡通的视觉效果。

const material = new THREE.MeshToonMaterial({ color: 0x44aa88 });

默认的渐变贴图在前 70% 亮度区域使用 70% 的明度,之后跳到 100%,形成经典的双色阶卡通效果。你也可以提供自定义的渐变贴图来实现更丰富的色阶。

5. MeshStandardMaterial —— 标准 PBR 材质

03.png

特点:基于物理渲染(PBR),使用 roughnessmetalness 参数。

这是 Three.js 中最常用的高质量材质。它基于物理的光照模型,能更真实地模拟现实世界中光线与材质的交互。

const material = new THREE.MeshStandardMaterial({
  color: 0x44aa88,
  roughness: 0.5, // 粗糙度 0~1
  metalness: 0.5, // 金属度 0~1
});

两个关键参数:

参数范围含义
roughness0 ~ 1表面粗糙度。0 = 光滑如镜(台球),1 = 完全粗糙(棒球)
metalness0 ~ 1金属感。0 = 非金属(塑料、木头),1 = 纯金属(铁、金)

roughness 可以理解为 shininess 的反义词——roughness 越高,表面越粗糙,反射越模糊。

6. MeshPhysicalMaterial —— 物理材质

特点:在 Standard 材质基础上增加了清漆层(Clearcoat)。

物理材质是标准材质的增强版,额外提供了 clearcoat(清漆)和 clearcoatRoughness(清漆粗糙度)参数,可以模拟汽车漆面、贴膜表面等具有多层反射的材质。

const material = new THREE.MeshPhysicalMaterial({
  color: 0x44aa88,
  roughness: 0.5,
  metalness: 0.5,
  clearcoat: 1.0,            // 清漆强度 0~1
  clearcoatRoughness: 0.1,   // 清漆粗糙度 0~1
});

四、性能排序:如何选择合适的材质?

04.png

不同材质的 GPU 开销差异显著,从快到慢排列:

MeshBasicMaterial → MeshLambertMaterial → MeshPhongMaterial → MeshStandardMaterial → MeshPhysicalMaterial
      最快                                                                                    最慢
    (无光照)         (顶点光照)          (像素光照)         (PBR)                (PBR + 清漆层)

五、通用材质属性

所有材质都继承自 Material 基类,以下两个属性最常用:

flatShading(平面着色)

控制物体表面看起来是棱角分明还是光滑圆润。

material.flatShading = true;  // 每个三角面使用统一法线,呈现硬朗的多面体效果
material.flatShading = false; // 默认,法线在三角面间插值,呈现平滑效果

side(渲染面)

控制三角面的哪一侧会被渲染:

material.side = THREE.FrontSide;  // 默认,只渲染正面
material.side = THREE.BackSide;   // 只渲染背面
material.side = THREE.DoubleSide; // 双面渲染

大多数 3D 物体是封闭实体,背面不可见,不需要渲染。但对于平面(Plane)、开放曲面等可能看到背面的几何体,应设为 THREE.DoubleSide

核心代码与完整示例:       my-three-app

总结

如果你喜欢本教程,记得点赞+收藏!关注我获取更多Three.js开发干货