Three.js 材质 #

材质(Material)决定了物体的外观,包括颜色、光泽度、透明度等属性。Three.js 提供了多种材质类型,从简单的基础材质到复杂的物理材质。

材质概述 #

text
┌─────────────────────────────────────────────────────────────┐
│                    Three.js 材质分类                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │   基础材质    │  │   高级材质   │  │   特殊材质   │         │
│  ├─────────────┤  ├─────────────┤  ├─────────────┤         │
│  │MeshBasicMat │  │MeshStandard │  │ShaderMaterial│         │
│  │MeshLambert  │  │MeshPhysical │  │RawShaderMat │         │
│  │MeshPhong    │  │MeshToon     │  │LineMaterial │         │
│  │MeshNormal   │  │             │  │PointsMaterial│        │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│                                                              │
└─────────────────────────────────────────────────────────────┘

基础材质 #

MeshBasicMaterial #

最简单的材质,不受光照影响,适合创建纯色物体或调试。

javascript
const material = new THREE.MeshBasicMaterial({
  color: 0xff0000,
  wireframe: false,
  transparent: false,
  opacity: 1.0
});

常用属性 #

属性 类型 默认值 描述
color Color 0xffffff 颜色
wireframe Boolean false 是否显示线框
transparent Boolean false 是否透明
opacity Number 1.0 透明度
visible Boolean true 是否可见
side Side FrontSide 渲染面

使用示例 #

javascript
const geometry = new THREE.BoxGeometry(1, 1, 1);

const solidMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const solidCube = new THREE.Mesh(geometry, solidMaterial);
solidCube.position.x = -1.5;

const wireframeMaterial = new THREE.MeshBasicMaterial({
  color: 0x00ff00,
  wireframe: true
});
const wireframeCube = new THREE.Mesh(geometry, wireframeMaterial);
wireframeCube.position.x = 1.5;

scene.add(solidCube, wireframeCube);

MeshLambertMaterial #

Lambert 材质模拟漫反射表面,适合哑光材质如木材、布料。

javascript
const material = new THREE.MeshLambertMaterial({
  color: 0xff6b6b,
  emissive: 0x000000
});

属性说明 #

属性 类型 默认值 描述
color Color 0xffffff 漫反射颜色
emissive Color 0x000000 自发光颜色
wireframe Boolean false 线框模式

MeshPhongMaterial #

Phong 材质支持镜面高光,适合光滑表面如塑料、金属。

javascript
const material = new THREE.MeshPhongMaterial({
  color: 0xff6b6b,
  specular: 0xffffff,
  shininess: 100,
  emissive: 0x000000
});

属性说明 #

属性 类型 默认值 描述
color Color 0xffffff 漫反射颜色
specular Color 0x111111 高光颜色
shininess Number 30 高光强度
emissive Color 0x000000 自发光颜色

不同光泽度效果 #

javascript
const materials = [
  new THREE.MeshPhongMaterial({ color: 0xff6b6b, shininess: 10 }),
  new THREE.MeshPhongMaterial({ color: 0xff6b6b, shininess: 50 }),
  new THREE.MeshPhongMaterial({ color: 0xff6b6b, shininess: 100 }),
  new THREE.MeshPhongMaterial({ color: 0xff6b6b, shininess: 200 })
];

materials.forEach((material, index) => {
  const sphere = new THREE.Mesh(
    new THREE.SphereGeometry(0.5, 32, 16),
    material
  );
  sphere.position.x = index * 1.5 - 2.25;
  scene.add(sphere);
});

MeshNormalMaterial #

法线材质将法线方向映射为颜色,常用于调试。

javascript
const material = new THREE.MeshNormalMaterial({
  flatShading: false
});

高级材质 #

MeshStandardMaterial #

基于物理的渲染(PBR)材质,是现代 3D 渲染的标准选择。

javascript
const material = new THREE.MeshStandardMaterial({
  color: 0xff6b6b,
  metalness: 0.5,
  roughness: 0.5,
  envMapIntensity: 1.0
});

核心属性 #

属性 类型 默认值 范围 描述
color Color 0xffffff - 基础颜色
metalness Number 0.0 0-1 金属度
roughness Number 0.5 0-1 粗糙度
emissive Color 0x000000 - 自发光颜色
emissiveIntensity Number 1.0 0-∞ 自发光强度
envMapIntensity Number 1.0 0-∞ 环境贴图强度

金属度与粗糙度 #

text
金属度 (Metalness)
┌─────────────────────────────────────────┐
│  0.0              0.5              1.0  │
│  │                │                │    │
│  ▼                ▼                ▼    │
│ 非金属          半金属           金属    │
│ (塑料、木材)    (金属涂层)      (金、银)  │
└─────────────────────────────────────────┘

粗糙度 (Roughness)
┌─────────────────────────────────────────┐
│  0.0              0.5              1.0  │
│  │                │                │    │
│  ▼                ▼                ▼    │
│ 光滑             半粗糙           粗糙   │
│ (镜子、金属)     (哑光金属)      (混凝土) │
└─────────────────────────────────────────┘

不同材质效果 #

javascript
const presets = {
  plastic: { metalness: 0.0, roughness: 0.5 },
  metal: { metalness: 1.0, roughness: 0.3 },
  gold: { metalness: 1.0, roughness: 0.2, color: 0xffd700 },
  copper: { metalness: 1.0, roughness: 0.4, color: 0xb87333 },
  glass: { metalness: 0.0, roughness: 0.0, transparent: true, opacity: 0.5 },
  rubber: { metalness: 0.0, roughness: 0.9 },
  concrete: { metalness: 0.0, roughness: 1.0 }
};

const material = new THREE.MeshStandardMaterial(presets.gold);

MeshPhysicalMaterial #

MeshPhysicalMaterial 是 MeshStandardMaterial 的扩展,提供更多物理属性。

javascript
const material = new THREE.MeshPhysicalMaterial({
  color: 0xffffff,
  metalness: 0.0,
  roughness: 0.0,
  clearcoat: 1.0,
  clearcoatRoughness: 0.1,
  transmission: 0.9,
  thickness: 0.5,
  ior: 1.5
});

高级属性 #

属性 类型 默认值 描述
clearcoat Number 0.0 清漆层强度
clearcoatRoughness Number 0.0 清漆层粗糙度
transmission Number 0.0 透光度
thickness Number 0.0 厚度
ior Number 1.5 折射率
sheen Number 0.0 光泽度
sheenColor Color 0x000000 光泽颜色
iridescence Number 0.0 彩虹色效果

玻璃材质 #

javascript
const glassMaterial = new THREE.MeshPhysicalMaterial({
  color: 0xffffff,
  metalness: 0,
  roughness: 0,
  transmission: 0.95,
  thickness: 0.5,
  ior: 1.5,
  transparent: true
});

汽车漆材质 #

javascript
const carPaintMaterial = new THREE.MeshPhysicalMaterial({
  color: 0xff0000,
  metalness: 0.5,
  roughness: 0.3,
  clearcoat: 1.0,
  clearcoatRoughness: 0.1
});

MeshToonMaterial #

卡通材质,实现卡通渲染效果。

javascript
const material = new THREE.MeshToonMaterial({
  color: 0xff6b6b,
  gradientMap: null
});

自定义渐变 #

javascript
const gradientMap = new THREE.DataTexture(
  new Uint8Array([0, 0, 0, 100, 100, 100, 200, 200, 200, 255, 255, 255]),
  4, 1, THREE.RGBFormat
);

const material = new THREE.MeshToonMaterial({
  color: 0xff6b6b,
  gradientMap: gradientMap
});

特殊材质 #

ShaderMaterial #

自定义着色器材质,提供最大的灵活性。

javascript
const material = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0.0 },
    uColor: { value: new THREE.Color(0xff0000) }
  },
  vertexShader: `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform float uTime;
    uniform vec3 uColor;
    varying vec2 vUv;
    void main() {
      float wave = sin(vUv.x * 10.0 + uTime) * 0.5 + 0.5;
      gl_FragColor = vec4(uColor * wave, 1.0);
    }
  `
});

PointsMaterial #

粒子点材质。

javascript
const material = new THREE.PointsMaterial({
  color: 0xff0000,
  size: 0.1,
  sizeAttenuation: true
});

const points = new THREE.Points(geometry, material);
scene.add(points);

LineBasicMaterial #

基础线条材质。

javascript
const material = new THREE.LineBasicMaterial({
  color: 0xffffff,
  linewidth: 2
});

const line = new THREE.Line(geometry, material);
scene.add(line);

LineDashedMaterial #

虚线材质。

javascript
const material = new THREE.LineDashedMaterial({
  color: 0xffffff,
  dashSize: 0.1,
  gapSize: 0.05
});

const line = new THREE.Line(geometry, material);
line.computeLineDistances();
scene.add(line);

材质属性详解 #

颜色(Color) #

javascript
material.color = new THREE.Color(0xff0000);

material.color = new THREE.Color(1, 0, 0);

material.color = new THREE.Color('red');

material.color.setHex(0xff0000);
material.color.setRGB(1, 0, 0);
material.color.setHSL(0, 1, 0.5);

透明度(Opacity) #

javascript
material.transparent = true;
material.opacity = 0.5;

material.alphaTest = 0.5;

渲染面(Side) #

javascript
material.side = THREE.FrontSide;
material.side = THREE.BackSide;
material.side = THREE.DoubleSide;

深度测试 #

javascript
material.depthTest = true;
material.depthWrite = true;

混合模式 #

javascript
material.blending = THREE.NormalBlending;
material.blending = THREE.AdditiveBlending;
material.blending = THREE.SubtractiveBlending;
material.blending = THREE.MultiplyBlending;

材质纹理 #

基础纹理贴图 #

javascript
const textureLoader = new THREE.TextureLoader();

const material = new THREE.MeshStandardMaterial({
  map: textureLoader.load('diffuse.jpg'),
  normalMap: textureLoader.load('normal.jpg'),
  roughnessMap: textureLoader.load('roughness.jpg'),
  metalnessMap: textureLoader.load('metalness.jpg'),
  aoMap: textureLoader.load('ao.jpg'),
  emissiveMap: textureLoader.load('emissive.jpg')
});

纹理类型 #

纹理类型 属性名 用途
漫反射贴图 map 基础颜色
法线贴图 normalMap 表面细节
粗糙度贴图 roughnessMap 粗糙度变化
金属度贴图 metalnessMap 金属度变化
环境光遮蔽 aoMap 遮蔽效果
自发光贴图 emissiveMap 自发光区域
凹凸贴图 bumpMap 凹凸效果
透明贴图 alphaMap 透明区域

纹理属性设置 #

javascript
const texture = textureLoader.load('texture.jpg');

texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(2, 2);

texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;

texture.anisotropy = renderer.capabilities.getMaxAnisotropy();

material.map = texture;

材质克隆与复制 #

克隆材质 #

javascript
const clonedMaterial = material.clone();

clonedMaterial.color.setHex(0x00ff00);

复制属性 #

javascript
const newMaterial = new THREE.MeshStandardMaterial();
newMaterial.copy(material);

材质数组 #

为几何体的不同面使用不同材质。

javascript
const materials = [
  new THREE.MeshBasicMaterial({ color: 0xff0000 }),
  new THREE.MeshBasicMaterial({ color: 0x00ff00 }),
  new THREE.MeshBasicMaterial({ color: 0x0000ff }),
  new THREE.MeshBasicMaterial({ color: 0xffff00 }),
  new THREE.MeshBasicMaterial({ color: 0xff00ff }),
  new THREE.MeshBasicMaterial({ color: 0x00ffff })
];

const geometry = new THREE.BoxGeometry(1, 1, 1);
const cube = new THREE.Mesh(geometry, materials);
scene.add(cube);

材质对比表 #

材质类型 光照 高光 性能 适用场景
MeshBasicMaterial 调试、UI
MeshLambertMaterial 哑光表面
MeshPhongMaterial 光滑表面
MeshStandardMaterial 真实渲染
MeshPhysicalMaterial 高级效果
MeshToonMaterial 卡通风格
ShaderMaterial 自定义 自定义 可变 自定义效果

最佳实践 #

选择合适的材质 #

javascript
// 简单颜色,无需光照
const basicMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });

// 哑光表面
const lambertMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });

// 光滑表面,需要高光
const phongMaterial = new THREE.MeshPhongMaterial({
  color: 0xff0000,
  shininess: 100
});

// 真实渲染
const standardMaterial = new THREE.MeshStandardMaterial({
  color: 0xff0000,
  metalness: 0.5,
  roughness: 0.5
});

// 高级效果(玻璃、清漆)
const physicalMaterial = new THREE.MeshPhysicalMaterial({
  color: 0xff0000,
  transmission: 0.9
});

性能优化 #

javascript
// 复用材质
const sharedMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const mesh1 = new THREE.Mesh(geometry1, sharedMaterial);
const mesh2 = new THREE.Mesh(geometry2, sharedMaterial);

// 及时释放
material.dispose();
texture.dispose();

完整示例 #

javascript
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(5, 5, 5);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.0;
document.body.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);

const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);

const pointLight = new THREE.PointLight(0xffffff, 0.5);
pointLight.position.set(-5, 5, -5);
scene.add(pointLight);

const materials = {
  basic: new THREE.MeshBasicMaterial({ color: 0xff6b6b }),
  lambert: new THREE.MeshLambertMaterial({ color: 0xff6b6b }),
  phong: new THREE.MeshPhongMaterial({ color: 0xff6b6b, shininess: 100 }),
  standard: new THREE.MeshStandardMaterial({ color: 0xff6b6b, metalness: 0.5, roughness: 0.5 }),
  physical: new THREE.MeshPhysicalMaterial({ color: 0xff6b6b, clearcoat: 1.0 }),
  toon: new THREE.MeshToonMaterial({ color: 0xff6b6b })
};

const geometry = new THREE.SphereGeometry(0.5, 32, 16);

Object.entries(materials).forEach(([name, material], index) => {
  const mesh = new THREE.Mesh(geometry, material);
  const row = Math.floor(index / 3);
  const col = index % 3;
  mesh.position.set(col * 2 - 2, 0, row * 2);
  scene.add(mesh);
});

function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}
animate();

下一步 #

现在你已经掌握了材质系统,接下来学习 光照,为场景添加光源!

最后更新:2026-03-28