機械学習基礎理論独習

誤りがあればご指摘いただけると幸いです。数式が整うまで少し時間かかります。リンクフリーです。

勉強ログです。リンクフリーです
目次へ戻る

GLSLを使いやすくする

頂点シェーダとフラグメントシェーダを別ファイルで管理したほうがよい

頂点シェーダとフラグメントシェーダを<script>タグ内に書く例をよく見かけますが、
あれは初心者向けの例であり、あまりよくないと思います。(プログラムを公開している人は勿論分かっている。)
頂点シェーダは xxx.vert、フラグメントシェーダは xxx.frag とするのが一般的なようです。

VSCodeで.vert,.fragを単語ごとに色付けしたい

以下をインストールするとよいかもしれません。

こんな感じで色が付きます。

テキストファイルの動的読み込み

.vert も.frag も単なるテキストファイルなので、非同期で読み込むメソッドを作っておくとよいでしょう。
私の作成したメソッドを貼り付けておきます。適宜修正して使ってください。

   /**
     * Load text file
     * @param {string} url URL
     * @returns {Promise<string>} string of file contents
     */
    static async loadTextAsync(url) {
        const response = await fetch(url);
        return await response.text();
    }

#include文を使いたい

C/C++のような#include文でメインのソースに違うソースを挿入できると便利ですよね。
作成したので良ければ使ってください。
ただし、挿入するソースの#includeは無視します。要は#includeを含むソースは#includeできないってことです。
エラーメッセージは修正したほうが良いと思います。

    /**
     * Get shader
     * @param {WebGL2RenderingContext} gl WebGL2 context
     * @param {string} mainUrl main source
     * @param {Object<string, string>} insertUrls insert sources
     * @returns {Promise<WebGLShader>} Shader
     */
    static async getShader(gl, mainUrl, insertUrls = {}) {
        // Get insert file contents
        const inserts = {};
        const names = Object.keys(insertUrls);
        // Is duplicated
        if(new Set(names).size !== names.length) { throw 'Invalid parameters. (GLUtility.getShader)'; }
        for(let i = 0; i < names.length; i += 1) {
            const name = names[i];
            inserts[name] = await File.loadTextAsync(insertUrls[name]);
        }
        // Insert file
        let source = await File.loadTextAsync(mainUrl);
        let includes = source.match(/^#include {1,}"\w{1,}.\w{1,}"/gm);
        if(!includes) { includes = []; }
        // Is same count
        if(includes.length !== names.length) { throw 'Invalid parameters. (GLUtility.getShader)'; }        
        includes.forEach(e => {
            const fileName = e.match(/"\w{1,}.\w{1,}"/)[0].replaceAll('"', '');
            if(!inserts[fileName]) {
                throw 'Invalid parameters. (GLUtility.getShader)';
            }
            source = source.replace(e, inserts[fileName]);
        });

        // Create shader
        let type;
        if(mainUrl.toLowerCase().endsWith('.vert')) {// vertex shader
            type = gl.VERTEX_SHADER;
        } else if(mainUrl.toLowerCase().endsWith('.frag')) {// fragment shader
            type = gl.FRAGMENT_SHADER;
        } else {
            throw 'Invalid parameters. (GLUtility.getShader)';
        }
        const shader = gl.createShader(type);

        // Compile shader
        gl.shaderSource(shader, source);
        gl.compileShader(shader);
        if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
            throw gl.getShaderInfoLog(shader);
        }
        return shader;
    }

このgetShaderの呼び出し方の例です。
'glsl/main.vert' には #include "inserted.vert" が記述されている必要があります。

getShader(gl, gl, 'glsl/main.frag', { 'test.frag': 'glsl/test.frag', 'test2.frag': 'glsl/test2.frag', });

目次へ戻る