Custom Shaders in q5 WebGPU - q5js/q5.js GitHub Wiki
What's a shader?
WebGPU shaders are programs written in WGSL (WebGPU Shading Language) that draw shapes given an array of vertices. These shapes can be textured with an image or video frame. The color of pixels in the shape can also be determined by the result of an equation.
WGSL is a C-like, low-level, statically-typed shading language. It's a superior alternative to WebGL Shading Language (GLSL) because WebGPU provides more helpful error messages and better performance.
The primary components of a shader are:
- the vertex function, which is run for every vertex
- the fragment function, which computes the color of every pixel
Take Google's Tour of WGSL to learn more.
How does q5 make writing shaders easier?
q5's shader creation functions enable users to override the vertex and/or fragment functions in a copy of the respective default shader for drawing shapes, images, videos, or text. This makes it easier to get started with WGSL programming, without having to create the pipelines, data buffers, and all the other WebGPU stuff required to run shaders that render stuff.
Your custom shader code has access to the following data and helper function as part of every q5 default shader.
Data (updated every frame):
q
: struct variable with q5 instance data memberswidth
,height
,halfWidth
,halfHeight
,pixelDensity
,frameCount
,time
,deltaTime
,mouseX
,mouseY
,mouseIsPressed
,keyCode
,keyIsPressed
transforms
: array of 4x4 transformation matricescolors
: array of colors in [r, g, b, a] float format
Helper function:
transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f
applies a transformation matrix to a vertex, then converts it from canvas pixel coordinates to normalized device coordinates (NDC).
Shapes Shader
Source: https://github.com/q5js/q5.js/blob/main/src/shaders/shapes.wgsl
Vertex parameters:
vertexIndex
: index of the vertexpos
: vertex position in canvas pixel coordinatescolorIndex
: index of the color in thecolors
arraymatrixIndex
: index of the transformation matrix in thetransforms
array
Fragment parameters:
position
: fragment position in NDCcolor
: fragment color in [r, g, b, a] float format
Image Shader
Source: https://github.com/q5js/q5.js/blob/main/src/shaders/image.wgsl
Vertex parameters:
vertexIndex
: index of the vertexpos
: vertex position in canvas pixel coordinatestexCoord
: texture coordinate in [u, v] float formattintIndex
: index of the tint color in thecolors
arraymatrixIndex
: index of the transformation matrix in thetransforms
arrayimageAlpha
: alpha value to apply to the image
Fragment parameters:
position
: fragment position in NDCtexCoord
tintColor
: tint color in [r, g, b, a] float formatimageAlpha
Data:
samp
: sampler to usetex
: texture to sample
Functions:
applyTint(color: vec4f, tint: vec4f) -> vec4f
: applies a tint to a color, using the tint's alpha as tinting strength
Text Shader
q5 WebGPU uses the MSDF technique to render text, more info:
https://github.com/q5js/q5.js/wiki/q5-WebGPU-renderer#text-rendering
Source: https://github.com/q5js/q5.js/blob/main/src/shaders/text.wgsl
Vertex parameters:
vertexIndex
: index of the vertexinstanceIndex
: index of the text character
Fragment parameters:
position
: fragment position in NDCtexCoord
: texture coordinate in [u, v] float formatfillColor
: fill color in [r, g, b, a] float formatstrokeColor
: stroke color in [r, g, b, a] float formatstrokeWeight
: stroke weight
Data:
textChars
: array of data for all the characters to render, stored invec4f
format- 0: x position
- 1: y position
- 2: index of the character in the text
- 3: index of the text in
textMetadata
textMetadata
: array ofText
text metadatapos
: position of the textscale
: scale of the textfillIndex
: index of the fill color in thecolors
arraystrokeIndex
: index of the stroke color in thecolors
arraystrokeWeight
: stroke weight
fontChars
: array ofChar
font character datasize
: size of the characteroffset
: offset of the charactertexExtent
: size of the character in the texturetexOffset
: position of the character in the texture
Functions:
calcPos(i: u32, char: vec4f, fontChar: Char, text: Text) -> vec2f
: calculates the vertex position in canvas pixel coordinates, giveni
the current vertex indexcalcUV(i: u32, fontChar: Char) -> vec2f
: calculates the UV mapping coordinates of the character in the font texture, giveni
the current vertex indexcalcDist(texCoord: vec2f, edgeWidth: f32) -> f32
: calculates the distance from the texture coordinate to the nearest edge of the glyph using the MSDF technique, larger edgeWidth values soften the edge of the glyph
Examples
Check out some examples! https://q5js.org/learn/#shadersSection