Article | Posted on April 2015

Live WebGL Shader Editor

Reading time: 5 minutes

Topics: WebGL, GLSL, JavaScript

This is a legacy post, ported from the old system:
Images might be too low quality, code might be outdated, and some links might not work.

This article explains how to augment JavaScript APIs and how to use it to create a plug-n-play, live GLSL shader editor.

This is a JavaScript library that aims to provide the same functionality as Firefox DevTools Shader Editor: modify the source of shaders in real-time, in the browser, without reloading, easy to include and totally implementation-agnostic. Using function hooks to modify the relevant methods of WebGLRenderingContext, it's possible to add this features with JavaScript only.

Better check the demo first: A simple cube with three.js

Extending APIs with hooks

One of the best things about JavaScript is its malleable nature. Some coders like it, some don't. I personally love the fact that we can polyfill, augment and re-invent almost any function.

The idea is simple, given an original function (originalFn) and a function that you want to execute along every time originalFn is called (hookFn), pass both to a function that creates a closure that will execute both. We're using Function.prototype.apply() to pass whatever arguments are in the original function signature.

Generic hook function

JavaScript - library

function hook( originalFn, hookFn ) {
  return function() {
    hookFn.apply( this, arguments );
    return originalFn.apply( this, arguments );
  }
}

The order of execution can be switched, in case you want to keep the return value of the originalFn call.

To use it, simply do something like this:

Using a hook function to instrument host methods

JavaScript - library

Document.prototype.getElementById = hook(
  Document.prototype.getElementById,
  function(){
    console.log( 'document.getElementById', arguments );
  }
);

I've used this method for many tools:

It's precisely this last experiment -trying to emulate the Firefox DevTools Web Audio Inspector- that gave me the idea that the Shader Editor -also in Firefox DevTools- could also be done as a library and embedded in a Chrome DevTools extension.

Creating the Shader Editor

To create a shader in WebGL we use a few methods, let's intercept those:

This works so far! We can show a UI with the list of programs, from the programs dictionary. When the user selects a program from the list, we populate the vertex shader editor and the fragment shader editor with the appropritate source code, and every time the user modifies the code, we have the reference to the shader, we can set the shader source again, test if it compiles, and if it compiles, attach it to the program and link the program.

Uniform problems

It turns out that if you cache the an uniform location (retrieved with getUniformLocation), the methods that are used to assign the uniform (uniform1f, uniformMatrix2fv, etc.) no longer work, because even though the program has not actually changed, the uniforms are related to a different program.

So we need to also agument getUniformLocation. This the bit hacky part:

Proof of concept and beyond

So this is a proof of concept. It's as easy to use as including the script before anything else (before the app JavaScript code starts using WebGL context):

Including the Live WebGL Editor in your page

HTML - index.html

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

So this works with Firefox, Chrome, Safari, etc. It works but it needs more time dedicated to it, I'm pretty sure it will fail for a lot of cases.

Additionally, I've added CodeMirror for formating and syntax highlighting, and expanded compileShader to add in-editor error reporting.

But the main idea is to create a Chrome DevTools extension. And I have really no idea how to get that done, so if anyone is willing to help, let's do it!

Comments