I am learning WebGL and I can feel that my speed is so slow because I am having a hard time debugging my code. Is there any extension or tool with help of which I can know the value of buffer, attribpointer, matrixes, etc.
I googled and learned about chrome extension spector.js but this does not work with me. I think it supposes to show me frames or context but when I click it shows nothing.
Yes, WebGL is hard to debug and I'm not sure anything will make it a whole lot easier. Most bugs are not something a debugger can find that easily. Certain bugs like un-renderable textures or buffers on the correct size already get reported by the browser. Other bugs though are usually math bugs, logic bugs, or data bugs. For example there is no easy way to step through a WebGL shader.
In any case, if you want to use spector you need to structure your code to be spector friendly. Spector is looking for frames based on requestAnimationFrame.
So, let's take this example which is the last example from this page.
The code has a main
function that looks like this
function main() {
// Get A WebGL context
/** @type {HTMLCanvasElement} */
var canvas = document.querySelector("#canvas");
var gl = canvas.getContext("webgl");
if (!gl) {
return;
}
// setup GLSL program
var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-3d", "fragment-shader-3d"]);
...
}
main();
I changed it to this. I renamed main
to init
and made it so I pass in the gl context.
function init(gl) {
// setup GLSL program
var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-3d", "fragment-shader-3d"]);
...
}
Then I made a new main
that looks like this
function main() {
// Get A WebGL context
/** @type {HTMLCanvasElement} */
var canvas = document.querySelector("#canvas");
var gl = canvas.getContext("webgl");
if (!gl) {
return;
}
const startElem = document.querySelector('button');
startElem.addEventListener('click', start, {once: true});
function start() {
// run the initialization in rAF since spector only captures inside rAF events
requestAnimationFrame(() => {
init(gl);
});
// make so more frames so spector has something to look at.
// Note: a normal webgl app would have a rAF loop: https://webglfundamentals.org/webgl/lessons/webgl-animation.html
requestAnimationFrame(() => {});
requestAnimationFrame(() => {});
requestAnimationFrame(() => {});
requestAnimationFrame(() => {});
requestAnimationFrame(() => {});
}
}
main();
And I added a button to my html
<button type="button">start</button>
<canvas id="canvas"></canvas>
The code is the way it is because we need to get a webgl context first or else spector will not notice the canvas (there will be nothing to select). After when turn to turn on spector, and only after that click the start button to run our code. We need to execute our code in a requestAnimationFrame
because that is what spector is looking for. It only records WebGL functions between frames.
Whether or not it will help you find any bugs though is another matter.
note that, if you are on Mac, Safari also has a WebGL debugger built in but just like spector it's only designed for frames. It requires you to draw something each frame so this worked
function start() {
// I'm not sure running the init code in a rAF is important in Safari but it worked
requestAnimationFrame(() => {
init(gl);
});
// by default safari tries to capture 3 frames so let's give it some frames
// Note: a normal webgl app would have a rAF loop: https://webglfundamentals.org/webgl/lessons/webgl-animation.html
requestAnimationFrame(() => { gl.clear(gl.COLOR_BUFFER_BIT); });
requestAnimationFrame(() => { gl.clear(gl.COLOR_BUFFER_BIT); });
requestAnimationFrame(() => { gl.clear(gl.COLOR_BUFFER_BIT); });
requestAnimationFrame(() => { gl.clear(gl.COLOR_BUFFER_BIT); });
requestAnimationFrame(() => { gl.clear(gl.COLOR_BUFFER_BIT); });
}
Another thing you can do is use a helper to help find errors.
<script src="https://greggman.github.io/webgl-lint/webgl-lint.js" crossorigin></script>
You can either download it or you can just include it via the link above. Example (open the javascript console to see the error)
const gl = document.createElement('canvas').getContext('webgl');
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.vertexAttribPointer(0, 1, gl.BYE, false, 0, 0);
<script src="https://greggman.github.io/webgl-lint/webgl-lint.js" crossorigin></script>
The helper has an API you can read about in its docs that lets you label objects and turn on/off various checks.
spector can be used as a library. Download it and then you can call it directly and tell it start capturing
https://github.com/BabylonJS/Spector.js?tab=readme-ov-file#use-as-a-script-reference