Appearance
材质,华丽的外衣
材质(Material)是 Three.js 中非常重要的概念,它决定了物体表面的外观和光照响应特性。如果说几何体是物体的骨架,那么材质就是物体的皮肤和外衣,给物体带来丰富多彩的视觉效果。通过不同的材质类型和属性配置,我们可以模拟出各种真实世界中的材料效果,如金属、塑料、玻璃、布料等。
在 Three.js 中,每个 Mesh
对象都需要一个几何体(Geometry)和一个材质(Material):
javascript
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(geometry, material);
材质决定了物体的外观特征:
- 颜色(Color):物体的基础颜色
- 透明度(Opacity):物体的透明程度
- 纹理(Texture):贴在物体表面的图像
- 光照响应:物体如何与光源交互
- 反射和折射:物体的反光和透光特性
常用材质
以下材质在开发过程中较为常见,各种材质的构建速度从最快到最慢:MeshBasicMaterial ➡ MeshLambertMaterial ➡ MeshPhongMaterial ➡ MeshStandardMaterial ➡ MeshPhysicalMaterial。构建速度越慢的材质,做出的场景越逼真。
1、MeshBasicMaterial 基础材质
MeshBasicMaterial
是最简单的材质类型,它不受光照影响,总是显示为同样的颜色。这种材质渲染速度最快,适合用于简单的效果或调试时使用。
javascript
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00, // 绿色
transparent: true, // 启用透明
opacity: 0.8, // 透明度
wireframe: false, // 是否显示线框
side: THREE.FrontSide, // 渲染哪一面
});
主要特点:
- 不受光照影响
- 性能最佳
- 颜色均匀分布
适用场景:
- UI 元素
- 调试模型
- 简单的颜色展示
- 对性能要求极高的场景
2、MeshLambertMaterial 兰伯特材质
MeshLambertMaterial
是一种非光泽表面的材质,具有漫反射特性。它能够很好地模拟无光泽表面,如粗糙的纸张、石头或未抛光的木材,但不能模拟具有镜面高光的光泽表面(例如涂漆木材)。
javascript
const material = new THREE.MeshLambertMaterial({
color: 0x00ff00,
emissive: 0x000000, // 自发光颜色
emissiveIntensity: 0, // 自发光强度
transparent: false,
opacity: 1.0,
});
主要特点:
- 漫反射光照模型
- 性能较好
- 受环境光和方向光影响
适用场景:
- 粗糙表面材料,如纸张、布料
- 需要简单光照的场景
3、MeshPhongMaterial 冯氏材质
MeshPhongMaterial
是一种具有镜面高光的材质,能够产生光泽效果。它使用 Phong 反射模型,可以模拟金属、塑料等有光泽的材料。
javascript
const material = new THREE.MeshPhongMaterial({
color: 0x00ff00,
specular: 0x111111, // 镜面反射颜色
shininess: 30, // 光泽度
emissive: 0x000000,
emissiveIntensity: 0,
transparent: false,
opacity: 1.0,
});
主要特点:
- 具有镜面高光
- 能模拟光泽表面
适用场景:
- 金属,塑料、陶瓷等
4、MeshStandardMaterial 标准材质
MeshStandardMaterial
是基于物理的渲染(PBR)材质,是 Three.js 中最先进和最真实的材质类型。它使用金属度和粗糙度来控制材质的外观,能够更准确地模拟真实世界的材料。
javascript
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00,
metalness: 0.0, // 金属度 (0-1)
roughness: 0.5, // 粗糙度 (0-1)
emissive: 0x000000,
emissiveIntensity: 0,
envMapIntensity: 1.0, // 环境贴图强度
transparent: false,
opacity: 1.0,
});
主要特点:
- 基于物理的渲染(PBR)
- 最真实的光照效果
- 支持金属度和粗糙度
- 适合需要高质量渲染的场景
金属度(Metalness):
0.0
:非金属材料(木材、塑料、石头)1.0
:纯金属材料(铁、铜、金)
粗糙度(Roughness):
0.0
:完全光滑,像镜子1.0
:完全粗糙,无反射
适用场景:
- 现代 PBR 渲染
- 需要真实感的场景
- 金属和非金属材料
- 大多数生产环境
5、MeshPhysicalMaterial 物理材质
MeshPhysicalMaterial
是 MeshStandardMaterial
的扩展,提供了更多的物理特性,如透明度、折射、光泽层等高级效果。也正因如此,其性能会低于MeshStandardMaterial
。
javascript
const material = new THREE.MeshPhysicalMaterial({
color: 0x00ff00,
metalness: 0.0,
roughness: 0.0,
transmission: 1.0, // 透射率
thickness: 1.0, // 厚度
ior: 1.5, // 折射率
clearcoat: 1.0, // 透明涂层
clearcoatRoughness: 0.0, // 涂层粗糙度
});
主要特点:
- 支持透明和折射效果
- 清漆涂层效果
- 最高质量的渲染
- 性能消耗最大
适用场景:
- 玻璃、水晶等透明材料
- 汽车漆面效果
- 高端产品展示
- 对视觉质量要求最高的场景
6、常用材质示例
下面在同一个场景中创建不同的材质,便于观察各材质的区别。
javascript
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// 场景对象
const scene = new THREE.Scene();
scene.background = new THREE.Color("#000000");
// 渲染器
const canvas = document.querySelector("#canvas") as HTMLCanvasElement;
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true; // 开启阴影
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 软阴影
// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 15);
camera.lookAt(0, 0, 0);
// 轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 创建环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// 创建主光源
const mainLight = new THREE.DirectionalLight(0xffffff, 1);
mainLight.position.set(5, 8, 5);
mainLight.castShadow = true;
mainLight.intensity = 2;
scene.add(mainLight);
// 创建辅助光源
const secondaryLight = new THREE.DirectionalLight(0xffffff, 0.3);
secondaryLight.position.set(-5, 5, -5);
scene.add(secondaryLight);
// 创建球体几何体(所有球体使用相同的几何体)
const sphereGeometry = new THREE.SphereGeometry(1, 32, 32);
// 从左到右按顺序创建5个球体
// 1. MeshBasicMaterial - 基础材质
const basicMaterial = new THREE.MeshBasicMaterial({
color: "#ff6b6b",
wireframe: false,
});
const basicSphere = new THREE.Mesh(sphereGeometry, basicMaterial);
basicSphere.position.set(-8, 0, 0);
scene.add(basicSphere);
// 2. MeshLambertMaterial - 兰伯特材质
const lambertMaterial = new THREE.MeshLambertMaterial({
color: "#4ecdc4",
});
const lambertSphere = new THREE.Mesh(sphereGeometry, lambertMaterial);
lambertSphere.position.set(-4, 0, 0);
scene.add(lambertSphere);
// 3. MeshPhongMaterial - 冯氏材质
const phongMaterial = new THREE.MeshPhongMaterial({
color: "#45b7d1",
shininess: 100, // 光泽度,值越大越亮
specular: "#ffffff", // 镜面反射颜色
});
const phongSphere = new THREE.Mesh(sphereGeometry, phongMaterial);
phongSphere.position.set(0, 0, 0);
scene.add(phongSphere);
// 4. MeshStandardMaterial - 标准材质
const standardMaterial = new THREE.MeshStandardMaterial({
color: "#f7b731",
metalness: 0.3, // 金属度:0=非金属,1=完全金属
roughness: 0.4, // 粗糙度:0=光滑镜面,1=完全粗糙
});
const standardSphere = new THREE.Mesh(sphereGeometry, standardMaterial);
standardSphere.position.set(4, 0, 0);
scene.add(standardSphere);
// 5. MeshPhysicalMaterial - 物理材质
const physicalMaterial = new THREE.MeshPhysicalMaterial({
color: "#a55eea",
metalness: 0.7,
roughness: 0.2,
clearcoat: 1.0, // 清漆层强度
clearcoatRoughness: 0.1, // 清漆层粗糙度
transmission: 0.1, // 透射程度
thickness: 0.5, // 厚度(影响透射效果)
});
const physicalSphere = new THREE.Mesh(sphereGeometry, physicalMaterial);
physicalSphere.position.set(8, 0, 0);
scene.add(physicalSphere);
// 渲染循环
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// 窗口大小改变时,更新渲染器和相机
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
PBR材质
PBR 材质,全称是 Physically Based Rendering(基于物理的渲染) 材质,是一种更加真实模拟光照与材质交互的渲染方式。它广泛用于现代 3D 引擎(如 Three.js、Unity、Unreal)中,以提升图像的真实感。上述常用材质中的MeshStandardMaterial
和MeshPhysicalMaterial
属于PBR材质。
1、核心理念
PBR 不是某种具体的材质,而是一种渲染方法论,它基于物理原理模拟光的行为,让材质在不同光照环境下具有一致且真实的外观。
2、常见属性
PBR 材质通常使用以下几种贴图或参数:
属性 | 含义说明 |
---|---|
Albedo / Base Color | 材质的基础颜色,不包含阴影、光照或高光。 |
Metallic(金属度) | 控制表面是否为金属,非金属为 0,纯金属为 1。 |
Roughness(粗糙度) | 控制表面光滑或粗糙程度,0 是非常光滑(有清晰高光),1 是完全粗糙(无高光)。 |
Normal Map | 模拟表面细节纹理(如凹凸),不改变几何形状。 |
AO(Ambient Occlusion)环境光遮蔽 | 模拟角落等区域的阴影,增加空间感。 |
Height / Displacement | 提供表面凹凸的实际位移效果(可选,用于高级效果)。 |
3、属性示例
(1)roughness(粗糙度)从0-1的变化,图中从左到右的值依次为:0, 0.25, 0.5, 0.75, 1.0。
javascript
for (let i = 0; i < 5; i++) {
const roughness = i / 4; // 0, 0.25, 0.5, 0.75, 1.0
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00, // 绿色
roughness: roughness,
metalness: 0.0, // 非金属
});
const mesh = new THREE.Mesh(sphereGeometry, material);
mesh.castShadow = true;
mesh.position.set(i * 3 - 6, 2, 6);
scene.add(mesh);
}
(2)metalness(金属度)从0-1的变化,图中从左到右的值依次为:0, 0.25, 0.5, 0.75, 1.0。
javascript
for (let i = 0; i < 5; i++) {
const metalness = i / 4; // 0, 0.25, 0.5, 0.75, 1.0
const material = new THREE.MeshStandardMaterial({
color: 0xff6600, // 橙色
roughness: 0.1, // 保持较低粗糙度以突出金属效果
metalness: metalness,
});
const mesh = new THREE.Mesh(sphereGeometry, material);
mesh.position.set(i * 3 - 6, 2, 2);
mesh.castShadow = true;
scene.add(mesh);
}
ShaderMaterial材质
1、基本概念
在 Three.js 中,ShaderMaterial(着色器材质) 是一种允许你使用 自定义 GLSL 着色器代码 来完全控制材质外观的方式。它是 Three.js 提供的最底层、最灵活的材质类型,适合需要实现复杂视觉效果或非标准渲染的场景。
很多酷炫的效果都是使用它来完成的,例如渐变的立方体等效果。关于该材质的更多介绍将在后续文章中做详细说明,此处只了解基本概念即可。
2、示例效果
通过ShaderMaterial材质创建一个渐变的立方体。
javascript
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// 场景对象
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);
// 渲染器
const canvas = document.querySelector("#canvas") as HTMLCanvasElement;
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(200, 200, 0);
camera.lookAt(0, 0, 0);
// 轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 创建网格
const size = 100;
const divisions = 10;
const gridHelper = new THREE.GridHelper(size, divisions);
scene.add(gridHelper);
// 创建立方体
const geometry = new THREE.BoxGeometry(20, 60, 20);
// 创建渐变材质
const material = new THREE.ShaderMaterial({
uniforms: {
topColor: { value: new THREE.Color(0.5, 0.8, 1.0) },
bottomColor: { value: new THREE.Color(0.1, 0.1, 0.5) },
},
vertexShader: `
varying vec2 vUv;
varying vec3 vNormal;
void main() {
vUv = uv;
vNormal = normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform vec3 topColor;
uniform vec3 bottomColor;
varying vec2 vUv;
varying vec3 vNormal;
void main() {
vec3 color;
if (vNormal.y > 0.99) {
color = bottomColor; // 底部颜色
} else if (vNormal.y < -0.99) {
color = topColor; // 顶部颜色
} else {
color = mix(topColor, bottomColor, vUv.y);
}
gl_FragColor = vec4(color, 1.0);
}
`,
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y += 30;
scene.add(mesh);
// 渲染循环
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// 窗口大小改变时,更新渲染器和相机
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});