とげとげジオメトリの生成

コードはこんな感じ。正二十面体の各面に対して、まず面の法線と重心を求めて、重心から法線方向に一定値delta進めたところに一つ頂点をを生やした感じ。

  function generateNeedlesGeometry(size: number) {
    const delta = size * 2.0;

    const geometry = new THREE.IcosahedronGeometry(size, 0);
    const positions = geometry.attributes.position;
    const { array, itemSize } = positions;
  
    const bufArray: number[] = [];
  
    const v1 = new THREE.Vector3();
    const v2 = new THREE.Vector3();
    const v3 = new THREE.Vector3();
  
    for (let i = 0, j = 0; i < array.length; i += itemSize, j++) {
      const x = array[i];
      const y = array[i+1];
      const z = array[i+2];
  
      if (j == 0) {
        v1.set(x, y, z);
      } else if (j == 1) {
        v2.set(x, y, z);
      } else if (j == 2) {
        v3.set(x, y, z);
        
        const v12 = new THREE.Vector3().subVectors(v2, v1);
        const v23 = new THREE.Vector3().subVectors(v3, v2);
        const vn = new THREE.Vector3().crossVectors(v12, v23).normalize();
        vn.multiplyScalar(delta);
  
        const vg = new THREE.Vector3();
        vg.add(v1);
        vg.add(v2);
        vg.add(v3);
        vg.multiplyScalar(1/3);
  
        vg.add(vn);
        
        bufArray.push(v1.x, v1.y, v1.z);
        bufArray.push(v2.x, v2.y, v2.z);
        bufArray.push(vg.x, vg.y, vg.z);
  
        bufArray.push(v2.x, v2.y, v2.z);
        bufArray.push(v3.x, v3.y, v3.z);
        bufArray.push(vg.x, vg.y, vg.z);
  
        bufArray.push(v3.x, v3.y, v3.z);
        bufArray.push(v1.x, v1.y, v1.z);
        bufArray.push(vg.x, vg.y, vg.z);
  
        j = 0;
      }
    }

    const buf = new THREE.BufferGeometry();
    buf.setAttribute( 'position', new THREE.Float32BufferAttribute( bufArray, 3 ) );
    return buf;
  }