基础材质四件套
本教程共 40 篇 · 第 13 篇 · 更新于 2026-08-14 · 约 7 分钟阅读
本节目标:学会 MeshBasicMaterial、MeshNormalMaterial、MeshLambertMaterial、MeshPhongMaterial 四种基础材质的特性与用途,知道它们各自需要什么、适合什么。
为什么还要学基础材质
PBR 材质(第 14 章)是主流,但四种基础材质仍值得学。Basic 和 Normal 不依赖灯光,是调试利器;Lambert 和 Phong 性能好、上手快,在低端设备和老项目里还很常见。更重要的是,它们把光照模型的演进讲得很清楚:不受光、只受漫反射、再加上高光。理解这条线,PBR 就只是”更精细的 Phong”。
MeshBasicMaterial:完全不受光的纯色
最基础的材质。它把颜色原样画在表面,完全忽略场景里所有灯光,没有明暗变化,物体看起来像剪影或扁平图标。
const material = new THREE.MeshBasicMaterial({ color: 0x44aaff });
特点:
- 不需要任何灯光,场景没灯也能看见;
- 没有光影变化,立体感弱,转起来才看得出是 3D;
- 配合
map纹理可以做纯纹理展示、2D 风格化效果。
用途:调试(快速看几何体形状)、加载完成前的占位、扁平风格场景。
调试时它还有个妙用:配合 wireframe: true 看三角形布线,配合半透明看模型内部结构。因为不受光,用 Basic 做调试能排除”灯光问题”这个变量。
MeshNormalMaterial:法线当颜色
它的颜色不是设置的,而是由表面法线方向算出来的:法线的 x、y、z 分量映射成 R、G、B。默认场景里,物体呈现五彩斑斓的”彩虹”效果。
const material = new THREE.MeshNormalMaterial();
特点:
- 不需要灯光;
- 没有 color 属性,颜色由法线方向决定;
- 法线是光照计算的依据,所以它是检查法线是否正确的最好工具——法线错了,颜色分布会立刻露出破绽。
用途:调试法线、快速预览几何体、做”科技感”装饰。
它同样支持 flatShading 和 wireframe,组合起来能快速判断一个模型”形状对不对、面朝向对不对”。第 15 章之后,还可以给标准材质挂法线贴图,Normal 材质是理解法线贴图的基础。
MeshLambertMaterial:哑光漫反射
第一个”正经”受光材质。它只计算漫反射:光从哪个方向来,表面就朝哪个方向亮。效果是哑光、不反光,像磨砂塑料、粉笔、墙面。
const material = new THREE.MeshLambertMaterial({ color: 0x44aaff });
注意它需要灯光,没灯就全黑。它支持 emissive 自发光和 map 纹理,但没有高光——表面永远不会出现”亮点”。
自发光用来模拟”自己会发光但又不照亮别人”的表面,比如屏幕、灯箱:
const material = new THREE.MeshLambertMaterial({
color: 0x333333,
emissive: 0xff6600, // 自发光颜色
emissiveIntensity: 0.8, // 自发光强度,默认 1
});
特点:
- 计算量小,性能好;
- 适合哑光物体:木材、石头、粗糙塑料;
- 无法表现镜面反射。
MeshPhongMaterial:加上高光的 Lambert
在 Lambert 的基础上加了镜面高光(specular)。高光区域由 shininess 控制:值越大,高光点越小越锐利。
const material = new THREE.MeshPhongMaterial({
color: 0x44aaff,
shininess: 60, // 高光锐利程度,默认 30
specular: 0xffffff, // 高光颜色,默认 0x111111(很暗)
emissive: 0x000000, // 自发光颜色,默认黑
});
特点:
- 需要灯光;
- 能表现塑料、瓷器、湿润表面等带高光的物体;
specular默认是很暗的 0x111111,想看到明显高光记得调亮它。shininess和specular的分工要分清:shininess只控制高光点的锐利程度(30 是柔和的大光斑,100 以上是锐利的小亮点),specular控制高光的颜色和明暗。两者配合,能调出从塑料到瓷器的各种质感。
Tip判断”该用 Lambert 还是 Phong”:物体表面会反光(哪怕一点点)就用 Phong,纯哑光用 Lambert。
场景选型:四件套怎么用
把材质和常见需求对上号:
- 木头、石头、粗糙塑料这类哑光物体,用 Lambert,性能最好;
- 塑料玩具、瓷器、湿润的石头这类带高光的物体,用 Phong;
- 扁平 UI 风格、调试占位,用 Basic,完全不受光影响;
- 需要检查模型法线是否正常,用 Normal,颜色分布会直接暴露问题;
- 需要纹理贴图又有真实光影,Lambert 和 Phong 都支持 map,看需不需要高光来选。
性能排序(从快到慢):Basic ≈ Normal < Lambert < Phong。老设备或大量物体同屏时,优先选靠前的材质。 为什么性能有差别?Lambert 每帧要算一次漫反射光照,Phong 还要多算一次高光,Basic 和 Normal 根本不算光照。物体数量上万个时,这点差距会放大成帧率的明显差异。当然,追求真实感时性能差一点是值得的,这正是 PBR 材质存在的意义。
四件套对比
| 材质 | 需要灯光 | 明暗变化 | 高光 | 性能 | 典型用途 |
|---|---|---|---|---|---|
| MeshBasicMaterial | 否 | 无 | 无 | 最快 | 调试、扁平风格、占位 |
| MeshNormalMaterial | 否 | 有(法线着色) | 无 | 快 | 调试法线、预览 |
| MeshLambertMaterial | 是 | 漫反射 | 无 | 快 | 哑光物体 |
| MeshPhongMaterial | 是 | 漫反射 | 有 | 较快 | 带高光的物体 |
完整示例:四个球
一个页面四个球,分别用四种材质,转起来对比。保存成 HTML 直接运行: 从左到右依次是 Basic、Normal、Lambert、Phong。运行后重点观察两点:前两个球不管怎么转,亮度都不变(它们不算光照);第四个球表面有一个移动的亮斑(Phong 的高光),第三个球没有。这个亮斑就是”高光”两个字的具体含义。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>基础材质四件套</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, 2.5, 6);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
// 灯光:Lambert 和 Phong 需要它,Basic 和 Normal 无视它
scene.add(new THREE.AmbientLight(0xffffff, 3));
const dirLight = new THREE.DirectionalLight(0xffffff, 3);
dirLight.position.set(3, 6, 4);
scene.add(dirLight);
const controls = new OrbitControls(camera, renderer.domElement);
// 四种材质,四个球
const materials = [
new THREE.MeshBasicMaterial({ color: 0x44aaff }),
new THREE.MeshNormalMaterial(),
new THREE.MeshLambertMaterial({ color: 0x44aaff }),
new THREE.MeshPhongMaterial({
color: 0x44aaff,
shininess: 60,
specular: 0xffffff,
}),
];
materials.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把示例里的灯光注释掉再看:Basic 和 Normal 的球依然可见,Lambert 和 Phong 的球全黑。这就是”谁依赖灯光”最直观的演示。
常见问题
- Lambert、Phong 的物体全黑:没加灯。这两种材质必须依赖灯光,场景里至少要有一盏灯。
- Basic 材质看着像纸片:这是它的本性——不受光、没有明暗。想要立体感就换受光材质。
- Normal 材质想改颜色改不了:它的颜色由法线方向决定,没有 color 属性。想自定义颜色就换别的材质。
- Phong 高光不明显:
specular默认是 0x111111(很暗),调亮到 0xffffff 再配合shininess看效果。 - 低多边形物体棱角太生硬:试试
flatShading: true,切面风格有时比平滑着色更好看。
小结
四种基础材质构成一条演进线:Basic 完全不受光,Normal 用法线着色,Lambert 加上漫反射,Phong 再加高光。它们覆盖了”不需要光”和”需要光但很便宜”的场景。想要更真实、更物理的质感,下一章进入 PBR 材质。