2、几何体与材质:BoxGeometry、SphereGeometry等基础几何体,MeshStandardMaterial、MeshPhongMaterial等材质,以及纹理贴图
好,咱们正式开始动手了。
上一章我们把 Three.js 的“舞台”搭好了——场景、相机、渲染器。现在该往舞台上放“演员”了。演员是谁?就是几何体(Geometry)和材质(Material)。
我个人习惯把几何体理解为“骨架”,材质理解为“皮肤”。骨架决定了形状,皮肤决定了看起来像什么。两者一结合,就成了一个网格对象(Mesh),也就是我们最终在屏幕上看到的东西。
2.1 基础几何体:从立方体到球体
Three.js 内置了很多基础几何体。说白了,就是帮你把顶点、面、法线这些底层数据都算好了,你直接拿来用就行。
BoxGeometry(立方体)——最常用的几何体,没有之一。
const geometry = new THREE.BoxGeometry(1, 1, 1);
三个参数分别是宽、高、深度。默认都是1,单位是“世界单位”,你可以理解为米。
我在项目中遇到过一个问题:用 BoxGeometry 做墙的时候,如果只给一个面贴图,其他面会显示黑色。后来发现是材质没设置透明,或者 UV 坐标没处理好。嗯,这个后面讲纹理时会细说。
SphereGeometry(球体)——做星球、灯泡、球状装饰必备。
const geometry = new THREE.SphereGeometry(1, 32, 16);
参数依次是:半径、水平分段数、垂直分段数。分段数越高,球越圆,但性能消耗也越大。32×16 是个不错的平衡点。
其他常用的还有:
- CylinderGeometry(圆柱体)——做柱子、罐子
- ConeGeometry(圆锥体)——做锥形、屋顶
- TorusGeometry(圆环体)——做甜甜圈、戒指
- PlaneGeometry(平面)——做地面、墙面、广告牌
你想想看,这些几何体其实覆盖了 90% 的日常需求。复杂的模型可以靠组合它们来实现,或者直接导入外部模型文件。
2.2 材质:让物体“看起来”像什么
几何体决定了形状,材质决定了外观。Three.js 的材质系统很丰富,但初学者掌握两个就够了:MeshStandardMaterial 和 MeshPhongMaterial。
MeshStandardMaterial(标准材质)——这是我现在最常用的材质。它基于物理渲染(PBR),能模拟真实世界的光照效果。
const material = new THREE.MeshStandardMaterial({
color: 0xff6600,
roughness: 0.4,
metalness: 0.1
});
三个核心属性:
- color:颜色,十六进制或 Color 对象
- roughness:粗糙度,0 到 1。0 像镜子,1 像砂纸
- metalness:金属度,0 到 1。0 非金属,1 纯金属
MeshPhongMaterial(冯氏材质)——老牌材质,性能比 Standard 好一点,但效果没那么真实。
const material = new THREE.MeshPhongMaterial({
color: 0x00aaff,
shininess: 30,
specular: 0x111111
});
shininess 控制高光强度,specular 控制高光颜色。如果你做卡通风格或者对性能要求高,可以用它。
这里有个坑要注意:Standard 材质需要环境光和方向光才能显示正常。如果你只用了环境光,物体会显得很平,没有立体感。我刚开始学的时候就犯过这个错,调了半天颜色,结果发现是光照没配好。
2.3 纹理贴图:给物体穿上“衣服”
纯色材质太单调了。真实世界的东西都有纹理——木头的纹路、砖墙的凹凸、金属的划痕。纹理贴图就是干这个的。
Three.js 用 TextureLoader 加载图片,然后赋给材质的 map 属性。
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('wood.jpg');
const material = new THREE.MeshStandardMaterial({
map: texture
});
就这么简单。但实际项目中,纹理贴图远不止这一种。常用的还有:
| 贴图类型 | 属性名 | 作用 |
|---|---|---|
| 颜色贴图 | map | 定义物体表面颜色 |
| 法线贴图 | normalMap | 模拟表面凹凸细节,不增加顶点 |
| 粗糙度贴图 | roughnessMap | 控制不同区域的粗糙程度 |
| 金属度贴图 | metalnessMap | 控制不同区域的金属感 |
| 环境光遮蔽贴图 | aoMap | 增加阴影细节,让物体更真实 |
我曾经做一个古建筑复原项目,只用颜色贴图时,木梁看起来像塑料。后来加了法线贴图和粗糙度贴图,瞬间有了木头的质感。嗯,这就是纹理的威力。
还有一个常用技巧:纹理重复。比如做地板,一张小瓷砖图片重复铺满地面。
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(4, 4); // 水平和垂直各重复4次
这样一张 256×256 的小图就能铺满 4×4 的世界单位,既省资源又清晰。
2.4 组合起来:一个完整的例子
说了这么多,咱们来写一个完整的例子。创建一个带纹理的立方体和一个金属球体。
// 立方体:带木纹
const boxGeo = new THREE.BoxGeometry(2, 2, 2);
const woodTexture = textureLoader.load('wood.jpg');
const boxMat = new THREE.MeshStandardMaterial({
map: woodTexture,
roughness: 0.8,
metalness: 0.0
});
const box = new THREE.Mesh(boxGeo, boxMat);
box.position.set(-2, 1, 0);
scene.add(box);
// 球体:金属质感
const sphereGeo = new THREE.SphereGeometry(1, 32, 32);
const sphereMat = new THREE.MeshStandardMaterial({
color: 0xcccccc,
roughness: 0.2,
metalness: 0.9
});
const sphere = new THREE.Mesh(sphereGeo, sphereMat);
sphere.position.set(2, 1, 0);
scene.add(sphere);
你看,代码结构很清晰:创建几何体 → 创建材质 → 组合成 Mesh → 设置位置 → 添加到场景。
最后别忘了加光照,否则材质再漂亮也显示不出来。
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 7);
scene.add(directionalLight);
好了,这一章的内容就这些。几何体是骨架,材质是皮肤,纹理是细节。三者配合,就能做出很棒的 3D 物体。
下一章我们聊聊光照和阴影——没有光,再好的材质也白搭。