BabylonJS 押し出しメッシュカスタム

# 押し出しメッシュカスタム

BabylonJS には多くの種類のメッシュ生成関数が存在します。今回はこのうち [`ExtrudeShapeCustom`](https://doc.babylonjs.com/typedoc/modules/BABYLON#ExtrudeShapeCustom-2) を紹介します。
`ExtrudeShapeCustom` は [`ExtrudeShape`](https://doc.babylonjs.com/typedoc/modules/BABYLON#ExtrudeShape-2) からさらに各パス点において、`scaleFunction` で拡大率を、`rotationFunction` で次のパス点へのねじり角度を指定できるようになっています。
この関数は `(i, distance)` の引数が渡され `i` がパス点のインデックスで `distance` が最初のパス点からパス点間同士の距離の累積値を与えられます。
`rotationFunction` の戻り値はラジアンで次のパス点までのねじり角を指定します。ワールド座標系ではねじり量は累積されていくことになります。

以下のコードは2023年12月9日の [BabylonJS Playground](https://playground.babylonjs.com/) 6.33.1 Javascript で動作したことがあります。

```js
const createScene = async () => {
    const scene = new BABYLON.Scene(engine);
    const camera = new BABYLON.ArcRotateCamera('camera1',
        0, 0, 10,
        new BABYLON.Vector3(-6, 0, 0), scene);
    camera.setPosition(new BABYLON.Vector3(10, 12, -16));
    camera.wheelDeltaPercentage = 0.01;
    camera.attachControl(true);

    const light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 1, 0), scene);
    light.intensity = 0.7;

    const b = 0.5;
    const hw = 2;
    const hh = 3;
    const shape = [
        [-hw+b, hh, 0],
        [-hw, hh-b, 0],
        [-hw, -hh+b, 0],
        [-hw+b, -hh, 0]
    ];
    for (let i = 0; i <= 16; ++i) {
        const ang = i * Math.PI / 16;
        const s = Math.sin(ang);
        shape.push([hw * s, -hh * Math.cos(ang), 0]);
    }

    const twistNum = 8;
    const path = [];
    let x = 0;
    for (let i = 0; i < 8; ++i) {
        path.push([x, 0, 0]);
        let offset = -1;
        switch(i) {
            case 0:
                offset = -b;
                break;
            case 3:
            case 5:
                offset = 0;
                break;
        }
        x += offset;
    }
    for (let i = 0; i < twistNum; ++i) {
        path.push([x, 0, 0]);
        x -= 1;
    }
    for (let i = 0; i < 2; ++i) {
        path.push([x, 0, 0]);
        x -= 4;
    }

    const opt = {
        shape: shape.map(p => new BABYLON.Vector3(...p)),
        closeShape: true,
        path: path.map(p => new BABYLON.Vector3(...p)),
        cap: BABYLON.Mesh.CAP_ALL,
        scaleFunction: (i, distance) => {
            let rate = 1;
            switch(i) {
                case 0:
                    rate = 0.8;
                    break;
                case 4:
                case 5:
                    rate = 1.2;
                    break;
            }
            return rate;
        },
        rotationFunction: (i, distance) => {
            if (i >= 8 && i < 8 + twistNum) {
                return Math.PI * 90 / 180 / twistNum;
            }
            if (i === path.length - 1) {
                return 0;
            }
            return 0;
        },
    };
    const mesh = BABYLON.MeshBuilder.ExtrudeShapeCustom('mesh1', opt, scene);
    return scene;
};
```


|実行結果|
|:-:|
|![esc3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213145/a7f395c0-e16b-bbdc-013e-91c11683b39b.png)|
|シェイプの拡大率とねじりを変更できます|


# リンク

- ExtrudePolygon
https://doc.babylonjs.com/typedoc/modules/BABYLON#ExtrudePolygon-2
多角形押し出しメッシュ生成。

- ExtrudeShape
https://doc.babylonjs.com/typedoc/modules/BABYLON#ExtrudeShape-2
シェイプ押し出しメッシュ生成。