一、缓冲类型几何体BufferGeometry
之前我们用到的长方体BoxGeometry
就是基于BufferGeometry
,BufferGeometry是一个没有任何形状的空几何体,你可以通过BufferGeometry自定义任何几何形状,具体一点说就是定义顶点数据。啥是顶点?自己百度去
第一步:创建一个空的几何体对象
const geometry = new THREE.BufferGeometry();
第二步:定义几何体的顶点坐标
这里可不是用简单的一个数组来表示顶点,需要通过javascript类型化数组Float32Array
创建一组xyz坐标数据用来表示几何体的顶点坐标
//类型化数组创建顶点数据
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标
50, 0, 0, //顶点2坐标
0, 100, 0, //顶点3坐标
0, 0, 10, //顶点4坐标
0, 0, 100, //顶点5坐标
50, 0, 10, //顶点6坐标
]);
通过threejs的属性缓冲区对象BufferAttribute
表示threejs几何体顶点数据。
// 创建属性缓冲区对象
//3个为一组,表示一个顶点的xyz坐标
const attribue = new THREE.BufferAttribute(vertices, 3);
第三步:设置几何体顶点
// 设置几何体attributes属性的位置属性
geometry.attributes.position = attribue;
第四步:创建mesh模型
const mesh= new THREE.Mesh(geometry, material);
到这一步了,你会发现,你渲染出来的根本不是想象中的那种立体图形,而是两个不相干的三角形
二、网格模型(三角形概念)
网格模型Mesh其实就一个一个三角形(面)拼接构成。使用网格模型Mesh渲染几何体geometry,就是几何体所有顶点坐标三个为一组,构成一个三角形,多组顶点构成多个三角形,就可以用来模拟表示物体的表面。
空间中一个三角形有正反两面,那么Three.js的规则是如何区分正反面的?非常简单,你的眼睛(相机)对着三角形的一个面,如果三个顶点的顺序是逆时针方向,该面视为正面,如果三个顶点的顺序是顺时针方向,该面视为反面。接下来,我们尝试创建一个矩形平面几何体
定义矩形几何体顶点坐标
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坐标
]);
这里需要注意一点,这个顶点坐标应该如何定义呢,就一个原则,同一面,两个三角形要么都是顺时针,要么都是逆时针,这里我定义的两个都逆时针。
观察上面的顶点坐标会发现顶点一和顶点四坐标是一样的,这才两个三角形就有两个重复点了,成百上千个三角形,不得重复一大堆,徒增工作量,这个时候,就得用上几何体的顶点索引geometry.index
。
有了顶点索引,上面vertices
数组就可以精简为:
const vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 80, 0, //顶点4坐标
]);
把重复点位直接删除
BufferAttribute
定义顶点索引.index
数据
通过javascript类型化数组Uint16Array
创建顶点索引.index数据。
// Uint16Array类型数组创建顶点索引数据
const indexes = new Uint16Array([
// 下面索引值对应顶点位置数据中的顶点坐标
0, 1, 2, 0, 2, 3,
])
说明:vertices
顶点坐标三个为一组,indexes
里面的0
就代表第一组,也就是说0,0,0
,同理可得1
就代表第二组,80,0,0
然后通过threejs的属性缓冲区对象BufferAttribute表示几何体顶点索引.index数据。
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组
上面讲的是几何体顶点位置数据geometry.attributes.position
,还有一种新的顶点数据,就是顶点法线(法向量)数geometry.attributes.normal
,具体啥样自行了解咯
顶点法线