几何体BufferGeometry

通过BufferGeometry自定义任何几何形状

Three.js的长方体BoxGeometry、球体SphereGeometry等几何体都是基于BufferGeometry类构建的,BufferGeometry是一个没有任何形状的空几何体,你可以通过BufferGeometry自定义任何几何形状,具体一点说就是定义顶点数据。

1
const geometry = new THREE.BufferGeometry(); 

定义顶点坐标。

1
2
3
4
5
const vertices = new Float32Array([
0, 0, 0, 50, 0, 0,
0, 100, 0, 0, 0, 10,
0, 0, 100, 50, 0, 10
]);

属性缓冲区对象BufferAttribute表示Three.js几何体顶点数据(顶点坐标3个为一组)。

1
const attribue = new THREE.BufferAttribute(vertices, 3); 

设置几何体顶点位置属性的值。

1
geometry.attributes.position = attribue;

点模型

设置点模型的材质。

1
2
3
4
const material = new THREE.PointsMaterial({
color: 0xffff00,
size: 10.0//点对象像素尺寸
});

几何体geometry作为点模型Points参数,会把几何体渲染为点。

1
const points = new THREE.Points(geometry, material);

线模型

设置线模型的材质。

1
2
3
const material = new THREE.LineBasicMaterial({
color: 0xffff00
});

几何体geometry作为线模型参数,会把几何体渲染为线。

(1)渲染效果是从第一个点开始到最后一个点,依次连成线。

1
const line = new THREE.Line(geometry, material);

(2)渲染效果是从第一个点开始到最后一个点,依次连成线;最后一个点再与第一个点连线使图形封口。

1
const line = new THREE.LineLoop(geometry, material);

(3)渲染效果是每两个点连接成一条线,已经连线的点不会再与其他点连线。

1
const line = new THREE.LineSegments(geometry, material);

网格模型构建矩形平面

网格模型Mesh其实就一个一个三角形(面)拼接构成。使用使用网格模型Mesh渲染几何体geometry,就是几何体所有顶点坐标三个为一组,构成一个三角形,多组顶点构成多个三角形,就可以用来模拟表示物体的表面。

  • 正面:逆时针
  • 反面:顺时针

空间中一个三角形有正反两面,相机对着三角形的一个面,如果三个顶点的顺序是逆时针方向,该面视为正面,如果三个顶点的顺序是顺时针方向,该面视为反面。

1
2
3
4
5
6
7
const material = new THREE.MeshLambertMaterial({
color: 0xffff00,
side:THREE.DoubleSide,//双面显示
//side:THREE.FrontSide//显示正面
//side:THREE.BackSide//显示反面

});

一个矩形平面,可以至少通过两个三角形拼接而成。而且两个三角形有两个顶点的坐标是重合的。注意三角形的正反面问题:保证矩形平面两个三角形的正面是一样的,也就是从一个方向观察,两个三角形都是逆时针或顺时针。

1
2
3
4
5
const vertices = new Float32Array([
0, 0, 0, 80, 0, 0,
80, 80, 0,0, 0, 0,
80, 80, 0,0, 80, 0
]);

使用THREE.MeshLambertMaterial设置网格模型材质,最后使用THREE.Mesh将几何体渲染成网格模型面。

几何体顶点索引数据

如果几何体有顶点索引geometry.index,那么可以三角形重复的顶点位置坐标删除。

1
2
3
4
const vertices = new Float32Array([
0, 0, 0, 80, 0, 0,
80, 80, 0, 0, 80, 0
]);

通过javascript类型化数组Uint16Array创建顶点索引数据。

1
2
3
4
const indexes = new Uint16Array([
//索引值对应顶点位置数据中的顶点坐标
0, 1, 2, 0, 2, 3,
])

除了设置几何体顶点位置属性的值,还需要通过Three.js的属性缓冲区对象BufferAttribute表示几何体顶点索引数据。

1
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组

顶点法线数据

使用MeshLambertMaterial材质(受光照影响的材质),几何体BufferGeometry需要定义顶点法线数据。

1
2
3
4
5
6
7
8
9
// 矩形平面,无索引,两个三角形,6个顶点(如果有索引可以定义四个法线顶点)
// 每个顶点的法线数据和顶点位置数据一一对应
const normals = new Float32Array([
0, 0, 1, 0, 0, 1,
0, 0, 1, 0, 0, 1,
0, 0, 10, 0, 1
]);
// 设置几何体的顶点法线属性
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3);

查看Threejs自带几何体顶点

Three.js提供的矩形平面PlaneGeometry、长方体BoxGeometry、球体SphereGeometry等各种形状的几何体,他们都有一个共同的父类BufferGeometry

可以用顶点索引index数据构建几何体,也可以不用,three.js默认的大部分几何体都有三角形的顶点索引数据,具体可以通过浏览器控制台打印几何体数据查看。

1
2
3
4
5
const geometry = new THREE.PlaneGeometry(100,50); //矩形平面几何体
// const geometry = new THREE.BoxGeometry(50,50,50); //长方体
console.log('几何体',geometry);
console.log('顶点位置数据',geometry.attributes.position);
console.log('顶点索引数据',geometry.index);

线条模式渲染,查看几何体三角形结构。

1
2
3
4
const material = new THREE.MeshLambertMaterial({
color: 0x00ffff,
wireframe:true,//线条模式渲染mesh对应的三角形数据
});

Three.js很多几何体都提供了细分数相关的参数,这里以矩形平面几何体PlaneGeometry为例,矩形平面几何体至少需要两个三角形拼接而成。

1
2
 //矩形几何体PlaneGeometry的参数3,4表示细分数,默认是1,1
const geometry = new THREE.PlaneGeometry(100,50,1,1);

把一个矩形分为2份,每个矩形2个三角形,总共就是4个三角形。

1
const geometry = new THREE.PlaneGeometry(100,50,2,1);

把一个矩形分为4份,每个矩形2个三角形,总共就是8个三角形。

1
const geometry = new THREE.PlaneGeometry(100,50,2,2);

球体SphereGeometry参数2、3分别代表宽、高度两个方向上的细分数,默认32,16。

1
const geometry = new THREE.SphereGeometry( 50, 32, 16 );

如果球体细分数比较低,表面就不会那么光滑。

1
const geometry = new THREE.SphereGeometry( 15, 8, 8 );

对于一个曲面而言,细分数越大,表面越光滑,但是三角形和顶点数量却越多。几何体三角形数量或者说顶点数量直接影响Three.js的渲染性能,在不影响渲染效果的情况下,一般尽量越少越好。

旋转、缩放、平移几何体

BufferGeometry通过.scale().translate().rotateX().rotateY().rotateZ()等方法可以对几何体本身进行缩放、平移、旋转,这些方法本质上都是改变几何体的顶点数据。(与Object3D的函数区分,此处函数的任何变化都是在局部坐标系中进行的,而局部坐标系原点的位置是通过模型的position属性定义的,Object3D的相关函数本质改变的是position属性)。

1
2
3
4
5
6
7
8
9
10
//缩放
geometry.scale(2, 2, 2);
//平移
geometry.translate(50, 0, 0);
//旋转
geometry.rotateX(Math.PI / 4);
geometry.rotateY(Math.PI / 4);
geometry.rotateZ(Math.PI / 4);
// 居中:已经偏移的几何体居中,执行.center(),可以看到几何体重新与坐标原点重合
geometry.center();

如下图通过mesh.position.set(50,50,0);将局部坐标系的中心设置在了世界坐标系x=50,y=50的地方,接下来用geometry.rotateX(Math.PI/2);geometry.translate(50,0,0);将物体相对于局部坐标系向x轴平移50,并且绕x轴旋转90°。可以看到物体中心相对于局部坐标系原点发生了改变,但是局部坐标系原点相对于世界坐标的原点的位置并没有发生改变。

image-20230205223715553

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码

请我喝杯咖啡吧~

支付宝
微信