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

一、材质是什么?

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

js 复制代码
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);

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

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

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

方式二:创建后动态修改

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

颜色的多种设置方式

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

js 复制代码
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

创建材质时也一样灵活:

js 复制代码
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

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

1. MeshBasicMaterial ------ 基础材质

特点:不受光照影响。

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

js 复制代码
const material = new THREE.MeshBasicMaterial({ color: 0x44aa88 });

2. MeshLambertMaterial ------ Lambert 材质

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

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

js 复制代码
const material = new THREE.MeshLambertMaterial({ color: 0x44aa88 });

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

3. MeshPhongMaterial ------ Phong 材质

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

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

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

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

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

emissive 属性的妙用

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

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

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

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

4. MeshToonMaterial ------ 卡通材质

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

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

js 复制代码
const material = new THREE.MeshToonMaterial({ color: 0x44aa88 });

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

5. MeshStandardMaterial ------ 标准 PBR 材质

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

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

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

两个关键参数:

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

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

6. MeshPhysicalMaterial ------ 物理材质

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

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

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

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

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

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

五、通用材质属性

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

flatShading(平面着色)

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

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

side(渲染面)

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

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

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

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

总结

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

相关推荐
慧都小妮子9 小时前
实时大屏掉帧排查:WebGL 图表库选型的 5 项可实测检查
webgl·scichart.js·实时大屏掉帧·前端图表选型
❀͜͡傀儡师11 小时前
移动端 360° 商品展示方案:从 20MB 雪碧图到 800KB 丝滑视频
ffmpeg·webgl·sprite
平行云20 小时前
国产GPU云渲染适配实战:驱动兼容、编码调优与多路并发
unity·ue5·webrtc·webgl·实时云渲染·云桌面·像素流送
平行云4 天前
实时云渲染信创架构解析:从GPU池化到全栈适配的技术演进
linux·unity·docker·ue5·webgl·数字孪生·实时云渲染
yyt3630458415 天前
KLineChartQuant:GLSL 的精度问题及 RTC 解法
前端·vue.js·react.js·交互·图形渲染·webgl·数据可视化
灵境(虚幻知音)7 天前
WebGL 不支持>1px的线绘制,那 Cesium 的带宽度的线是怎么画出来的?
webgl·cesium·着色器
云登指纹浏览器7 天前
浏览器指纹检测原理演进:从Canvas到WebGL的4轮风控升级
webgl
lerhxx10 天前
为什么你的Three.js物体总是乱转?一文彻底搞懂“万向锁”与四元数
前端·three.js
前端老爷更车10 天前
从 `renderer.render()` 到地面上的阴影:Three.js 阴影渲染全流程源码解析
webgl
lerhxx11 天前
R3F 第一人称漫游与碰撞检测:Pointer Lock + 不穿墙的滑墙秘诀(中)
前端·javascript·three.js