three.js で点の位置や色を後からぐりぐり変える方法

# やりたいこと

Three.js で座標を変更したい！！
要約するとこのあたりのメソッドを駆使すればよい。

**点の数の取得**

```javascript
{mesh}.geometry.attributes.position.count
```

**点のXYZ座標の取得**
`getX()` とかの引数でインデックスを指定することに要注意。

```javascript
{mesh}.geometry.attributes.position.getX(index)
{mesh}.geometry.attributes.position.getY(index)
{mesh}.geometry.attributes.position.getZ(index)
```

**点のXYZ座標毛の変更**
これも引数でインデックスを指定するのに注意。

```javascript
{mesh}.geometry.attributes.position.setXYZ(i, x, y, z)
```

**点の色の変更**
これも引数でインデックスを指定する、かつ、なぜかメソッド名がXYZ（？）

```javascript
{mesh}.geometry.attributes.color.setXYZ(i, r, g, b);
```

**色や座標に変化があったことを知らせるフラグ**

```javascript
{mesh}.geometry.attributes.position.needsUpdate = true
{mesh}.geometry.attributes.color.needsUpdate = true
```

このあたりを知っていればなんとかなりそう。

# サンプルまでに全体のコード
まずランダムに白い点をうってみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/e5e7160a-67c3-edfa-7cb3-9f5f338a175b.png)

コードはこんな感じ。

```html
<html>

<head>
    <meta charset="utf-8" />
    <script type="importmap">
      {
        "imports": {
          "three": "https://cdn.jsdelivr.net/npm/three@0.167.0/build/three.module.js",
          "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.167.0/examples/jsm/"
        }
      }
    </script>
</head>

<body>
    <canvas id="myCanvas"></canvas>

    <script type="module">
        import * as THREE from "three";
        import { OrbitControls } from "three/addons/controls/OrbitControls.js";

        // サイズを指定
        const width = window.innerWidth;
        const height = window.innerHeight;

        // レンダラーを作成
        let canvas = document.querySelector("#myCanvas")
        const renderer = new THREE.WebGLRenderer({
            canvas: canvas,
            antialias: true
        });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(width, height);

        // シーンを作成
        const scene = new THREE.Scene();

        // カメラを作成
        const camera = new THREE.PerspectiveCamera(45, width / height);
        camera.position.set(0, 0, 50);
        const controls = new OrbitControls(camera, canvas);

        // 適当なデータ作成
        let mesh

        const vertices = [];
        const colors = [];

        for (let i = 1; i < 100; i++) {
            let x = Math.random() * 10 - 5;
            let y = Math.random() * 10 - 5;
            let z = Math.random() * 10 - 5;
            vertices.push( x, y, z );

            let r = 1;
            let g = 1;
            let b = 1;
            colors.push( r, g, b );
        }

        // 形状データを作成
        const geometry = new THREE.BufferGeometry();
        geometry.setAttribute("position", new THREE.Float32BufferAttribute(vertices, 3));
        geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));

        // マテリアルを作成
        const material = new THREE.PointsMaterial({
            size: 1,
            vertexColors: true
        });

        // 物体を作成
        mesh = new THREE.Points(geometry, material);
        scene.add(mesh);

        tick();

        function tick() {
            renderer.render(scene, camera);
            requestAnimationFrame(tick);
        }
    </script>
</body>

</html>
```

`tick()` の中で点の位置や色をぐりぐり変えてみる！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/3236bdc4-d9f9-cf52-0adf-7a69695434b0.png)


```javascript
        function tick() {
            if(mesh){
                for(let i=0;i<mesh.geometry.attributes.position.count;i++){
                    let x = mesh.geometry.attributes.position.getX(i) + (Math.random() - 0.5)
                    let y = mesh.geometry.attributes.position.getY(i) + (Math.random() - 0.5)
                    let z = mesh.geometry.attributes.position.getZ(i) + (Math.random() - 0.5)
                    mesh.geometry.attributes.position.setXYZ(i, x, y, z)

                    let r = Math.random();
                    let g = Math.random();
                    let b = Math.random();
                    mesh.geometry.attributes.color.setXYZ(i, r, g, b);
                }
                mesh.geometry.attributes.position.needsUpdate = true
                mesh.geometry.attributes.color.needsUpdate = true
            }

            renderer.render(scene, camera);
            requestAnimationFrame(tick);
        }
```