誰向け?
GLSLのコンパイルエラーのエラーメッセージがブラウザのコンソールで見られず困っている人向け。
この記事ではp5.jsを使った例を上げますが、p5.jsを使っていない人にも考え方は役に立つはず。
解決したい問題
そもそもp5.jsはGLSLのコンパイルエラーのエラーメッセージをコンソールに表示する機能を備えています。
この画像内の
🌸 p5.js says: Snap! Error linking shader program: Precisions of uniform 'uRed' differ between VERTEX and FRAGMENT shaders.
という奴がそうです。
ところが私の環境だと何故かこれがコンソールに出なくなってしまいました。
Node.jsかReactかNext.jsかTypeScriptあたりが怪しいのですが、調査しても原因特定できず。心当たりのある方は教えて下さい…。
ということで、下記の方法では、p5.jsの機能に頼らず、シェーダーのコンパイルエラーのエラーメッセージを取得します。
方法
Vertex ShaderとFragment Shaderと、それらを集約したWebGL Programの3箇所にエラーが格納されています。これを読み出せばいいです。
Vertex ShaderとFragment Shaderのエラー
→ getShaderInfoLogで取得
WebGL Programのエラー
→ getProgramInfoLogで取得
Vertex Shader と Fragment Shader については、WebGL2RenderingContext と WebGLShader のインスタンスを取得し、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.jsとscript.jsを読み込んでいるだけで、あとはテンプレ、ボイラープレートです。
<!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 Shader と Fragment Shader と WebGL Program をそれぞれ取り出して、メッセージが記録されていればそれをコンソールに throw しています。
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コードは、この記事の内容的にはどうでもいいですが、後ほどこれを少し破壊して、どんなエラーが出るか確認してみます。
#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);
}
#version 300 es
precision mediump float;
in vec4 vertColor;
out vec4 fragColor;
void main() {
// vertex shaderから受け取った値を色として出力するだけ
fragColor = vertColor;
}
出力結果
エラー例1 vertex shaderのエラー
- out vec4 vertColor;
+ out vec3 vertColor;
vertex shader で型エラーを引き起こしてみます。
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のエラー
- out vec4 fragColor;
こうすると…
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 と呼ばれていた奴ですね。型を不一致にさせてみます。
- in vec4 vertColor;
- out vec4 fragColor;
+ in vec3 vertColor;
+ out vec3 fragColor;
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 ShaderとFragment Shaderのエラー
→ getShaderInfoLogで取得
WebGL Programのエラー
→ getProgramInfoLogで取得




