4 - Running Your Shaders
Chapter 4 - Running Your Shaders
In chapter 4 of the Book of Shaders we learn how to display and edit shaders across different platforms (Linux, Mac, Windows, Raspberry Pi, Browser).
Below I'll review some of the GLSL ecosystem and explain how I'm running GLSL shaders as React components on this site using the static-site generator Docusaurus.
Patricio's GLSL Tools
In writting The Book of Shaders Patricio Gonzalez Vivo developed an ecosystem of GLSL-based tools for displaying and editing shaders:
- glslCanvas - Javascript library for displaying GLSL shaders on an HTML
canvas
element. GLSL source code is loaded from a URL or a string. - glslEditor - In-browser fragment shader editor for GLSL. Uses the above glslCanvas for the built-in viewer.
- glslViewer - Command line tool for GLSL shader generation / display. Think ImageMagick for shaders, but also hot-reloading viewer.
- openframe - Open-source platform for digital art with support for HDMI display using RaspberryPi.
The glslEditor is lovely. Especially for its affordances like control widgets for live tweaking of vectors, numbers, and colours. You can play around with the editor at editor.thebookofshaders.com. Although its ability to save to a URL and its integration to openframe.io seems to be broken due to an SSL issue.
Other Shader Editors and Communities
There are a bunch of other Shader editors worth noting, many of which are also online communities for sharing Shader art:
- ShaderToy - Editor and community. I'll be creating ShaderToy ports for all my WebGL shaders.
- Shaderoo - Similar editor and community.
- ShaderFrog - Another similar editor and community, but this editor is node-based not GLSL. Includes the concept of "composed shaders", which are shaders composed out of multiple more basic sub-shaders.
- ISF Editor - Part of the open Interactive Shader Format for sharing GL shaders/metadata. The ability to create tweakable input parameters with a simple slider-based UI is nice! Also includes a community.
- ShaderFactory - Vertex and fragment shader editor with simple uniform UI.
- KodeLife - Cross-platform real-time GPU shader editor, live-code performance tool and graphics prototyping sketchpad.
- SHADERed - Lightweight, cross-platform & full-featured desktop IDE for shaders. Supports both GLSL and HLSL shaders.
I'm sure I'm missing a bunch, but that should do. ๐
Docusaurus
This website is built using an alpha release of version 2 of Docusaurus, a static site generator for documentation created by Facebook's open source team.
I've been looking for a new way to create static notes for my courses at RRC so I've been meaning to try out a few static site generators. Docusaurus looks to be a good option. A quick run down of the features:
- Docusaurus is built around the React UI library.
- Getting started is easy as their docs are great.
- Docusarus documents are written in Markdown with configurations handled by JSON documents.
- The flavour of Markdown is mdx, which means you can also embed custom React components in your docs.
You can see the markdown docs used to generate this site on Github.
Custom React Component
Take a peek at the shaders running on this page. The shaders are running within the browser through WebGL by way of glslCanvas. I'm not using glslCanvas directly though, I've got it wrapped in two layers of React components.
The first wrapper is react-shader-canvas which makes it easy to display and control a glslCanvas with a React component. In its simplest form it works like this:
I wanted two additional features beyond what react-shader-canvas offered:
- Responsive resizing of the shader canvas depending on screen size.
- Ability to load shader source code from an URL rather than from a string.
To add these two features I wrote my own custom React component to wrap <ShaderCavas>
. Adding a custom component to docusaurus was super easy. First I installed react-shader-canvas using yarn, and then I added a ResponsiveShader.js
file to the docusaurus project folder src\theme\
folder.
The full source code of my <ResponsiveShader>
component can be seen here.
The component is used from with .mdx
docs like this:
The fragShaderPath
is a relative path to the GLSL source code. In this case /shaders/3.0-hello-gradient.frag. Shader source can also be passed in directly as a string:
Responsive Resizing of Component
The responsive resizing is handled by a useEffect
hook that listens for the window
's resize
event. The relevant code is:
Loading Shader Source from a URL
I'm using the fetch API to load shader source from a provided URL. Relevant code:
The use of a ref to mark the component as mount/unmounted is a bit of a hack. I'm not sure why, but the component mounts and then unmounts itself on load, and that was causing a warning to be issued in the fetchShader
function. Checking to see if the component is mounted before setting the fragShaderData
variable fixed this. The specific warning was:
Can't perform a React state update on an unmounted component.
Preventing SSR for Shaders
Just when I thought I was all done with this component I attempted to publish a live version of the site and the server-side rendering (SSR) failed.
The error stated that "window is not defined". This made sense because the window
object is only available in the browser, and not available when server-side rendering, while both my code and glslCanvas itself make use of the window
object. At first I thought this was a show-stopper, but then I came across this issue that pointed out the ability to test for the presence of the browser with ExecutionEnvironment.canUseDom
.
This was the fix I needed, although I needed to include glslCanvas with a require
rather than an import
, as import
statements can't be nested. The relevant code is:
You can see the full <ResponsiveShader>
component source code here.
Next up we'll explore shaping functions. See you then!