「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
几何体
- 在
three.js
中如球体、立方体、平面、狗、猫、人、树、建筑等物体,都是几何体。它们都是根据大量顶点参数生成。 - 在
three.js
中内置了许多基本几何体,也提供了自定义几何体的方法。在开发中常见的做法是让美术在 3D 建模软件中创建 3D 模型,在由开发人员进行交互开发。
常见几何体
BoxGeometry 盒子
- 分段数简单理解,就是每多一个分段,在对应面的轴上添加两个顶点,增加组成这个面三角形的数量。分段数越多面就越精细,性能消耗也会变大。
const width = 8 // 宽度
const height = 8 // 高度
const depth = 8 // 深度
const widthSegments = 4 // ui: 宽度的分段数
const heightSegments = 4 // ui: 高度的分段数
const depthSegments = 4 // ui: 深度的分段数
const boxGeometry = new THREE.BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)
SphereGeometry 球
SphereGeometry
是通过扫描并计算围绕着Y轴和X轴的顶点来创建的。我们可以通过修改水平、垂直扫描角度的大来实现球体切片。
const radius = 8 // 球体半径
const widthSegments = 32 // 水平分段数
const heightSegments = 16 // 垂直分段数
const geometry = new THREE.SphereGeometry(radius, widthSegments, heightSegments)
// 网格
const mesh = new THREE.Mesh(geometry, material)
mesh.position.x = 10
scene.add(mesh)
{
const radius = 8 // 球体半径
const widthSegments = 32 // 水平分段数
const heightSegments = 16 // 垂直分段数
const phiStart = Math.PI * 0.25 // 水平(经线)起始角度
const phiLength = Math.PI * 2 // 水平(经线)扫描角度的大小
const thetaStart = Math.PI * 0.25 // 垂直(纬线)起始角度
const thetaLength = Math.PI * 0.5 // 垂直(纬线)扫描角度大小
const geometry1 = new THREE.SphereGeometry(
radius,
widthSegments,
heightSegments,
phiStart,
phiLength,
thetaStart,
thetaLength
)
// 网格
const mesh1 = new THREE.Mesh(geometry1, material)
mesh1.position.x = -10
scene.add(mesh1)
}
PlaneGeometry 平面几何体
const width = 8 // 宽度
const height = 8 // 高度
const widthSegments = 2 // 宽度的分段数
const heightSegments = 2 // 高度的分段数
const geometry = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments)
BufferGeometry 自定义几何体
BufferGeometry
是面片、线或点几何体的有效表述。通过顶点位置、法相量、颜色值、UV 坐标等值来绘制几何体- 使用
BufferGeometry
可以有效减少向 GPU 传输顶点数据所需的开销。
- 定义面的顶点位置,法线坐标(法线是面朝向的信息)。一个面是两个三角形组成,所以需要6个顶点,一个立方体就需要36个顶点信息。
const vertices = [
// front
{ pos: [-1, -1, 1], norm: [0, 0, 1] },
{ pos: [1, -1, 1], norm: [0, 0, 1] },
{ pos: [-1, 1, 1], norm: [0, 0, 1] },
{ pos: [-1, 1, 1], norm: [0, 0, 1] },
{ pos: [1, -1, 1], norm: [0, 0, 1] },
{ pos: [1, 1, 1], norm: [0, 0, 1] },
// right
{ pos: [1, -1, 1], norm: [1, 0, 0] },
{ pos: [1, -1, -1], norm: [1, 0, 0] },
{ pos: [1, 1, 1], norm: [1, 0, 0] },
{ pos: [1, 1, 1], norm: [1, 0, 0] },
{ pos: [1, -1, -1], norm: [1, 0, 0] },
{ pos: [1, 1, -1], norm: [1, 0, 0] },
// back
{ pos: [1, -1, -1], norm: [0, 0, -1] },
{ pos: [-1, -1, -1], norm: [0, 0, -1] },
{ pos: [1, 1, -1], norm: [0, 0, -1] },
{ pos: [1, 1, -1], norm: [0, 0, -1] },
{ pos: [-1, -1, -1], norm: [0, 0, -1] },
{ pos: [-1, 1, -1], norm: [0, 0, -1] },
// left
{ pos: [-1, -1, -1], norm: [-1, 0, 0] },
{ pos: [-1, -1, 1], norm: [-1, 0, 0] },
{ pos: [-1, 1, -1], norm: [-1, 0, 0] },
{ pos: [-1, 1, -1], norm: [-1, 0, 0] },
{ pos: [-1, -1, 1], norm: [-1, 0, 0] },
{ pos: [-1, 1, 1], norm: [-1, 0, 0] },
// top
{ pos: [1, 1, -1], norm: [0, 1, 0] },
{ pos: [-1, 1, -1], norm: [0, 1, 0] },
{ pos: [1, 1, 1], norm: [0, 1, 0] },
{ pos: [1, 1, 1], norm: [0, 1, 0] },
{ pos: [-1, 1, -1], norm: [0, 1, 0] },
{ pos: [-1, 1, 1], norm: [0, 1, 0] },
// bottom
{ pos: [1, -1, 1], norm: [0, -1, 0] },
{ pos: [-1, -1, 1], norm: [0, -1, 0] },
{ pos: [1, -1, -1], norm: [0, -1, 0] },
{ pos: [1, -1, -1], norm: [0, -1, 0] },
{ pos: [-1, -1, 1], norm: [0, -1, 0] },
{ pos: [-1, -1, -1], norm: [0, -1, 0] }
]
const positions = []
const normals = []
// 以数组形式获取 数据
for (const vertex of vertices) {
positions.push(...vertex.pos)
normals.push(...vertex.norm)
}
- 通过
.setAttribute()
设置定义好的顶点信息。这里需要注意的是.BufferAttribute()
第二个参数是确认,数组中连续的几个值组合为一组信息。
const geometry = new THREE.BufferGeometry()
const positionNumComponents = 3 // 3个一组 为一个顶点
const normalNumComponents = 3 // 3个一组 为一个顶点
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), positionNumComponents))
geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(normals), normalNumComponents))
- 自定义几何体的优势是它和GPU传输的数度快,缺点是顶点信息难以修改,在开发中需要根据需求判断是否使用。
总结
- 在
three.js
中内置的几何体非常的多,需要深入了解的需要到官网上查看。本节简单的介绍了几何体是什么。 - 在创建几何体时需要注意,分段数的大小要控制好。细分的越少,运行的越流畅,使用的内存也会更少。细分的越多,动画越精细,运行的越不流畅。