1. 内置几何体全览
Three.js 提供了丰富的内置几何体,覆盖日常 3D 开发的绝大多数需求。每种几何体都继承自 BufferGeometry,可以通过构造函数参数控制尺寸和分段数。
| 几何体 | 构造参数 | 用途 |
|---|---|---|
BoxGeometry | width, height, depth, wSegs, hSegs, dSegs | 正方体/长方体,建筑、UI 元素 |
SphereGeometry | radius, widthSegs, heightSegs | 球体、星球、灯泡 |
TorusGeometry | radius, tube, radialSegs, tubularSegs | 甜甜圈、戒指、轮胎 |
PlaneGeometry | width, height, wSegs, hSegs | 地面、水面、屏幕 |
CylinderGeometry | radiusTop, radiusBottom, height, segs | 圆柱、圆锥(顶半径为0) |
TorusKnotGeometry | radius, tube, tubularSegs, radialSegs, p, q | 装饰性纽结形状 |
TetrahedronGeometry | radius, detail | 四面体,低多边形风格 |
OctahedronGeometry | radius, detail | 八面体,宝石、钻石 |
IcosahedronGeometry | radius, detail | 二十面体,球体近似 |
TextGeometry | text, { font, size, depth } | 3D 文字(需 FontLoader) |
// 常用几何体示例
const box = new THREE.BoxGeometry(1, 1, 1);
const sphere = new THREE.SphereGeometry(0.5, 32, 16); // 分段越多越圆滑
const torus = new THREE.TorusGeometry(0.5, 0.2, 16, 50);
const plane = new THREE.PlaneGeometry(10, 10, 10, 10); // 10x10 网格地面
const cone = new THREE.CylinderGeometry(0, 0.5, 1, 32); // 顶半径为0 = 圆锥
2. Mesh = Geometry + Material
Three.js 中的可见 3D 对象通常是 Mesh,它由两部分组成:
- Geometry(几何体):定义形状,存储顶点位置、法线、UV 坐标等数据。
- Material(材质):定义外观,决定物体如何响应光照、颜色、纹理等。
const geometry = new THREE.SphereGeometry(1, 32, 16);
const material = new THREE.MeshStandardMaterial({ color: 0x049EF4 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// 一个 Geometry 可以被多个 Mesh 共享(节省内存)
const sharedGeo = new THREE.BoxGeometry(1, 1, 1);
const mesh1 = new THREE.Mesh(sharedGeo, new THREE.MeshStandardMaterial({ color: 'red' }));
const mesh2 = new THREE.Mesh(sharedGeo, new THREE.MeshStandardMaterial({ color: 'blue' }));
mesh1.position.x = -1.5;
mesh2.position.x = 1.5;
scene.add(mesh1, mesh2);
3. wireframe 线框模式
线框模式只显示几何体的边线,不填充面,常用于调试几何体结构或实现低多边形艺术风格:
// 方式一:材质属性
const mat = new THREE.MeshBasicMaterial({
color: 0x049EF4,
wireframe: true
});
// 方式二:运行时切换
mesh.material.wireframe = true;
// 方式三:专用 WireframeGeometry(显示所有边,包括对角线)
const wireGeo = new THREE.WireframeGeometry(geometry);
const wireLines = new THREE.LineSegments(wireGeo,
new THREE.LineBasicMaterial({ color: 0x049EF4 })
);
scene.add(wireLines);
4. BufferGeometry 自定义顶点
当内置几何体无法满足需求时,可以使用 BufferGeometry 从顶点数据构建任意形状。顶点数据存储在类型化数组(TypedArray)中,直接对应 GPU 缓冲区。
// 手动创建一个三角形
const geometry = new THREE.BufferGeometry();
// 定义三个顶点(每个顶点 3 个值:x, y, z)
const vertices = new Float32Array([
-1, 0, 0, // 顶点 0
1, 0, 0, // 顶点 1
0, 1, 0 // 顶点 2
]);
// BufferAttribute(array, itemSize)
// itemSize=3 表示每个属性由3个值组成(xyz)
geometry.setAttribute(
'position',
new THREE.BufferAttribute(vertices, 3)
);
// 自动计算法线(用于光照计算)
geometry.computeVertexNormals();
const mesh = new THREE.Mesh(geometry,
new THREE.MeshStandardMaterial({ color: 0x049EF4, side: THREE.DoubleSide })
);
scene.add(mesh);
// 大量随机顶点(粒子效果预热)
const count = 5000;
const positions = new Float32Array(count * 3);
for (let i = 0; i < count * 3; i++) {
positions[i] = (Math.random() - 0.5) * 10;
}
const pointsGeo = new THREE.BufferGeometry();
pointsGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
5. 分段数的重要性
分段数(Segments)决定几何体的细腻程度。分段越多,表面越平滑,但顶点数也越多,影响渲染性能。
// 低分段球(看起来像多面体)
const lowPolyBall = new THREE.SphereGeometry(1, 8, 6); // 48 个三角面
// 高分段球(接近真正的球面)
const hiPolyBall = new THREE.SphereGeometry(1, 64, 32); // 4096 个三角面
// 实践原则:
// - 近景大物体:高分段(32-64)
// - 远景/小物体:低分段(8-16)
// - 地面/水面需要细分才能做波浪效果
6. 实战:太阳系模型
综合运用本章知识,创建一个带轨道旋转的简化太阳系:
import * as THREE from 'three';
const scene = new THREE.Scene();
const clock = new THREE.Clock();
// 太阳——自发光黄色球
const sunGeo = new THREE.SphereGeometry(1.5, 32, 16);
const sunMat = new THREE.MeshBasicMaterial({ color: 0xffcc00 });
const sun = new THREE.Mesh(sunGeo, sunMat);
scene.add(sun);
// 点光源从太阳中心发光
const sunLight = new THREE.PointLight(0xffffff, 3, 50);
scene.add(sunLight);
// 创建行星的辅助函数
function createPlanet(radius, color, orbitRadius, speed) {
const pivot = new THREE.Object3D(); // 轴心点(用于轨道旋转)
scene.add(pivot);
const mesh = new THREE.Mesh(
new THREE.SphereGeometry(radius, 24, 12),
new THREE.MeshStandardMaterial({ color })
);
mesh.position.x = orbitRadius; // 偏移到轨道半径处
pivot.add(mesh);
// 绘制轨道圆圈
const orbitGeo = new THREE.TorusGeometry(orbitRadius, 0.01, 2, 80);
const orbit = new THREE.Mesh(orbitGeo,
new THREE.MeshBasicMaterial({ color: 0x334455 })
);
orbit.rotation.x = Math.PI / 2;
scene.add(orbit);
return { pivot, mesh, speed };
}
const planets = [
createPlanet(0.3, 0x9a9a9a, 3, 1.6), // 水星
createPlanet(0.5, 0xd4956a, 4.5, 1.2), // 金星
createPlanet(0.5, 0x2266bb, 6.5, 1.0), // 地球
createPlanet(0.4, 0xcc4422, 8.5, 0.8), // 火星
];
function animate() {
requestAnimationFrame(animate);
const t = clock.getElapsedTime();
// 太阳自转
sun.rotation.y = t * 0.2;
// 行星公转(绕各自 pivot 旋转)
planets.forEach(({ pivot, speed }) => {
pivot.rotation.y = t * speed;
});
renderer.render(scene, camera);
}
animate();
Object3D 作为轴心:行星轨道旋转的技巧是创建一个空的 Object3D 作为父对象(pivot),将行星 Mesh 添加为子对象并偏移到轨道半径处,然后旋转父对象——子对象就会绕父对象的原点(即太阳中心)公转。这是 Three.js 中层级变换的核心技巧。
本章小结:Three.js 内置的几何体覆盖大多数场景,复杂形状用 BufferGeometry 自定义。Mesh = Geometry + Material 的组合设计让形状和外观独立变化。下一章深入学习材质与纹理系统。