WebGL で色々な表現に挑戦する - シェーダーを別のファイルに移す

## この記事の概要

前回の記事ではウィンドウのサイズにあわせて要素を拡大し、リサイズ時も追従するようにしました。

https://qiita.com/xrxoxcxox/items/8b226078e7605276fcb7

今回はシェーダーファイルを上手く扱うための方法についてです。
まだ表現力をアップするには至りません……。

## 現状の確認

現状のコードを抜粋すると、こういった部分があります。

```typescript
// シェーダープログラムの作成
const vertexShaderSource = `#version 300 es
in vec2 aPosition;
void main() {
  gl_Position = vec4(aPosition, 0.0, 1.0);
}`;

const fragmentShaderSource = `#version 300 es
precision mediump float;
out vec4 outColor;
void main() {
  outColor = vec4(1.0, 0.0, 0.0, 1.0); // 赤色
}`;

const vertexShader = gl.createShader(gl.VERTEX_SHADER) as WebGLShader;
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER) as WebGLShader;
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
```

`vertexShaderSource` と `fragmentShaderSource` については、[GLSL](https://developer.mozilla.org/ja/docs/Games/Techniques/3D_on_the_web/GLSL_Shaders) を文字列として埋め込んでいるだけです。

今のコードであれば良いですが、後々やりづらくなると思いますし、分割しておく方が何かと楽でしょう。

というわけで、これらを別のファイルに移します。

## 別のファイルへ移動し import

以下のように新しいフォルダとファイルを作成しました。

```sh
.
└── src
    ├── main.ts
    ├── shaders # 新しいフォルダ
    │   ├── plane.frag # フラグメントシェーダー
    │   └── plane.vert # 頂点シェーダー
    ├── style.css
    └── vite-env.d.ts
```

```glsl:shaders/plane.frag
#version 300 es

precision mediump float;

out vec4 outColor;

void main() {
  outColor = vec4(1.0, 0.0, 0.0, 1.0); // 赤色
}
```

```glsl:shaders/plane.vert
#version 300 es

in vec2 aPosition;

void main() {
  gl_Position = vec4(aPosition, 0.0, 1.0);
}
```

拡張子は `.frag` `.vert` と分けず、どちらも `.glsl` でも良いです。
ただ、同じにした場合は `planeFragmenr.glsl` `planeVertex.glsl` みたいなファイル名にすることが多いようで、冗長さが嫌でこうしました。

`main.ts` も書き換えます。

```diff_typescript:main.ts
+ import vertexShaderSource from "./shaders/plane.vert";
+ import fragmentShaderSource from "./shaders/plane.frag";
- const vertexShaderSource = `#version 300 es
- in vec2 aPosition;
- void main() {
-   gl_Position = vec4(aPosition, 0.0, 1.0);
- }`;
-
- const fragmentShaderSource = `#version 300 es
- precision mediump float;
- out vec4 outColor;
- void main() {
-   outColor = vec4(1.0, 0.0, 0.0, 1.0); // 赤色
- }`;
```

これでおしまいかと思いきや、現段階ではこのようなエラーが出ます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/d4c74b19-13dc-6ef8-f2bb-bc266503b84c.png)

こちらを解決します。

## プラグインの設定

今回は Vite を使っているので、それにあわせたプラグインである [vite-plugin-glsl](https://github.com/UstymUkhman/vite-plugin-glsl) を適用します。

```sh
bun i -d vite-plugin-glsl
```

`tsconfig.json` の `types` フィールドに追加します。

```json:tsconfig.json
{
  "compilerOptions": {
    "types": [
      "vite-plugin-glsl/ext"
    ]
  }
}
```

そして、`vite.config.js` にも手を加えます。

```javascript
import { defineConfig } from "vite";
import glsl from "vite-plugin-glsl";

export default defineConfig({
  plugins: [glsl()],
});
```

この状態で起動すれば、ちゃんと表示できます。

## VS Code の設定

ここからは VS Code を使っている人だけに該当する話です。

今のままでは GLSL にシンタックスハイライトが当たりません。
拡張機能をインストールします。

いくつか試してみた限りでは以下が良かったです。

https://marketplace.visualstudio.com/items?itemName=raczzalan.webgl-glsl-editor

`gl_Position` のような組み込みの変数なら、ドキュメントを読むこともできます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/a5048860-9439-98fe-a721-fc077a3e3f42.png)

ただし VS Code の初期設定のままだと Inlay Hints の主張が強いかもしれません。
設定の `Editor > Inlay Hints: Enabled` から `offUnlessPressed` にでも変えると良い具合になる気がします。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/23902ac9-a6e7-8d41-1803-023b4196225e.png)

## 最後に

あれやこれや設定に関する記事を書きました。
そろそろ具体的な表現について記事を書きます。

次の記事はこちらです。

https://qiita.com/xrxoxcxox/items/146d744bf7f124924eff