在 Three.js 的 3D 宇宙里,每一个物体都渴望拥有独一无二的 "皮肤"------ 物理材质(Physical Materials),它可不是简单的 "外衣",而是决定物体如何与光线共舞、展现真实质感的关键角色。今天,我们就来揭开物理材质的神秘面纱,看看如何用代码赋予物体逼真的外观!
一、物理材质:3D 世界的 "魔术师"
物理材质基于物理渲染(PBR,Physically Based Rendering)原理,它就像一位严谨的科学家,遵循现实世界中光线与物体表面相互作用的规律。在真实世界里,光线遇到不同材质的物体时,会发生反射、折射、吸收等现象,物理材质就是要在虚拟的 3D 世界中复刻这些神奇的过程。
想象一下,你面前有一块闪闪发光的金属和一块哑光的木头。金属表面光滑,光线大部分被反射,所以看起来亮堂堂的;而木头表面粗糙,光线被散射和吸收,显得比较暗淡。物理材质通过一系列参数,来模拟这些不同材质对光线的独特反应,让 3D 物体看起来和真实世界中的一模一样。
二、Three.js 中的物理材质家族
在 Three.js 里,物理材质主要有MeshStandardMaterial和MeshPhysicalMaterial这两位 "明星成员"。MeshStandardMaterial是基础款,能满足大部分常见材质的需求;而MeshPhysicalMaterial则更加强大,支持更多高级特性,就像 "豪华升级版"。
创建一个简单的物理材质物体非常容易,就像给孩子搭积木一样:
csharp
// 创建一个MeshStandardMaterial材质
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00, // 设置颜色为绿色
roughness: 0.5, // 设置粗糙度,数值越大越粗糙
metalness: 0.0 // 设置金属度,0表示非金属,1表示完全金属
});
// 创建一个几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 创建一个网格对象,将几何体和材质组合起来
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
在这段代码里,我们首先创建了一个MeshStandardMaterial材质,设置了它的颜色、粗糙度和金属度。然后创建了一个立方体几何体,最后把几何体和材质组合成一个网格对象,并添加到场景中。这样,一个绿色、半粗糙的非金属立方体就出现在我们的 3D 世界里啦!
三、深入探索物理材质的参数
物理材质的参数就像是魔法师的咒语,每一个参数的调整都会带来不同的效果。
1. 颜色(color)
颜色参数就像给物体穿上不同颜色的衣服。它可以接受十六进制颜色值(如0x00ff00表示绿色)、RGB 值(new THREE.Color(0, 1, 0)也表示绿色),甚至可以通过调整颜色的r(红色分量)、g(绿色分量)、b(蓝色分量)属性来动态改变颜色。比如:
ini
const material = new THREE.MeshStandardMaterial();
material.color.r = 0.2;
material.color.g = 0.8;
material.color.b = 0.3;
这样,物体就会变成一种独特的黄绿色。
2. 粗糙度(roughness)
粗糙度参数控制物体表面的粗糙程度,就像砂纸一样。数值从 0 到 1,0 表示表面像镜子一样光滑,光线会规则反射;1 表示表面非常粗糙,光线会向四面八方散射。比如,制作一个镜面材质的物体,就把粗糙度设为 0:
php
const mirrorMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0,
metalness: 1
});
而制作一块布满灰尘的石头,就可以把粗糙度设得高一些:
php
const stoneMaterial = new THREE.MeshStandardMaterial({
color: 0x8b4513,
roughness: 0.8,
metalness: 0
});
3. 金属度(metalness)
金属度参数决定物体像金属的程度。0 表示完全非金属,比如木头、塑料;1 表示完全金属,像不锈钢、黄金。不同的金属度会影响光线的反射和吸收特性。例如,制作一个铜制的雕塑:
php
const copperMaterial = new THREE.MeshStandardMaterial({
color: 0xb87333,
roughness: 0.3,
metalness: 0.9
});
4. 环境光遮蔽(aoMap & aoMapIntensity)
环境光遮蔽就像给物体添加 "阴影细节"。aoMap(环境光遮蔽贴图)是一张灰度图,用来表示物体表面不同区域受到环境光影响的程度;aoMapIntensity(环境光遮蔽强度)则控制这种效果的强弱。想象一下,一个古老的石雕,缝隙处因为长期积灰,显得比较暗,就可以用环境光遮蔽来模拟这种效果:
php
const aoMap = new THREE.TextureLoader().load('ao_map.jpg');
const stoneMaterial = new THREE.MeshStandardMaterial({
color: 0x8b4513,
roughness: 0.8,
metalness: 0,
aoMap: aoMap,
aoMapIntensity: 0.5
});
5. 法线贴图(normalMap & normalScale)
法线贴图就像给物体表面 "伪造细节"。它是一张 RGB 图,通过改变表面的法线方向(可以理解为表面的 "朝向"),让平坦的表面看起来有凹凸起伏的效果。比如,制作一块表面有纹路的木板,不需要真的创建复杂的几何体,用一张法线贴图就能实现:
php
const normalMap = new THREE.TextureLoader().load('normal_map.jpg');
const woodMaterial = new THREE.MeshStandardMaterial({
color: 0x8b4513,
roughness: 0.6,
metalness: 0,
normalMap: normalMap,
normalScale: new THREE.Vector2(1, 1)
});
normalScale参数用来控制法线贴图效果的强弱,数值越大,凹凸感越明显。
四、让物理材质与光线共舞
物理材质的逼真效果离不开光线的配合。在 Three.js 中,常见的光源类型有环境光(AmbientLight)、点光源(PointLight)、平行光(DirectionalLight)和聚光灯(SpotLight)。不同的光源会以不同的方式照亮物体,影响物理材质的最终表现。
比如,用一个点光源照亮物体,就像在黑暗中打开一盏台灯:
ini
const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.position.set(2, 2, 2);
scene.add(pointLight);
而平行光就像太阳光线,会均匀地从一个方向照射过来:
ini
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
调整光源的位置、颜色和强度,再结合物理材质的参数,就能创造出千变万化的光影效果,让你的 3D 世界栩栩如生!
五、实战演练:打造一个科幻场景
现在,我们用学到的知识来打造一个充满未来感的科幻场景。场景中有一个发光的能量核心、金属质感的墙壁和地面,还有一些带有复杂纹理的机械装置。
ini
// 创建场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建能量核心材质
const energyCoreMaterial = new THREE.MeshStandardMaterial({
color: 0x00ffff,
roughness: 0.1,
metalness: 0.2,
emissive: 0x00ffff, // 让物体自发光
emissiveIntensity: 2
});
// 创建能量核心几何体和网格对象
const energyCoreGeometry = new THREE.SphereGeometry(1, 32, 32);
const energyCore = new THREE.Mesh(energyCoreGeometry, energyCoreMaterial);
scene.add(energyCore);
// 创建金属墙壁材质
const metalWallMaterial = new THREE.MeshStandardMaterial({
color: 0x808080,
roughness: 0.2,
metalness: 0.8
});
// 创建金属墙壁几何体和网格对象
const metalWallGeometry = new THREE.BoxGeometry(10, 5, 0.1);
const metalWall = new THREE.Mesh(metalWallGeometry, metalWallMaterial);
metalWall.position.y = 2.5;
scene.add(metalWall);
// 创建地面材质
const groundMaterial = new THREE.MeshStandardMaterial({
color: 0x444444,
roughness: 0.5,
metalness: 0.1
});
// 创建地面几何体和网格对象
const groundGeometry = new THREE.PlaneGeometry(20, 20);
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
scene.add(ground);
// 添加光源
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.position.set(3, 3, 3);
scene.add(pointLight);
// 动画循环
function animate() {
requestAnimationFrame(animate);
energyCore.rotation.x += 0.01;
energyCore.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
在这个例子中,我们创建了不同材质的物体,设置了合适的参数,并添加了光源。能量核心通过自发光属性模拟出发光的效果,金属墙壁和地面展现出不同的金属和粗糙质感。通过不断调整参数和添加更多元素,你可以打造出更加复杂、惊艳的 3D 场景!
六、总结与展望
物理材质是 Three.js 中让 3D 物体 "活" 起来的关键技术。通过调整颜色、粗糙度、金属度等参数,结合不同类型的光源,我们可以创造出逼真的材质效果,构建出丰富多彩的 3D 世界。
随着技术的不断发展,物理渲染的效果会越来越真实,Three.js 也会提供更多强大的功能和特性。希望这篇文章能让你对 Three.js 的物理材质有更深入的理解,现在就动手试试,用代码创造属于你的 3D 奇迹吧!如果在实践中遇到问题,或者有新的创意,欢迎一起交流分享,让我们共同探索 Three.js 的无限可能!
上述文章涵盖了 Three.js 物理材质的基础和实践。如果你想深入了解某部分内容,或者有特定效果想实现,欢迎随时告诉我。