3、几何体与材质:内置几何体与基础材质

好,咱们进入第三章。这一章我打算聊聊 Three.js 里最基础、也最常用的两个概念——几何体材质

说白了,几何体就是物体的「骨架」,材质就是物体的「皮肤」。你想想看,一个 3D 场景里,不管多复杂的模型,拆到最底层,都是由一个个几何体拼起来的。而材质决定了这个几何体看起来像什么——是金属、塑料、还是木头?

我个人习惯,每次开始一个新项目,都会先用内置几何体搭个「草稿」。这样能快速验证光照、相机位置这些基础设置。等一切就绪了,再替换成精细模型。这个习惯帮我省了不少时间。

3.1 内置几何体:开箱即用的形状

Three.js 内置了好几种几何体,最常用的就是 Box、Sphere、Cylinder 这三个。我刚开始学的时候,觉得它们太简单了,后来才发现,很多复杂场景其实都是这些基础形状的组合。

3.1.1 BoxGeometry(立方体)

这个最常用,也最好理解。你传三个参数进去,它就能生成一个长方体。

const geometry = new THREE.BoxGeometry(2, 1, 3);
// 宽度 2,高度 1,深度 3

嗯,这里要注意:参数顺序是 width、height、depth。我见过不少新手把顺序搞反,结果模型变形了还找不到原因。

我的小技巧: 如果你想要一个正方体,三个参数传一样的值就行。比如 new THREE.BoxGeometry(1, 1, 1)

3.1.2 SphereGeometry(球体)

球体稍微复杂一点,因为它涉及到「分段数」的概念。

const geometry = new THREE.SphereGeometry(1, 32, 16);
// 半径 1,宽度分段 32,高度分段 16

为什么要有分段数?因为计算机没法画真正的圆,它只能用多边形去「模拟」圆。分段数越高,球体越光滑,但性能开销也越大。

我曾经在做一个移动端项目时,把球体的分段数设成了 128,结果在低端手机上直接卡成幻灯片。后来我改成了 24 和 12,肉眼几乎看不出区别,但帧率从 20 飙到了 60。所以,别盲目追求高分段,够用就行。

3.1.3 CylinderGeometry(圆柱体)

圆柱体也挺有意思,它不仅能做圆柱,还能做圆锥、甚至多棱柱。

const geometry = new THREE.CylinderGeometry(1, 1, 2, 32);
// 顶部半径 1,底部半径 1,高度 2,径向分段 32

如果你把顶部半径设为 0,它就变成了一个圆锥。如果你把径向分段设为 6,它就变成了一个六棱柱。这个灵活性在实际项目中非常有用。

几何体 常用参数 典型应用场景
BoxGeometry width, height, depth 建筑、箱子、墙壁
SphereGeometry radius, widthSegments, heightSegments 星球、球体装饰、碰撞体
CylinderGeometry radiusTop, radiusBottom, height, radialSegments 柱子、管道、圆锥

3.2 基础材质:给几何体穿上衣服

几何体搭好了,接下来就是材质。Three.js 提供了好几种材质,但最基础、最常用的就两个:MeshBasicMaterialMeshStandardMaterial

3.2.1 MeshBasicMaterial(基础材质)

这个材质最简单,它不受光照影响。你给它什么颜色,它就显示什么颜色。

const material = new THREE.MeshBasicMaterial({
  color: 0xff0000,  // 红色
  wireframe: false   // 是否显示线框
});

说实话,这个材质在实际项目中用得不多,因为它没有立体感。但它非常适合做调试——比如你想快速看看几何体的形状对不对,或者做 UI 元素、辅助线之类的东西。

注意: 如果你用了 MeshBasicMaterial,场景里的灯光对它完全无效。别花时间调光了,它根本不响应。

3.2.2 MeshStandardMaterial(标准材质)

这个才是主力。它基于物理渲染(PBR),能模拟真实世界的光照效果。

const material = new THREE.MeshStandardMaterial({
  color: 0x00ff00,
  roughness: 0.5,   // 粗糙度,0 最光滑,1 最粗糙
  metalness: 0.3     // 金属感,0 非金属,1 纯金属
});

我个人习惯,roughness 和 metalness 这两个参数一定要调。很多人只改 color,结果模型看起来像塑料玩具。你试试 roughness 设成 0.2、metalness 设成 0.8,立马就有金属质感了。

我记得有一次做产品展示,客户说模型看起来「太假了」。我调了半天光照都没用,最后发现是 roughness 设得太高了,表面太粗糙,没有反光。改成 0.3 之后,效果立竿见影。

3.3 颜色与纹理:让材质活起来

光有纯色材质还不够,真实世界的东西都是有纹理的——木头的纹路、石头的颗粒、布料的编织。

3.3.1 颜色设置

Three.js 支持多种颜色表示方式:

// 十六进制
material.color.setHex(0xff6600);

// RGB 字符串
material.color.setStyle('#ff6600');

// 颜色名称
material.color.set('orange');

我个人推荐用十六进制,因为它最精确,也最容易从设计稿里复制。

3.3.2 纹理贴图

纹理才是让材质「活起来」的关键。你需要用 TextureLoader 来加载图片。

const loader = new THREE.TextureLoader();
const texture = loader.load('path/to/texture.jpg');

const material = new THREE.MeshStandardMaterial({
  map: texture,  // 颜色贴图
  roughnessMap: texture,  // 粗糙度贴图(可选)
  normalMap: texture      // 法线贴图(可选)
});

嗯,这里有个坑:纹理加载是异步的。如果你在加载完成之前就渲染场景,可能会看到一片灰色。我建议用 loader.load 的回调函数,等纹理加载完了再添加到场景里。

核心要点:
  • 几何体定义形状,材质定义外观
  • MeshBasicMaterial 不受光照,适合调试
  • MeshStandardMaterial 是主力,记得调 roughness 和 metalness
  • 纹理让材质更真实,但要注意加载时机

好了,这一章的内容就这些。下一章我们会把这些几何体和材质组合起来,真正搭建一个完整的 3D 场景。到时候我会分享一些我在实际项目中踩过的坑,保证有用。