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

一、概念

在 Three.js 中,材质(Material)决定了几何体表面的外观------包括颜色、光照反应、透明度、反射率、甚至物理属性。

简单来说,几何体是形状,材质是皮肤 。

不同的材质会模拟不同的现实渲染效果,从低成本的"纯色贴图",到高质量的 PBR(基于物理的渲染) 。


二、原理

材质的核心是 着色器(Shader) ,即 GPU 上运行的小程序。

Three.js 提供了两类材质:

  1. 内置材质 :如 MeshPhongMaterial、MeshStandardMaterial,直接调用,简单易用。
  2. 自定义材质 :如 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();

五、拓展

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

六、潜在问题

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

AI 生成内容声明

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

相关推荐
xixichensh10 小时前
前端转做AI程序员第一步——开发一个AI流式对话Demo
前端
小羊没烦恼!10 小时前
系统内部模块(子系统)之间的耦合以及模块(子系统)划分
java·开发语言·前端·数据库·算法·c#
Leslie16510 小时前
聚合不只是 GROUP BY:HashAggregate 与 SortAggregate 的内存账本
前端
ITOM运维行者11 小时前
PHP性能监控怎么做?从响应时间到慢函数的6个关键指标
前端·javascript·后端
成旭先生11 小时前
AI 文本审核 API:一段中文文本判风险等级、命中标签与处置建议
java·前端·人工智能·api接口·内容风控·文本审核·ugc审核
liangshanbo121511 小时前
前端面试题:AI 对话中超长消息导致内存溢出,怎么解决?
java·开发语言·前端
静默回滚11 小时前
PDF能打开却不能复制,原来是权限密码
前端
律宏阔11 小时前
Dart FFI 内存管理:用 using + Arena 替代嵌套 try-finally
前端·flutter
guslegend12 小时前
脚手架入门:必要性、核心功能与执行原理
前端·架构·node.js·脚手架·前端工程化
律宏阔12 小时前
Flutter 调用 Go:从 c-shared + ffigen 到 @Native + Native Assets 踩坑记录
前端·flutter