一、概念
在 Three.js 中,材质(Material)决定了几何体表面的外观------包括颜色、光照反应、透明度、反射率、甚至物理属性。
简单来说,几何体是形状,材质是皮肤 。
不同的材质会模拟不同的现实渲染效果,从低成本的"纯色贴图",到高质量的 PBR(基于物理的渲染) 。
二、原理
材质的核心是 着色器(Shader) ,即 GPU 上运行的小程序。
Three.js 提供了两类材质:
- 内置材质 :如
MeshPhongMaterial
、MeshStandardMaterial
,直接调用,简单易用。 - 自定义材质 :如
ShaderMaterial
、RawShaderMaterial
,需要自己写 GLSL。
不同材质的底层实现基于不同的 光照模型:
- Lambert(漫反射) → 粗糙表面,无镜面高光。
- Phong(冯氏模型) → 漆面、陶瓷,带镜面反射。
- Standard / Physical(PBR 模型) → 金属、玻璃、水,逼真模拟。
三、对比
材质 | 是否受光照影响 | 主要参数 | 适用场景 | 性能开销 |
---|---|---|---|---|
SpriteMaterial | 否 | map, color | 2D 图标、UI、特效 | ★ |
ShadowMaterial | 特殊 | opacity | 阴影接收 | ★ |
ShaderMaterial | 自定义 | uniforms, vertex/fragmentShader | 特效、波纹、火焰 | ★★★★ |
RawShaderMaterial | 自定义 | 完全自写 GLSL | 高级渲染 | ★★★★★ |
PointsMaterial | 否 | size, map | 粒子系统、星空、点云 | ★ |
MeshToonMaterial | 是 | gradientMap | 卡通渲染、漫画风 | ★★ |
MeshStandardMaterial | 是 | metalness, roughness, map | 木材、金属、石头 | ★★★ |
MeshPhysicalMaterial | 是 | transmission, clearcoat | 玻璃、水、宝石 | ★★★★ |
MeshPhongMaterial | 是 | shininess, specular | 漆面、塑料 | ★★ |
MeshNormalMaterial | 否 | 无需参数 | 法线调试 | ★ |
MeshLambertMaterial | 是 | color | 布料、纸张 | ★ |
MeshMatcapMaterial | 否 | matcap 纹理 | ZBrush 风格快速预览 | ★ |
MeshDistanceMaterial | 特殊 | near, far | 阴影、深度编码 | ★ |
四、实践(示例代码)
ini
import * as THREE from 'three';
// 初始化场景
const scene = new THREE.Scene();
// 相机
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 10);
// 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// 灯光
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
light.castShadow = true;
scene.add(light);
// 地面接收阴影
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(20, 20),
new THREE.ShadowMaterial({ opacity: 0.3 })
);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
// 常见几何体
const geometry = new THREE.SphereGeometry(0.7, 32, 32);
// 各种材质
const materials = [
new THREE.MeshBasicMaterial({ color: 0xff0000 }),
new THREE.MeshLambertMaterial({ color: 0x00ff00 }),
new THREE.MeshPhongMaterial({ color: 0x0000ff, shininess: 80 }),
new THREE.MeshStandardMaterial({ color: 0xffff00, metalness: 0.8, roughness: 0.2 }),
new THREE.MeshPhysicalMaterial({ color: 0x00ffff, transmission: 0.9, thickness: 0.5 }),
new THREE.MeshToonMaterial({ color: 0xff00ff }),
new THREE.MeshNormalMaterial(),
new THREE.MeshMatcapMaterial({ matcap: new THREE.TextureLoader().load('matcap.png') })
];
// 逐个摆放材质球
materials.forEach((mat, i) => {
const mesh = new THREE.Mesh(geometry, mat);
mesh.position.x = (i - 3.5) * 2;
mesh.castShadow = true;
scene.add(mesh);
});
// 粒子系统
const particlesGeo = new THREE.BufferGeometry();
const count = 500;
const positions = new Float32Array(count * 3);
for (let i = 0; i < count * 3; i++) positions[i] = (Math.random() - 0.5) * 10;
particlesGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
const particles = new THREE.Points(particlesGeo, new THREE.PointsMaterial({ color: 0xffffff, size: 0.05 }));
scene.add(particles);
// 精灵
const spriteTex = new THREE.TextureLoader().load('https://threejs.org/examples/textures/sprite.png');
const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: spriteTex }));
sprite.position.set(0, 3, 0);
scene.add(sprite);
// 渲染循环
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
五、拓展
- 性能优化 :移动端尽量避免
PhysicalMaterial
,优先Lambert
或Matcap
。 - 项目应用 :建筑可视化用
StandardMaterial
,游戏用ToonMaterial
,展示产品用PhysicalMaterial
。 - 调试工具 :
NormalMaterial
和DistanceMaterial
特别适合调试几何体和阴影效果。
六、潜在问题
- 性能瓶颈:PBR 在低端设备上容易掉帧。
- 阴影丢失 :如果
renderer.shadowMap
没启用,ShadowMaterial
不生效。 - 光照依赖 :忘记添加光源时,
Lambert
、Phong
、Standard
会显示黑色。 - 兼容性 :
RawShaderMaterial
在不同浏览器可能表现差异。
AI 生成内容声明
本文由人工智能生成,仅供参考与学习,不构成专业建议。