Three.js 材质(Material)详解 —— 区别、原理、场景与示例

563 阅读3分钟

一、概念

Three.js 中,材质(Material)决定了几何体表面的外观——包括颜色、光照反应、透明度、反射率、甚至物理属性。
简单来说,几何体是形状,材质是皮肤
不同的材质会模拟不同的现实渲染效果,从低成本的“纯色贴图”,到高质量的 PBR(基于物理的渲染)


二、原理

材质的核心是 着色器(Shader) ,即 GPU 上运行的小程序。
Three.js 提供了两类材质:

  1. 内置材质:如 MeshPhongMaterialMeshStandardMaterial,直接调用,简单易用。
  2. 自定义材质:如 ShaderMaterialRawShaderMaterial,需要自己写 GLSL。

不同材质的底层实现基于不同的 光照模型

  • Lambert(漫反射) → 粗糙表面,无镜面高光。
  • Phong(冯氏模型) → 漆面、陶瓷,带镜面反射。
  • Standard / Physical(PBR 模型) → 金属、玻璃、水,逼真模拟。

三、对比

材质是否受光照影响主要参数适用场景性能开销
SpriteMaterialmap, color2D 图标、UI、特效
ShadowMaterial特殊opacity阴影接收
ShaderMaterial自定义uniforms, vertex/fragmentShader特效、波纹、火焰★★★★
RawShaderMaterial自定义完全自写 GLSL高级渲染★★★★★
PointsMaterialsize, map粒子系统、星空、点云
MeshToonMaterialgradientMap卡通渲染、漫画风★★
MeshStandardMaterialmetalness, roughness, map木材、金属、石头★★★
MeshPhysicalMaterialtransmission, clearcoat玻璃、水、宝石★★★★
MeshPhongMaterialshininess, specular漆面、塑料★★
MeshNormalMaterial无需参数法线调试
MeshLambertMaterialcolor布料、纸张
MeshMatcapMaterialmatcap 纹理ZBrush 风格快速预览
MeshDistanceMaterial特殊near, far阴影、深度编码

四、实践(示例代码)

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();

五、拓展

  1. 性能优化:移动端尽量避免 PhysicalMaterial,优先 LambertMatcap
  2. 项目应用:建筑可视化用 StandardMaterial,游戏用 ToonMaterial,展示产品用 PhysicalMaterial
  3. 调试工具NormalMaterialDistanceMaterial 特别适合调试几何体和阴影效果。

六、潜在问题

  • 性能瓶颈:PBR 在低端设备上容易掉帧。
  • 阴影丢失:如果 renderer.shadowMap 没启用,ShadowMaterial 不生效。
  • 光照依赖:忘记添加光源时,LambertPhongStandard 会显示黑色。
  • 兼容性RawShaderMaterial 在不同浏览器可能表现差异。

AI 生成内容声明

本文由人工智能生成,仅供参考与学习,不构成专业建议。