IcosahedronGeometryの頂点にカラフルなドットを追加する



デモ：https://mo49.github.io/qiita/20161005/globe.html

![スクリーンショット 2016-10-05 20.36.07.png](https://qiita-image-store.s3.amazonaws.com/0/136286/cfb3688b-e8ff-08f5-8546-fe6ecd1ea1f8.png "スクリーンショット 2016-10-05 20.36.07.png")


IcosahedronGeometryのインスタンスを生成して、その頂点数分for文をまわし各頂点の色情報を設定する。

```javascript:IcosahedronGeometryの生成
const icosaGeom = new THREE.IcosahedronGeometry(8, 1); // radius, detail (+1で4倍)
const vertices = icosaGeom.vertices; // vec3
const positions = new Float32Array(vertices.length * 3);
const colors_base = [];
for (var i = 0; i < vertices.length; i++) {
  vertices[i].toArray(positions, i * 3);
  let color;
  switch (i % 4) {
    case 0: color = { h: 0.6, s: 0.72, v: 0.95 }; break;
    case 1: color = { h: 0.37, s: 0.69, v: 0.65 }; break;
    case 2: color = { h: 0.12, s: 0.98, v: 0.98 }; break;
    case 3: color = { h: 0.0, s: 0.80, v: 1.0 }; break;
    default: color = { h: 0.0, s: 0.80, v: 1.0 }
  }
  colors_base.push(color.h, color.s, color.v);
}
```

BufferGeometryに位置と色情報をセットする

```javascript:BufferGeometryの生成
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
const colors = new Float32Array(colors_base);
geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3));
```

各頂点ごとに描く円をcanvasで生成し、canvasをテクスチャに渡す

```javascript:createTexture()
createTexture() {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const CANVAS_SIZE = 128;

  canvas.width = canvas.height = CANVAS_SIZE;
  ctx.fillStyle = "rgba(255, 255, 255, 1)";
  ctx.arc(CANVAS_SIZE/2, CANVAS_SIZE/2, CANVAS_SIZE/2, 0, Math.PI / 180, true);
  ctx.fill();

  const texture = new THREE.Texture(canvas);
  texture.minFilter = THREE.NearestFilter;
  texture.needsUpdate = true;
  return texture;
};
```

テクスチャをシェーダに渡す

```javascript:ShaderMaterialの生成
const shaderMat = new THREE.ShaderMaterial({
  uniforms: {
    size: {
      type: 'f',
      value: 12.0
    },
    texture: {
      type: 't',
      value: this.createTexture()
    }
  },
  vertexShader: document.getElementById('vs').textContent,
  fragmentShader: document.getElementById('fs').textContent,
  transparent: true,
  depthWrite: false
});
```

シェーダでは色とサイズを制御する

```html:シェーダの設定
<script id="vs" type="x-shader/x-vertex">
  attribute vec3 color;
  uniform float size;
  varying vec3 vColor;

  void main() {
    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
    vColor = color;

    gl_PointSize = size;
    gl_Position = projectionMatrix * mvPosition;
  }
</script>
<script id="fs" type="x-shader/x-fragment">
  uniform sampler2D texture;

  varying vec3 vColor;

  vec3 hsv2rgb(vec3 c){
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
  }

  void main() {
    vec3 custom_color = hsv2rgb(vColor);
    gl_FragColor = vec4(custom_color, 1.0) * texture2D(texture, gl_PointCoord);
  }
</script>
```



> 参考
[Add Dots to Vertices in Three.js](http://stackoverflow.com/questions/37950024/add-dots-to-vertices-in-three-js)
[three.js製パーティクルシステムの実装](http://blog.tsumikiinc.com/article/20160225_threejs-points.html)