4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

GLSLのコンパイルエラーをブラウザのコンソールに表示する

Last updated at Posted at 2024-03-15

誰向け?

GLSLのコンパイルエラーのエラーメッセージがブラウザのコンソールで見られず困っている人向け。

この記事ではp5.jsを使った例を上げますが、p5.jsを使っていない人にも考え方は役に立つはず。

解決したい問題

そもそもp5.jsはGLSLのコンパイルエラーのエラーメッセージをコンソールに表示する機能を備えています。

スクリーンショット 2024-03-12 23.03.14.png

この画像内の

🌸 p5.js says: Snap! Error linking shader program: Precisions of uniform 'uRed' differ between VERTEX and FRAGMENT shaders.

という奴がそうです。

ところが私の環境だと何故かこれがコンソールに出なくなってしまいました。

Node.jsReactNext.jsTypeScriptあたりが怪しいのですが、調査しても原因特定できず。心当たりのある方は教えて下さい…。

ということで、下記の方法では、p5.jsの機能に頼らず、シェーダーのコンパイルエラーのエラーメッセージを取得します。

方法

Vertex ShaderFragment Shaderと、それらを集約したWebGL Programの3箇所にエラーが格納されています。これを読み出せばいいです。

Vertex ShaderFragment Shaderのエラー
getShaderInfoLogで取得
WebGL Programのエラー
getProgramInfoLogで取得

Vertex ShaderFragment Shader については、WebGL2RenderingContextWebGLShader のインスタンスを取得し、Context の getShaderInfoLog メソッドに Shader のインスタンスを渡せばエラーメッセージが取得できるので、それを console.log などすればよいです。

p5.js の場合は、 p5.Shader の中にある vertexShader と fragmentShader のインスタンスを取り出して、Context の getShaderInfoLog に渡します。

WebGL Program については、getProgramInfoLog メソッドを使って、ほぼ同様にします。

各シェーダー・プログラムのインスタンスのありか

https://github.com/processing/p5.js/blob/main/src/webgl/p5.Shader.js
こちらのソースコードを見ると、p5.Shader
_vertShader
_fragShader
_glProgram
というプロパティを持っていることがわかります。これらがそうです。

コード例

まずはHTML。p5.jsscript.jsを読み込んでいるだけで、あとはテンプレ、ボイラープレートです。

index.html
<!DOCTYPE html>
<html lang="ja">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.8.0/p5.js"></script>
    </head>

    <body>
        <script src="script.js"></script>
    </body>

</html>

次の JavaScript がこの記事のメインです!
p5.Shader の中にある Vertex ShaderFragment ShaderWebGL Program をそれぞれ取り出して、メッセージが記録されていればそれをコンソールに throw しています。

script.js
window.onload = function () {

    const sketch = (p5) => {
        let myShader;  // p5.Shaderを格納
        let myCanvas; // p5.Rendererを格納(canvasを指し示す)
        let gl; // WebGL2RenderingContextを格納

        p5.preload = () => {
            // preload内でシェーダを読み込む
            myShader = p5.loadShader('./shader.vert', './shader.frag');
        }

        p5.setup = () => {
            myCanvas = p5.createCanvas(400, 400, p5.WEBGL); // 作ったCanvasを代入
            gl = myCanvas.elt.getContext('webgl2'); // GL2のContextを取得して代入
            p5.noStroke();
        }

        p5.draw = () => {
            p5.background(0);
            const red = [1.0, 0.0, 0.0];
            const green = [0.0, 1.0, 0.0];
            myShader.setUniform("uColors", [red, green].flat());
            p5.shader(myShader);

            // vertex shaderのコンパイルエラーを取得して表示
            const messageVert = gl.getShaderInfoLog(myShader._vertShader);
            if (messageVert !== null && messageVert.length > 0) {
                console.log("error of vertex shader");
                throw messageVert;
            }

            // fragment shaderのコンパイルエラーを取得して表示
            const messageFrag = gl.getShaderInfoLog(myShader._fragShader);
            if (messageFrag !== null && messageFrag.length > 0) {
                console.log("error of fragment shader");
                throw messageFrag;
            }

            // WebGLProgramのエラーを取得して表示
            const messageProgram = gl.getProgramInfoLog(myShader._glProgram);
            if (messageProgram !== null && messageProgram.length > 0) {
                console.log("error of gl program");
                throw messageProgram;
            }

            p5.beginShape(p5.TRIANGLES); // 三角形を描画
            p5.vertex(0.0, 0.5); // gl_VertexID == 0
            p5.vertex(-0.5, -0.5); // gl_VertexID == 1
            p5.vertex(0.5, -0.5); // gl_VertexID == 2
            p5.endShape();
        }
    }

    new p5(sketch);
};

2つのシェーダーのGLSLコードは、この記事の内容的にはどうでもいいですが、後ほどこれを少し破壊して、どんなエラーが出るか確認してみます。

shader.vert
#version 300 es

precision mediump float;

uniform vec3 uColors[2];
in vec3 aPosition;
out vec4 vertColor;

void main() {
    gl_Position = vec4(aPosition, 1.0);
    // 1色目と2色目はuniformで受け取り、3色目はハードコードしています。
    vertColor =
        gl_VertexID == 0 ? vec4(uColors[0],1.0):
        gl_VertexID == 1 ? vec4(uColors[1],1.0):
        vec4(0.0, 0.0, 1.0, 1.0);
}
shader.frag
#version 300 es

precision mediump float;

in vec4 vertColor;
out vec4 fragColor;

void main() {
    // vertex shaderから受け取った値を色として出力するだけ
    fragColor = vertColor;
}

出力結果

ダウンロード.png

エラー例1 vertex shaderのエラー

shader.vert
- out vec4 vertColor;
+ out vec3 vertColor;

vertex shader で型エラーを引き起こしてみます。

スクリーンショット 2024-03-14 15.03.08.png

script.js:30 Uncaught ERROR: 0:12: '=' : dimension mismatch
ERROR: 0:12: 'assign' : cannot convert from 'mediump 4-component vector of float' to 'out mediump 3-component vector of float'

いいですね。fragment shader ではなく vertex shader が怒られている、ということもちゃんとわかります。

エラー例2 fragment shaderのエラー

shader.frag
- out vec4 fragColor;

こうすると…

スクリーンショット 2024-03-14 15.08.13.png

script.js:37 Uncaught ERROR: 0:9: 'fragColor' : undeclared identifier
ERROR: 0:9: 'assign' : l-value required (can't modify a const)
ERROR: 0:9: '=' : dimension mismatch
ERROR: 0:9: 'assign' : cannot convert from 'in highp 4-component vector of float' to 'const highp float'

ちゃんと undeclared identifier と怒られましたね。fragment shader が怒られていることもちゃんとわかります。

エラー例3 vertex shaderとfragment shaderの連携エラー

昔の呼び方で varying と呼ばれていた奴ですね。型を不一致にさせてみます。

shader.frag
- in vec4 vertColor;
- out vec4 fragColor;
+ in vec3 vertColor;
+ out vec3 fragColor;

スクリーンショット 2024-03-15 15.17.10.png

Uncaught Types of varying 'vertColor' differ between VERTEX and FRAGMENT shaders.
FRAGMENT varying vertColor does not match any VERTEX varying

今回は WebGL Program でエラーが発生したことがわかります。

まとめ

とにかくこれらを取得して、console.log

Vertex ShaderFragment Shaderのエラー
getShaderInfoLogで取得
WebGL Programのエラー
getProgramInfoLogで取得

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?