一、BufferGeometry
首先,在 three.js 中有THREE.Mesh 网格、THREE.Points 点、THREE.Line 线条等模型。其中:
Mesh 网格模型创建的物体是由一个个小三角形组成,如下面各图。这些小三角形又是由三个点确定,需要三个确定的位置,即确定的 xyz
Points 模型创建的物体是由一个个点构成,每个点都有自己的位置,Points 相当于点的集合。
Line 模型创建的物体是连续的线条,这些线可以理解为是按顺序把所有点连接起来。
不管是哪一种模型,它们都有一个共同点,就是都离不开点,每一个点都有确定的 x y z,BoxGeometry、SphereGeometry 帮我们封装了对这些点的操作,我们只需要告诉它们长宽高或者半径这些信息,它就会帮我创建一个默认的几何体。而 BufferGeometry 就是完全由我们自己去操作点信息的方法,我们可以通过它去设置每一个点的位置,即 position;每一个点的颜色,即 color;每一个点的法向量 normal 等。
二、position 设置点位置
1. 首先,我们将所有点的坐标存在一个类型化数组中,关于类型化数组的介绍可以查看:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Typed_arrays。如下,每一行是一个点的x y z 值,我们按顺序存储每一个点的坐标,这里我们声明了六个点。
let positions = new Float32Array([ -10, 0, 0, // 0 10, 0, 0, // 1 0, 10, 0, // 2 0, 0, 5, // 3 0, 10, 5, // 4 0, 0, 15 // 5 ]);
2. 定义好顶点数组后,我们将顶点设置到 BufferGeometry 中,代码如下。其中,THREE.BufferAttribute(positions, 3) 中第二个参数 3 指的是数组 positions 中每三个元素构成一个点,分别表示x y z 值。
geometry = new THREE.BufferGeometry(); geometry.attributes.position = new THREE.BufferAttribute(positions, 3);
3. 设置好后,此时如果我们构建网格模型,代码如下。此时,会自动以positions 数组中三行数据,即9个元素3个点,连接构成一个三角形。依次构成三角形,上面的六个点将构成两个三角形,效果如图:
let mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide }) ); scene.add(mesh);
4. 如果使用点模型构建,则会以每3个元素创建一个点,代码、效果如下:六个点直接显示出来。
let point = new THREE.Points( geometry, new THREE.PointsMaterial({ color: 0x00ff00, size: 3 }) ); scene.add(point);
5. 如果使用线模型构建,则会按照点的顺序依次连接各个点,代码、效果如下:
let line = new THREE.Line( geometry, new THREE.LineBasicMaterial({ color: 0x00ffff }) ); scene.add(line);
三、设置点颜色
1. 每一个点都可以设置颜色,颜色通过 rgb 值来设置,r g b 分别取 0-1之间的值。比如如下设置颜色,其中,每一行分别为一个点的颜色,每一行的三个元素分别是颜色的 rgb 值,下面设置了六个点的颜色。
let colors = new Float32Array([ 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1 ]);
2. 定义好颜色数组后,添加到 BufferGeometry 中,并且设置到材质中,举例创建一个Mesh模型如下:
geometry.addAttribute("color", new THREE.BufferAttribute(colors, 3)); let mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors, // 该设置就是使用顶点设置颜色 side: THREE.DoubleSide }) ); scene.add(mesh);
3. 可以看到网格、点、线设置顶点颜色后效果分别如下:
四、设置点法向量
normal 的设置主要和光照相关,我们知道光照在物体的表面,由于光线与表面夹角角度的不一样,会导致亮度等也不一样。在 three.js 中,我们要知道一个物体的光照效果,需要知道物体表面每一个位置的法向方向,而 threejs 中的物体是由一个个点构成的,我们就需要知道每一个的法向量,这里的两个三角形法线方向分别是 z 轴和 x 轴。注意:法向量必须归一化,Vector3 中有方法可以直接调用。这里我们直接声明法向量数组:
let normals = new Float32Array([ 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 ]); geometry.addAttribute("normal", new THREE.BufferAttribute(normals, 3));
五、设置 index
可以理解 index 为 positions 数组中的第n-1个点,如下每一行注释后面就是该点的 index 值。我们知道在 Mesh 模型中,threejs 直接按顺序没三个点一组创建一个三角形,index 就是为了帮助我们指定哪三个点构成一个三角形,并且这些点还可以重复使用。
let positions = new Float32Array([ -10, 0, 0, // 0 10, 0, 0, // 1 0, 10, 0, // 2 0, 0, 5, // 3 0, 10, 5, // 4 0, 0, 15 // 5 ]);
如下,注意:这里用的是 Uint16Array,在这里,我们就可以通过6个点创建3个三角形,并且这些三角形的顶点都是我们自己指定的。而且,这里的 THREE.BufferAttribute(indexs, 1) 的第二个参数为 1 ,表示这里数组 indexs 中每一个元素表示一个点。
let indexs = new Uint16Array([ 0, 1, 2, 3, 4, 5, 2, 4, 5 ]); geometry.index = new THREE.BufferAttribute(indexs, 1);
效果如下,三个三角形: