几何体定义了模型的形状或结构,它描述了模型的顶点、边和面,也就是说几何体决定了模型的物理外观。
几何体的本质
几何体本质上就是一个一个三角形拼接而成的
说明:几何体所有顶点坐标三个为一组,构成一个三角形,多组顶点构成多个三角形,用来模拟物体的表面。
如:一个矩形平面,可以由两个三角形组合而成。一个矩形方块,可以由12个三角形组合而成等。
三角形的正反面
三个点可以构成一个三角形,从第一个点往第三个点连接
-
正面:相机对着面,连接的顺序是逆时针
-
反面:相机对着面,连接的顺序是顺时针
常用的几何体
基本几何体
-
BoxGeometry用于创建立方体或长方体。
width、height 和depth 分别表示立方体的宽、高和深度。const geometry = new THREE.BoxGeometry(width, height, depth); -
PlaneGeometry用于创建一个二维平面。
width 和height 分别表示平面的宽和高。const geometry = new THREE.PlaneGeometry(width, height); -
CircleGeometry用于创建一个圆形。
radius 表示圆的半径,segments 表示圆的分段数。const geometry = new THREE.CircleGeometry(radius, segments);
球体和多面体几何体
-
SphereGeometry用于创建一个球体。
radius 表示球的半径,widthSegments 和heightSegments 分别表示球在水平和垂直方向的分段数。const geometry = new THREE.SphereGeometry(radius, widthSegments, heightSegments); -
DodecahedronGeometry用于创建一个十二面体。
radius 表示十二面体的半径。const geometry = new THREE.DodecahedronGeometry(radius); -
IcosahedronGeometry用于创建一个二十面体。
radius 表示二十面体的半径。const geometry = new THREE.IcosahedronGeometry(radius); -
OctahedronGeometry用于创建一个八面体。
radius 表示八面体的半径。const geometry = new THREE.OctahedronGeometry(radius); -
TetrahedronGeometry用于创建一个四面体。
radius 表示四面体的半径。const geometry = new THREE.TetrahedronGeometry(radius);
圆柱体和圆锥体几何体
-
CylinderGeometry用于创建一个圆柱体。
radiusTop 和radiusBottom 分别表示圆柱体顶部和底部的半径,height 表示圆柱体的高度,radialSegments 表示圆柱体的径向分段数。const geometry = new THREE.CylinderGeometry(radiusTop, radiusBottom, height, radialSegments); -
ConeGeometry用于创建一个圆锥体。
radius 表示圆锥体底部的半径,height 表示圆锥体的高度,radialSegments 表示圆锥体的径向分段数const geometry = new THREE.ConeGeometry(radius, height, radialSegments);
环形几何体
-
TorusGeometry用于创建一个圆环。
radius 表示圆环的半径,tube 表示圆环管的半径,radialSegments 表示圆环的径向分段数,tubularSegments 表示圆环管的分段数。const geometry = new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments); -
TorusKnotGeometry用于创建一个环结。
radius 表示环结的半径,tube 表示环结管的半径,radialSegments 表示环结的径向分段数,tubularSegments 表示环结管的分段数。const geometry = new THREE.TorusKnotGeometry(radius, tube, radialSegments, tubularSegments);
自定义几何体
-
BufferGeometryThreeJS的长方体
BoxGeometry 、球体SphereGeometry 等几何体都是基于BufferGeometry 类构建的,BufferGeometry是一个没有任何形状的空几何体,你可以通过BufferGeometry自定义任何几何形状,具体一点说就是定义顶点数据。// 创建自定义几何体 const geometry = new THREE.BufferGeometry();
几何体顶点位置数据
geometry.attributes.position 是 Three.js 中 BufferGeometry 对象的一个属性,用于存储几何体的顶点位置数据。
位置数据通常是一个 Float32Array,每三个值表示一个顶点的 x、y、z 坐标。
-
设置顶点位置
const vertices = new Float32Array([ 0, 0, 0, // 顶点1 1, 0, 0, // 顶点2 0, 1, 0 // 顶点3 ]); geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); -
访问顶点位置数据。
const positions = geometry.attributes.position.array; positions[0] = 1; // 修改第一个顶点的 x 坐标 -
通知ThreeJS更新顶点位置
修改顶点位置数据后,需要设置
needsUpdate 属性为true,以通知 Three.js 数据已更改geometry.attributes.position.needsUpdate = true;
几何体顶点索引数据
网格模型Mesh对应的几何体BufferGeometry,拆分为多个三角后,很多三角形重合的顶点位置坐标是相同的,
这时候如果你想减少顶点坐标数据量,可以借助几何体顶点索引 geometry.index 来实现。
如下:
每个三角形3个顶点坐标,矩形平面可以拆分为两个三角形,也就是6个顶点坐标。
const geometry = new THREE.BufferGeometry();
// 顶点位置数据
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 0, 0, //顶点4坐标 和顶点1位置相同
80, 80, 0, //顶点5坐标 和顶点3位置相同
0, 80, 0, //顶点6坐标
]);
// 顶点数据赋值给几何体的attributes属性
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); //3个为一组
// 创建材质
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, side: THREE.DoubleSide });
// 创建网格模型
const mesh = new THREE.Mesh(geometry, material);
// 网格模型添加到场景中
scene.add(mesh);
如果几何体有顶点索引 geometry.index,那么你可以把三角形重复的顶点位置坐标删除。
// ......
// 新的顶点位置数据
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 80, 0, //顶点4坐标
]);
// Uint16Array类型数组创建顶点索引数据
const indexes = new Uint16Array([
// 下面索引值对应顶点位置数据中的顶点坐标
0, 1, 2, 0, 2, 3,
])
// 索引数据赋值给几何体的index属性
geometry.setIndex(new THREE.BufferAttribute(indexes, 1)); //1个为一组
// 顶点数据赋值给几何体的attributes属性
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); //3个为一组
// ......
顶点法线数据
先来理解一下数学上的法线概念,比如一个平面,法线的就是该平面的垂线,如果是光滑曲面,一点的法线就是该点切面的法线。
在ThreeJS中法线是一个向量,表示顶点或面的方向,通常用于光照计算。
ThreeJS使用 BufferGeometry 对象的一个属性:geometry.attributes.normal来存储几何体的发现数据
法线数据通常是一个 Float32Array,每三个值表示一个法线向量的 x、y、z 分量。
-
设置法线
const normals = new Float32Array([ 0, 0, 1, // 顶点1的法线 0, 0, 1, // 顶点2的法线 0, 0, 1 // 顶点3的法线 ]); geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3)); -
自动计算法线
ThreeJS 提供了
computeVertexNormals 方法,可以自动计算顶点法线。geometry.computeVertexNormals(); -
访问和修改法线
const normals = geometry.attributes.normal.array; // 访问(获取)法线 normals[0] = 1; // 修改第一个法线向量的 x 分量 -
更新法线
修改法线数据后,需要设置
needsUpdate 属性为true,以通知 Three.js 数据已更改。geometry.attributes.normal.needsUpdate = true;
// 创建一个几何体
const geometry = new THREE.BufferGeometry();
// 定义顶点坐标
const vertices = new Float32Array([
0, 0, 0, // 顶点1
1, 0, 0, // 顶点2
0, 1, 0 // 顶点3
]);
// 定义法线
const normals = new Float32Array([
0, 0, 1, // 顶点1的法线
0, 0, 1, // 顶点2的法线
0, 0, 1 // 顶点3的法线
]);
// 将顶点坐标和法线添加到几何体中
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3));
// 创建一个材质
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
// 创建一个网格
const mesh = new THREE.Mesh(geometry, material);
// 将网格添加到场景中
scene.add(mesh);
旋转、缩放、居中和平移几何体
BufferGeometry通过 .scale()、.translate()、.rotateX()、.rotateY() 等方法可以对几何体本身进行缩放、平移、旋转,这些方法本质上都是改变几何体的顶点数据。
缩放 .scale()
// 几何体xyz三个方向都放大2倍
geometry.scale(2, 2, 2);
// BufferGeometry的旋转、缩放、平移等方法本质上就是改变顶点的位置坐标
console.log('顶点位置数据', geometry.attributes.position);
平移 .translate()
// 几何体沿着x轴平移50
geometry.translate(50, 0, 0);
旋转 .rotateX()、.rotateY()、.rotateZ()
// 几何体绕着x轴旋转45度
geometry.rotateX(Math.PI / 4);
居中 .center()
geometry.translate(50, 0, 0);//偏移
// 居中:已经偏移的几何体居中,执行.center(),你可以看到几何体重新与坐标原点重合
geometry.center();