🐷

p5jsでshaderのコンパイルエラーを取得する

に公開

結論のソースコード


let myShader;
let vertCode;
let fragCode;

function preload() {
  // 頂点シェーダーは変更しないので事前に読み込む
  vertCode = `
    precision highp float;
    // p5.jsのデフォルトの頂点位置属性
    attribute vec3 aPosition;
    void main() {
      gl_Position = vec4(aPosition, 1.0);
    }
  `;
}

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);

  // 初期シェーダーを設定
  fragCode = `
    precision highp float;
    void main() {
      vec3 color = vec3(0.0, 0.0, 1.0);
      gl_FragColor = vec4(color, 1.0);
    }
  `;
  myShader = createShader(vertCode, fragCode);
  shader(myShader); // なぜかshader()を実行しないとコンパイルされない
}

function draw() {
  background(220);

  myShader.setUniform("u_time", millis() / 1000.0);
  noStroke();
  shader(myShader);
  quad(-1, -1, -1, 1, 1, 1, 1, -1);
  resetShader();
}

function mouseClicked() {
  console.log("mouseClicked");

  // シェーダーを切り替える
  fragCode = `
    precision highp float;
    uniform float u_time;
    uniform vec2 u_mouse;
    void main() {
      vec3 color = vec3(sin(u_time) * 0.5 + 0.5, 0, 0);
      gl_FragColor = vec4(color, 1.0);
      あえてエラーを起こすコード
    }
  `;

  const compilingShader = createShader(vertCode, fragCode);
  shader(compilingShader); // shaderを実行しないとコンパイルされない

  // コンパイルエラーのチェック
  const gl = compilingShader._renderer.GL;
  const frag_compile_status = gl.getShaderParameter(
    compilingShader._fragShader,
    gl.COMPILE_STATUS
  );
  if (frag_compile_status == false) {
    print("shaderコンパイルエラー");
  } else {
    myShader = compilingShader;
  }
}

Image from Gyazo

マウスクリック時にエラーの出てしまうシェーダーに切り替えてしまいますが、コンパイルエラーを検出しています。
もしコンパイルエラー検出がなくて、myShaderにそのまま代入してしまうと、他の箇所でmyShaderを使うときにエラーが出てしまいます。

できなかったこと

  • try...catch
    • p5js内部では、console.errorを出しているだけなので、catchできません
  • loadShaderの第四引数
    • https://p5js.org/reference/p5/loadShader/
    • jsコード内でshaderのコードを書くのではなく、ファイルに保存してやる方法
    • コンパイルエラーは関係なくファイルロードのエラーの検出なので、コンパイルエラーは検出されない
  • createCanvasで取得するcanvasオブジェクトから、webgl2の取得

myCanvas = p5.createCanvas(400, 400, p5.WEBGL);
gl = myCanvas.elt.getContext('webgl2'); // 中身がなかった

利用用途

ちなみにコンパイルエラーのメッセージ内容取得


const messageFrag = gl.getShaderInfoLog(myShader._fragShader);

こんな感じで取得できました
作ったものでは、AIが作ったコードのコンパイルエラーをまたエラーメッセージと一緒にAIへ渡して、コードを修正させてみています。
工夫ができそうです。

Discussion