1. 五种核心材质对比
Three.js 提供多种 Mesh 材质,性能和效果各有侧重。理解它们的差异,才能在正确场合选对材质:
| 材质 | 需要光照 | 性能 | 特点 |
|---|---|---|---|
MeshBasicMaterial | 否 | 最高 | 纯色/纹理,不受光照影响,用于 UI 元素、线框、背景 |
MeshLambertMaterial | 是 | 高 | 漫反射模型,无高光,适合低性能场景的哑光物体 |
MeshPhongMaterial | 是 | 中 | Phong 光照模型,有高光(shininess),适合塑料/光滑表面 |
MeshStandardMaterial | 是 | 中低 | PBR 标准材质,roughness + metalness,现代 3D 首选 |
MeshPhysicalMaterial | 是 | 最低 | PBR 扩展,增加 clearcoat(清漆)、transmission(透明)、iridescence(虹彩) |
// MeshBasicMaterial — 不受光照影响
const basic = new THREE.MeshBasicMaterial({
color: 0x049EF4,
transparent: true,
opacity: 0.8,
side: THREE.DoubleSide // 双面渲染
});
// MeshStandardMaterial — PBR 首选
const standard = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0.3, // 0=镜面, 1=完全粗糙
metalness: 0.8, // 0=非金属, 1=金属
envMapIntensity: 1.0
});
// MeshPhysicalMaterial — 高级效果
const physical = new THREE.MeshPhysicalMaterial({
color: 0x88ccff,
roughness: 0.05,
metalness: 0.0,
transmission: 0.95, // 透明度(玻璃效果)
thickness: 0.5, // 材质厚度(影响折射)
ior: 1.5, // 折射率(玻璃≈1.5)
clearcoat: 1.0, // 清漆层强度(汽车漆)
clearcoatRoughness: 0.1
});
2. TextureLoader 加载图片纹理
纹理(Texture)是贴在几何体表面的图片。Three.js 的 TextureLoader 负责异步加载图片并转为 GPU 纹理:
const loader = new THREE.TextureLoader();
// 方式一:回调函数
const texture = loader.load(
'/textures/brick.jpg',
(tex) => { console.log('纹理加载完成', tex); },
undefined,
(err) => { console.error('加载失败', err); }
);
// 方式二:Promise 封装(推荐)
const loadTexture = (url) =>
new Promise((resolve, reject) => {
loader.load(url, resolve, undefined, reject);
});
const [colorMap, normalMap, roughnessMap] = await Promise.all([
loadTexture('/textures/color.jpg'),
loadTexture('/textures/normal.jpg'),
loadTexture('/textures/roughness.jpg')
]);
const material = new THREE.MeshStandardMaterial({
map: colorMap, // 颜色纹理
normalMap: normalMap, // 法线贴图
roughnessMap: roughnessMap // 粗糙度贴图
});
3. UV 映射
UV 坐标定义了 3D 几何体表面的每个点对应纹理图片上的哪个位置。U 轴对应横向(0~1),V 轴对应纵向(0~1)。Three.js 的内置几何体都自带 UV 坐标。
// 纹理重复(平铺地板)
const floorTex = await loadTexture('/textures/floor.jpg');
floorTex.wrapS = THREE.RepeatWrapping; // U 方向重复
floorTex.wrapT = THREE.RepeatWrapping; // V 方向重复
floorTex.repeat.set(4, 4); // 4x4 平铺
// 纹理旋转
floorTex.rotation = Math.PI / 4; // 旋转 45°
floorTex.center.set(0.5, 0.5); // 旋转中心(UV 中点)
// 纹理偏移
floorTex.offset.set(0.1, 0); // 平移纹理
// wrapMode 选项:
// THREE.ClampToEdgeWrapping — 边缘像素拉伸(默认)
// THREE.RepeatWrapping — 重复平铺
// THREE.MirroredRepeatWrapping — 镜像重复
4. 法线贴图(Normal Map)
法线贴图是一种低成本制造高细节表面凹凸感的技术。它不改变几何体的实际形状,而是通过改变表面法线方向来欺骗光照计算,使平面看起来有凹凸纹理。
- 法线(Normal) 垂直于表面的向量,用于计算光照反射角度。法线的方向决定了表面"朝向哪里",从而决定光照强度。
- 法线贴图 RGB 颜色图,R/G/B 分别编码法线的 x/y/z 分量偏移。粉紫色调是法线贴图的典型特征(因为默认法线方向编码为 [128, 128, 255])。
- 位移贴图(displacementMap) 与法线贴图不同,位移贴图会真实地移动顶点位置,产生实际的几何凹凸。需要高分段数几何体配合,性能消耗更高。
const stoneMat = new THREE.MeshStandardMaterial({
map: loader.load('/stone/color.jpg'),
normalMap: loader.load('/stone/normal.jpg'),
roughnessMap: loader.load('/stone/roughness.jpg'),
aoMap: loader.load('/stone/ao.jpg'), // 环境光遮蔽贴图
normalScale: new THREE.Vector2(2, 2) // 增强法线效果
});
5. PBR 材质与环境贴图
PBR(Physically Based Rendering)是现代实时渲染的标准——材质参数对应真实世界的物理属性,在不同光照环境下都能产生可信的效果。
PBR 材质需要环境贴图(envMap)才能产生真实的反射效果。通常使用 HDR(高动态范围)全景图作为环境光源:
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
const rgbeLoader = new RGBELoader();
const envMap = await new Promise((resolve) =>
rgbeLoader.load('/env/studio.hdr', resolve)
);
// 设置为 EquirectangularReflectionMapping
envMap.mapping = THREE.EquirectangularReflectionMapping;
// 同时作为场景背景和所有物体的反射源
scene.background = envMap;
scene.environment = envMap; // 所有 PBR 材质自动使用
// 金属球(高反射)
const metalBall = new THREE.Mesh(
new THREE.SphereGeometry(1, 64, 32),
new THREE.MeshStandardMaterial({
color: 0xcccccc,
metalness: 1.0,
roughness: 0.05 // 高光泽金属
})
);
// 磨砂金属
const brushedMetal = new THREE.MeshStandardMaterial({
color: 0x8899aa,
metalness: 0.9,
roughness: 0.4
});
// 橡胶/塑料
const rubber = new THREE.MeshStandardMaterial({
color: 0x222222,
metalness: 0.0,
roughness: 0.9
});
免费 HDR 环境贴图资源:
• Poly Haven(polyhaven.com)— 免版权 HDR 环境贴图,质量极高
• ambientCG(ambientcg.com)— 免版权 PBR 材质纹理包
• Three.js Editor 内置示例环境贴图
6. 纹理压缩与性能
// 纹理过滤——影响缩放时的质量
texture.magFilter = THREE.LinearFilter; // 放大过滤(默认)
texture.minFilter = THREE.LinearMipmapLinearFilter; // 缩小过滤(MipMap)
texture.generateMipmaps = true; // 自动生成 MipMap(默认开启)
// 各向异性过滤——斜视时纹理更清晰
const maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
texture.anisotropy = maxAnisotropy; // 最大值(通常 8 或 16)
// 纹理格式建议:
// JPG —— 颜色/漫反射贴图(有损压缩,体积小)
// PNG —— 需要透明通道时
// HDR/EXR —— 环境贴图(高动态范围)
// KTX2/Basis —— GPU 压缩纹理(最佳性能)
// 释放不再使用的纹理(防止内存泄漏)
texture.dispose();
material.dispose();
geometry.dispose();
本章小结:材质决定物体的视觉效果。开发中优先使用 MeshStandardMaterial(PBR);需要玻璃/透明/清漆效果时升级为 MeshPhysicalMaterial;UI 元素用 MeshBasicMaterial。配合 HDR 环境贴图,即使简单场景也能呈现专业品质。