解決したいこと
WebGL で使用する頂点シェーダーとフラグメントシェーダーの GLSL ES コードは単純な文字列データであればよいので、下記のように JavaScript のコードに埋め込んでしまう方法が最初に思いつきます。
const VSHADER_CODE = `
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 10.0;
}`;
const FSHADER_CODE = `
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}`;
しかし、これだとアプリ側のコードとシェーダーのコードが混ざってしまうので美しくありません。 ここでは、シェーダーコードを分離するいくつかの方法を示します。
script 要素内にシェーダーコードを埋め込む方法
下記のような感じで、頂点シェーダーとフラグメントシェーダー用の script 要素を用意して、そこにコードを埋め込んでしまう方法です。
<script id="vshader" type="x-shader/x-vertex">
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 10.0;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
</script>
それぞれのシェーダーコードは、JavaScript コードで下記のようにして取り出すことができます。
const vsCode = document.getElementById('vshader').textContent;
const fsCode = document.getElementById('fshader').textContent;
import でシェーダーファイルを読み込む方法
ECMAScript 2015 (ES6) の import 構文 を使用すると、別ファイルとして保存した JavaScript ファイルを読み込むことができます。
import { VS_CODE, FS_CODE } from 'shaders.js';
例えば、下記のように個別の JS ファイルとしてシェーダーコードを保存しておければ、少なくともアプリ側の JS コードにシェーダーコードが埋もれてしまうことは防ぐことができます。
// Vertex Shader
export const VS_CODE = `
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 10.0;
}
`;
// Fragment Shader
export const FS_CODE = `
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
`;
import
を使用するスクリプトの <script>
タグには、type="module"
を指定しておく必要があります。
<script type="module">
import { VS_CODE, FS_CODE } from './shaders.js';
// ...
const shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, VS_CODE);
gl.compileShader(shader);
// ...
</script>
メインスクリプトを JavaScript ファイルに分離するのであれば次ような感じ。
<script type="module" src="./main.js"></script>