PBR材质
本教程共 40 篇 · 第 14 篇 · 更新于 2026-08-14 · 约 8 分钟阅读
本节目标:理解 PBR 的概念,掌握 MeshStandardMaterial 的 roughness 与 metalness 两大核心参数,学会 MeshPhysicalMaterial 的 clearcoat、transmission、sheen 等高级属性。
PBR 是什么
PBR(Physically Based Rendering,基于物理的渲染)是用真实物理规律计算”光打到表面后怎么反射”的渲染技术。它由 Disney 为动画电影提出,后来成为游戏引擎(Unreal、Frostbite)的行业标准。最大的好处是材质参数的含义贴近真实世界,调起来有直觉——“这是金属还是塑料?粗糙还是光滑?“——而不是盲目调一堆魔法数字。
three.js 的 PBR 材质有两个:MeshStandardMaterial(标准)和 MeshPhysicalMaterial(物理增强)。使用它们必须配灯光或环境贴图,否则表面是全黑的。
PBR 还有一个好处:材质在不同光照条件下表现一致。传统材质在日光场景里调好的参数,换到夜景就全废;PBR 材质只要参数符合真实世界,白天黑夜都成立。调材质时只需要回答两个问题:表面是金属吗?表面有多粗糙?剩下交给物理公式。
MeshStandardMaterial:标准 PBR 材质
它是 three.js 的主力材质,能模拟绝大多数日常表面:木材、石材、金属、塑料、橡胶……核心参数只有两个:roughness 和 metalness。
const material = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0.4, // 粗糙度 0~1,默认 1
metalness: 0.2, // 金属度 0~1,默认 0
});
roughness 粗糙度
表面”磨砂程度”:0 是镜面般光滑,1 是完全粗糙(以漫反射为主)。
- roughness = 0:像抛光的镜子,高光又亮又清晰;
- roughness = 0.3:像亚克力、湿石头,高光柔和;
- roughness = 1:像哑光涂料、纸,几乎没有高光。
默认值是 1。很多新手忘了调,物体看起来”灰蒙蒙的”,把 roughness 降到 0.3 左右立刻精神起来。
真实材质的 roughness 有大致参考值:抛光金属 0.10.3,塑料 0.4 左右,木材 0.60.9,粗糙石头接近 1。做材质时先按参考值起步,再微调。
metalness 金属度
表面”像金属的程度”:0 是非金属(塑料、木头、皮肤),1 是纯金属(金、银、铁)。
- metalness = 0:非金属,反射弱,颜色以自身颜色为主;
- metalness = 1:金属,几乎只反射环境,自身颜色变淡;
- 中间值:生锈的金属、脏金属。
Note金属度高的物体必须配合环境贴图(envMap)或足够丰富的灯光才好看。纯金属几乎不产生漫反射,场景里只有一两盏灯时,会黑得发闷。这是正常的物理现象,不是 bug。环境贴图在第 18 章光照模型与渲染原理会展开。
纹理槽位
MeshStandardMaterial 除了 color,还有一整套纹理槽位(第 15、16 章展开):
map:颜色贴图,给表面铺上图案;normalMap:法线贴图,给平面加凹凸细节(不改变形状,只改变光照);roughnessMap/metalnessMap:逐像素控制粗糙度和金属度;aoMap:环境光遮蔽贴图,加深缝隙和角落的阴影;emissive与emissiveMap:自发光,注意自发光不会照亮别人;envMap:环境贴图,提供反射来源。
其他常用属性
flatShading(平面着色)、wireframe、transparent / opacity、side 都是第 12 章讲过的通用属性,Standard 全部支持。另有 envMapIntensity 控制环境贴图强度,默认 1。
MeshPhysicalMaterial:Standard 的增强版
MeshPhysicalMaterial 继承自 MeshStandardMaterial,拥有它的全部能力,再叠加一摞高级属性。默认行为和 Standard 完全一致,可以无缝替换。它比 Standard 贵(渲染开销更大),只在需要特殊效果时用。
clearcoat 清漆层
在表面叠一层”透明漆”,模拟车漆、钢琴漆、抛光木器:底层有颜色和粗糙度,上层是光亮清漆。
const material = new THREE.MeshPhysicalMaterial({
color: 0xcc3333,
clearcoat: 1, // 清漆强度 0~1,默认 0
clearcoatRoughness: 0.1, // 清漆层的粗糙度,默认 0(最光滑)
});
clearcoatRoughness 控制清漆层本身的光滑度,0 是镜面漆,越大越像磨砂漆。
transmission 透射:玻璃效果
transmission: 1 让物体像玻璃一样透光,能看到后面的物体。常搭配三个参数:
const material = new THREE.MeshPhysicalMaterial({
transmission: 1, // 开启透射
thickness: 0.5, // 厚度,0 表示薄壁玻璃
ior: 1.5, // 折射率,默认 1.5;水约 1.33,玻璃 1.5~1.9
roughness: 0.05, // 表面越光滑,透射越清晰
transparent: true, // 通常搭配透明使用
});
Tiptransmission 开销很大,而且场景里要有足够的内容在物体后面,才看得出”透”的效果。测试时放几个彩色物体在玻璃后面。
sheen 天鹅绒与布料
sheen 模拟天鹅绒、丝绸这类”边缘发亮”的布料质感,有自己独立的颜色和粗糙度:
const material = new THREE.MeshPhysicalMaterial({
color: 0x8822aa,
sheen: 1, // 强度 0~1,默认 0
sheenColor: 0xff88cc, // 绒毛的颜色
sheenRoughness: 0.6, // 绒毛粗糙度,默认 1
});
更多高级属性(认识即可)
iridescence:虹彩效果,肥皂泡、油膜,配合iridescenceIOR使用;specularIntensity/specularColor:调整非金属的镜面反射强度和颜色;anisotropy:各向异性高光,拉丝金属、光盘背面,配合anisotropyRotation;reflectivity:非金属反射率,默认 0.5(对应折射率 1.5);dispersion:色散,透明物体的彩虹色边缘;attenuationColor/attenuationDistance:光在透射介质中被吸收的颜色和距离,做彩色玻璃用。
环境贴图与 PBR
前面反复提到”金属需要环境贴图”。环境贴图(envMap)是一张记录周围环境景象的图,材质从里面采样作为反射来源。有了它,金属球才能映出环境,roughness 低的光滑表面才会有真实的反光。
three.js 里最省事的做法,是用官方的 RoomEnvironment 扩展生成一个模拟室内环境的贴图:
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
const pmrem = new THREE.PMREMGenerator(renderer);
scene.environment = pmrem.fromScene(new RoomEnvironment(), 0.04).texture;
scene.environment 设置后,场景里所有 PBR 材质自动获得环境反射,金属球立刻”亮”起来。这行代码是调试 PBR 材质时的第一选择——先确认材质本身没问题,再去调灯光。
Standard 还是 Physical
- 90% 的场景用 MeshStandardMaterial 就够了;
- 需要车漆(clearcoat)、玻璃(transmission)、布料(sheen)、虹彩(iridescence)时,再升级到 MeshPhysicalMaterial;
- 移动端性能敏感时优先 Standard,transmission 和 clearcoat 都很吃性能。
完整示例:四个球对比
一屏四个球,分别演示 roughness、metalness、clearcoat、transmission 的效果。保存成 HTML 直接运行:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>PBR 材质</title>
<style>
html, body { margin: 0; height: 100%; }
</style>
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.185.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.185.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.1, 100);
camera.position.set(3, 3, 7);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
// PBR 材质必须有光
scene.add(new THREE.AmbientLight(0xffffff, 3));
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(5, 8, 6);
scene.add(dirLight);
const controls = new OrbitControls(camera, renderer.domElement);
// 四个测试球
const setups = [
{ name: 'roughness=0.2', material: new THREE.MeshStandardMaterial({ color: 0x44aaff, roughness: 0.2, metalness: 0 }) },
{ name: 'metalness=1', material: new THREE.MeshStandardMaterial({ color: 0x44aaff, roughness: 0.3, metalness: 1 }) },
{ name: 'clearcoat', material: new THREE.MeshPhysicalMaterial({ color: 0xcc3333, clearcoat: 1, clearcoatRoughness: 0.1 }) },
{ name: 'transmission', material: new THREE.MeshPhysicalMaterial({ color: 0xffffff, transmission: 1, thickness: 0.5, roughness: 0.05, transparent: true }) },
];
setups.forEach(({ material }, i) => {
const sphere = new THREE.Mesh(new THREE.SphereGeometry(0.9, 32, 16), material);
sphere.position.x = (i - 1.5) * 2;
scene.add(sphere);
});
function animate() {
requestAnimationFrame(animate);
scene.children.forEach((obj) => {
if (obj.isMesh) obj.rotation.y += 0.01;
});
controls.update();
renderer.render(scene, camera);
}
animate();
addEventListener('resize', () => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});
</script>
</body>
</html>
Note第二个球(metalness=1)在只有两盏灯的场景里会明显偏暗,这是金属反射环境光的特性。给场景加一张环境贴图(envMap)后,它才会呈现金属光泽,第 18 章会教。
常见问题
- 金属球黑得发闷:纯金属几乎不产生漫反射,只有环境反射。用 RoomEnvironment 给
scene.environment赋值,或加更多灯光。 - 物体全黑:PBR 材质必须开灯,检查场景里有没有光源。
- transmission 玻璃看不出效果:玻璃后面要有物体;另外
transparent要配合开启。 - clearcoat 没反应:
clearcoat默认为 0,先设成 1,再配合低clearcoatRoughness观察高光变化。 - 页面掉帧:Physical 的 transmission、clearcoat 开销大,移动端慎用;能用 Standard 就别升级到 Physical。
小结
PBR 让”调材质”从玄学变成直觉:roughness 管粗糙光滑,metalness 管金属非金属。MeshStandardMaterial 是默认选择,MeshPhysicalMaterial 提供清漆、透射、天鹅绒等进阶质感。下一章开始,给材质贴上真实世界的纹理。