几何体定义了模型的形状或结构,它描述了模型的顶点、边和面,也就是说几何体决定了模型的物理外观。
几何体的本质
几何体本质上就是一个一个三角形拼接而成的
说明:几何体所有顶点坐标三个为一组,构成一个三角形,多组顶点构成多个三角形,用来模拟物体的表面。
如:一个矩形平面,可以由两个三角形组合而成。一个矩形方块,可以由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);
自定义几何体
-
BufferGeometry
ThreeJS的长方体
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();