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