Skip to content

Instantly share code, notes, and snippets.

@sessamekesh
Created July 14, 2019 06:48
Show Gist options
  • Save sessamekesh/92a0f46f37b2cfe9aa32104495437ce7 to your computer and use it in GitHub Desktop.
Save sessamekesh/92a0f46f37b2cfe9aa32104495437ce7 to your computer and use it in GitHub Desktop.
Quick example about loading vertex/fragment shaders from a GLSL file (instead of inlining it)
//
// If you're loading the shaders from an external file, one way or
// another you'll have to do some asynchronous stuff. This means
// that you'll have to run the code to load the shader (which can
// potentially take awhile), and have a callback ready to start
// the demo once the shader source is loaded.
// I'll illustrate three ways to do that here, hopefully it helps!
//
// Code shared between all three methods: essentially the same code
// that's in the videos, except that it's wrapped inside a function
// that takes vertexShaderText and fragmentShaderText as parameters
// instead of defining them as variables at the top.
function runDemo(webGLContext, vertexShaderText, fragmentShaderText) {
// "const" is loosely the same as "var", but newer and better.
const vs = webGLContext.createShader(webGLContext.VERTEX_SHADER);
webGLContext.shaderSource(vs, vertexShaderText);
// ... so on, like in the videos
}
loadShadersAndRunDemo();
// Method 1: Async/Await
// By far the cleanest to read, but requires new-ish JavaScript features
// that aren't super common yet.
// Notice "async" before "function" - this marks the function as an
// asynchronous function, meaning that it will return a Promise.
// Read up on promises here if you aren't familiar:
// https://developers.google.com/web/fundamentals/primers/promises
async function loadShadersAndRunDemo() {
// "fetch" makes an HTTP request to the given address, then returns
// a Result object that can be parsed as text, json, or binary.
// We want the text result!
// "await" says "wait for the fetch call to finish before setting
// the variable and continuing execution"
const vertexShaderText = await fetch('vertexshader.glsl')
.then(result => result.text());
const fragmentShaderText = await fetch('fragmentshader.glsl')
.then(result => result.text());
runDemo(vertexShaderText, fragmentShaderText);
}
// Method 2: Promise-based. Identical to the method 1 in how the web
// browser actually runs the code, but not quite as new (so it'll
// work on more browsers, and has more demos that use it):
function loadShadersAndRunDemo() {
const vertexShaderPromise = fetch('vertexshader.glsl')
.then(result => result.text());
const fragmentShaderPromise = fetch('fragmentshader.glsl')
.then(result => result.text());
// Promise.all says "wait for these promises to finish, then
// call a function that takes the results as parameters"
Promise.all([vertexShaderPromise, fragmentShaderPromise])
.then((vertexShaderText, fragmentShaderText) => {
runDemo(vertexShaderText, fragmentShaderText);
});
}
// Method 3: Old, outdated, possibly familiar. This is what was common
// around the time I was initially learning WebGL (pre-ES6 days...)
// but I think even in the videos I was using newer stuff than this.
function loadShadersAndRunDemo() {
var vsxml = new XMLHttpRequest();
vsxml.open('GET', 'vertexshader.glsl');
vsxml.onLoad = function (vsText) {
var fsxml = new XMLHttpRequest();
fsxml.open('GET', 'fragmentshader.glsl');
fsxml.onLoad = function (fsText) {
runDemo(vsText, fsText);
};
fsxml.send();
};
vsxml.send();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment