系列文章目录
Three.js 快速入门教程【一】开启你的 3D Web 开发之旅
Three.js 快速入门教程【二】透视投影相机
Three.js 快速入门教程【三】渲染器
Three.js 快速入门教程【四】三维坐标系
Three.js 快速入门教程【五】动画渲染循环
Three.js 快速入门教程【六】相机控件 OrbitControls
Three.js 快速入门教程【七】常见几何体类型
Three.js 快速入门教程【八】常见材质类型
Three.js 快速入门教程【九】光源类型
文章目录
一、前言
在 Three.js 的三维世界里,材质(Material)就像是给物体穿上的 “衣服”,它决定了物体如何与光线交互,以及最终呈现出的视觉效果。对于前端开发者来说,掌握材质的使用是构建逼真且富有表现力的 3D 场景的关键。本文将带你深入了解 Three.js 中常见的材质类型及其应用。
二、材质的基本概念
在 Three.js 中,材质是 Material 类的实例,用于定义物体的外观属性。每个材质都包含了一些属性,如颜色、透明度、反射率等,这些属性会影响物体在场景中的渲染方式。材质与几何形状(Geometry)结合,才能创建出完整的物体。
三、光的基本概念
在现实世界中,光是一种能量形式,通过照射物体并被物体反射进入我们的眼睛,使我们能够看到物体。在 three.js 的 3D 虚拟场景中,光同样起着类似的作用,它可以照亮场景中的物体,并且可以模拟不同类型的光照效果,如太阳光、点光源、聚光灯等。
ps:尽管光不是构建3D场景必须元素,但想构建逼真炫酷的3D场景是离不开光的,所以光在three.js开发中非常重要,这边只要了解什么是光以及记住光会影响材质就行了,后续有专门篇幅介绍光
四、常见材质类型
1. MeshBasicMaterial(基础网格材质)
MeshBasicMaterial 是最简单的材质,它不受光照影响,始终以固定颜色显示。常用于调试或创建不需要光照效果的简单物体,适用场景例如:快速原型、辅助线框、UI元素等
如果你有阅读该系列教程前几篇文章,你就会发现示例中几何体粗糙模糊没棱角3d效果比较差,因为都是用了基础网格材质类型,基础材质在实际开发中还是比较少用的,更多用来代码演示和调试使用。
构造函数
javascript"> new THREE.MeshBasicMaterial(options)
属性讲解
- color:材质的颜色,默认值为白色(0xffffff)。
- wireframe:是否以线框模式显示,默认值为 false。
示例
javascript">// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建几何体
const geometry = new THREE.BoxGeometry();
// 创建 MeshBasicMaterial 材质
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
// 创建网格对象
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 渲染循环
function animate() {
requestAnimationFrame(animate);
//旋转
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
2. MeshLambertMaterial(Lambert网格材质)
MeshLambertMaterial 是一种基于 Lambert 光照模型的材质,它可以模拟出漫反射的效果,受光照影响,但不产生镜面反射。适合创建具有粗糙表面的物体,像石头、木材等
构造函数
javascript"> new THREE.MeshLambertMaterial(options)
属性讲解
- color:材质的颜色,默认值为白色(0xffffff)。
- emissive:自发光颜色,默认值为黑色(0x000000),即不发光。
示例
javascript">// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建几何体
const geometry = new THREE.BoxGeometry(1,1,1);
// 创建 MeshLambertMaterial 材质
const material = new THREE.MeshLambertMaterial({ color: 0x8844aa });
// 创建网格对象
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
// 添加光源
let light = new THREE.DirectionalLight(0xffffff,4);
light.position.set(2, 2, 2);
scene.add(light);
// 渲染循环
function animate() {
requestAnimationFrame(animate);
//旋转
sphere.rotation.x += 0.01;
sphere.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
3. MeshPhongMaterial(高光网格材质)
MeshPhongMaterial 也是一种基于光照模型的材质,它在 MeshLambertMaterial 的基础上增加了镜面反射效果,可以模拟出有光泽的物体表面。适用于金属、玻璃等材质。
构造函数
javascript"> new THREE.MeshPhongMaterial(options)
属性讲解
- color:材质的颜色,默认值为白色(0xffffff)。
- specular:镜面反射颜色,默认值为灰色(0x111111)。
- shininess:光泽度,值越大,反射越集中,默认值为 30。
示例
javascript">// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建几何体
const geometry = new THREE.CylinderGeometry();
// 创建 MeshPhongMaterial 材质
const material = new THREE.MeshPhongMaterial({
color: 0x0000ff,
specular: 0xffffff, //反射颜色
shininess: 100 //光泽度
});
// 创建网格对象
const cylinder = new THREE.Mesh(geometry, material);
scene.add(cylinder);
// 添加光源
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1);
scene.add(light);
// 渲染循环
function animate() {
requestAnimationFrame(animate);
cylinder.rotation.x += 0.01;
cylinder.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
4. MeshStandardMaterial(标准网格材质)
MeshPhongMaterial 基于物理的渲染(PBR)材质,更准确地模拟真实世界中物体与光线的交互,考虑了漫反射、镜面反射、环境光遮蔽等因素,可创建逼真效果。它可以通过设置金属度和粗糙度属性来模拟不同的材质,从金属到非金属都能很好地表现。
构造函数
javascript"> new THREE.MeshStandardMaterial(options)
属性讲解
- color:材质的颜色,默认值为白色(0xffffff)。
- roughness:粗糙度,值越大,表面越粗糙,默认值为 1。
- metalness:金属度,值越大,表面越像金属,默认值为 0。
示例
javascript">
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建几何体
const geometry = new THREE.ConeGeometry();
// 创建 MeshStandardMaterial 材质
const material = new THREE.MeshStandardMaterial({
color: 0xffff00,
roughness: 0.5,//粗糙度
metalness: 0.8//金属度
});
// 创建网格对象
const cylinder = new THREE.Mesh(geometry, material);
scene.add(cylinder);
// 添加光源
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1);
scene.add(light);
// 渲染循环
function animate() {
requestAnimationFrame(animate);
cylinder.rotation.x += 0.01;
cylinder.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
5. MeshPhysicalMaterial(物理网格材质)
MeshPhysicalMaterial 是 Three.js 里基于物理渲染(PBR,Physically Based Rendering)的一种材质,它在 MeshStandardMaterial 的基础上进行了拓展,提供了更多的参数用于更精细地模拟真实世界中物体的外观和光学特性,从而创建出非常逼真的材质效果。如折射率、透明度等,适用于创建更复杂的材质效果,如液体、半透明物体等
构造函数
javascript"> new THREE.MeshPhysicalMaterial(options)
属性讲解
- clearcoat:清漆层的强度,取值范围是 0 到 1。清漆层可以模拟物体表面的一层透明涂层,如汽车漆、家具表面的清漆等,增加物体表面的光泽感。
- clearcoatRoughness:清漆层的粗糙程度,取值范围是 0 到 1。控制清漆层表面的光滑程度,影响清漆层反射的清晰度。
- ior:折射率(Index of Refraction),取值范围通常在 1 到 2.33 之间。用于控制光线在材质内部折射的程度,不同的材质有不同的折射率,例如水的折射率约为 1.33,玻璃的折射率约为 1.5。
- transmission:透明度(仅适用于透明材质),取值范围是 0 到 1。值为 0 时,材质完全不透明;值为 1 时,材质完全透明,可用于创建玻璃、水等透明物体。
- specularIntensity:镜面反射强度,控制材质表面镜面反射的亮度。
示例
javascript">// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建几何体
const geometry = new THREE.SphereGeometry(1, 32, 32);
// 创建 MeshPhysicalMaterial 材质
const material = new THREE.MeshPhysicalMaterial({
color: 0x00ffff,
roughness: 0.1,//粗糙度
metalness: 0.2,//金属度
clearcoat: 0.8,//清漆层的强度
clearcoatRoughness: 0.2,//清漆层的粗糙程度
ior: 1.5,//折射率
transmission: 0.5,//透明度
specularIntensity: 0.8,//镜面反射强度
});
// 创建网格对象
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// 添加光照
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// 渲染循环
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
五、通用的材质属性
除了上述各个材质特有属性外,在 Three.js 中,许多材质类都继承自 THREE.Material 基类,因此具备一些通用的材质属性。下面介绍一些常用的通用材质属性。
属性名称 | 类型 | 说明 | 默认值 |
---|---|---|---|
color | THREE.Color | 定义材质的基础颜色。可以使用十六进制值、CSS 颜色字符串或者 RGB 值来设置 | 不同材质默认值不同,如 MeshBasicMaterial 默认是 new THREE.Color(0xffffff)(白色) |
opacity | Number | 控制材质的不透明度,取值范围是从 0(完全透明)到 1(完全不透明)。不过,要使 opacity 生效,还需将 transparent 属性设置为 true | 1 |
transparent | Boolean | 指示材质是否透明 | false |
fog | Boolean | 决定材质是否受场景中雾效的影响。如果设置为 false,则该材质不会被雾效所模糊或改变颜色 | true |
receiveShadow | Boolean | 指定材质是否接收阴影。如果要让物体表面显示其他物体投射的阴影,需将此属性设置为 true,同时渲染器的 shadowMap.enabled 也必须设置为 true | false |
castShadow | Boolean | 表示材质是否投射阴影。设置为 true 后,该材质对应的物体在光照下会投射阴影到其他接收阴影的物体表面。 | false |
side | Number | 定义材质的渲染面。可选值有 THREE.FrontSide(只渲染正面)、THREE.BackSide(只渲染背面)和 THREE.DoubleSide(双面渲染) | THREE.FrontSide |
map | THREE.Texture | 材质的纹理贴图,用于给物体表面添加纹理。可以通过加载图片来创建纹理并赋值给该属性 | null |
wireframe | Boolean | 是否以线框模式渲染物体。设置为 true 后,物体会以线框形式显示 | false |
flatShading | Boolean | 是否使用平面着色。设为 true 会让物体表面以平面块的形式显示,产生硬边效果,常用于创建低多边形风格的模型 | false |
示例:带透明六面不同颜色正方体
javascript">import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// 创建场景
const scene = new THREE.Scene();
// 创建坐标轴辅助器
const axesHelper = new THREE.AxesHelper(40);
scene.add(axesHelper);
// 创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建正方体的几何体
const geometry = new THREE.BoxGeometry();
// 为正方体的每个面创建不同颜色的半透明材质
const materials = [
new THREE.MeshLambertMaterial({ color: 0xff0000, transparent: true, opacity: 0.6 }), // 红色
new THREE.MeshLambertMaterial({ color: 0x00ff00, transparent: true, opacity: 0.6 }), // 绿色
new THREE.MeshLambertMaterial({ color: 0x0000ff, transparent: true, opacity: 0.6 }), // 蓝色
new THREE.MeshLambertMaterial({ color: 0xffff00, transparent: true, opacity: 0.6 }), // 黄色
new THREE.MeshLambertMaterial({ color: 0xff00ff, transparent: true, opacity: 0.6 }), // 紫色
new THREE.MeshLambertMaterial({ color: 0x00ffff, transparent: true, opacity: 0.6 }) // 青色
];
// 创建网格对象,将几何体和材质数组传入
const mesh = new THREE.Mesh(geometry, materials);
scene.add(mesh);
// 添加光照
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
let directionalLight = new THREE.DirectionalLight(0xffffff, 10);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0xffffff, 10);
directionalLight.position.set(-1, -1, -1);
scene.add(directionalLight);
// 创建 OrbitControls 控件
const controls = new OrbitControls(camera, renderer.domElement);
// 设置阻尼(惯性),让控件的操作更平滑
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// 渲染循环
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
controls.update();
renderer.render(scene, camera);
}
animate();
通过生成6个不同颜色的材质对象组成数组传递给网格对象构造函数生成6个不同颜色面的立方体
六、 材质的高级应用
纹理映射:除了使用纯色,我们还可以通过纹理(Texture)来为材质添加更丰富的细节。纹理可以是图片、法线贴图、凹凸贴图等。例如,使用 TextureLoader 加载一张图片作为纹理,并应用到 MeshBasicMaterial 上:
核心代码:
javascript">//加载纹理
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('texture.jpg');
//创建立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
//创建材质
const material = new THREE.MeshBasicMaterial({ map: texture });
// 创建网格对象,将几何体和材质传入
const mesh= new THREE.Mesh(geometry, material);
scene.add(mesh);
示例:纹理贴图——自转的地球
javascript">import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建正方体的几何体
const geometry = new THREE.SphereGeometry(1, 32, 32);
// 加载纹理
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('https://pic1.zhimg.com/v2-4f5bc4b2185ff9a57993bca60e6adc90_r.jpg');
// 创建材质并应用纹理
const material =new THREE.MeshLambertMaterial({ map: texture })
// 创建网格对象,将几何体和材质传入
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// 添加环境光
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
// 添加平行光
let directionalLight = new THREE.DirectionalLight(0xffffff, 10);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// 添加平行光2
directionalLight = new THREE.DirectionalLight(0xffffff, 10);
directionalLight.position.set(-1, -1, -1);
scene.add(directionalLight);
// 创建 OrbitControls 控件
const controls = new OrbitControls(camera, renderer.domElement);
// 设置阻尼(惯性),让控件的操作更平滑
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// 渲染循环
function animate() {
requestAnimationFrame(animate);
mesh.rotation.y += 0.01;
controls.update();
renderer.render(scene, camera);
}
animate();
上述代码中我们新建了一个球体几何体和新建一个基础材质并设置纹理属性,纹理对象加载了地球图片,最终呈现一个自转的3D地球效果
五、总结
通过本文的介绍,我们对 Three.js 中的材质有了更深入的了解。从基础的 MeshBasicMaterial 到基于物理的 MeshStandardMaterial 和 MeshPhysicalMaterial,以及材质的高级应用,这些知识将帮助我们创建出更加逼真和富有表现力的 3D 场景。在实际开发中,我们需要根据具体的需求选择合适的材质类型,并不断调整材质的属性,以达到最佳的视觉效果。
更多three.js入门知识点请关注该系列教程后续的更新。