A class to describe a shader program.
Each p5.Shader
object contains a shader program that runs on the graphics processing unit (GPU). Shaders can process many pixels or vertices at the same time, making them fast for many graphics tasks. They’re written in a language called GLSL and run along with the rest of the code in a sketch.
A shader program consists of two files, a vertex shader and a fragment shader. The vertex shader affects where 3D geometry is drawn on the screen and the fragment shader affects color. Once the p5.Shader
object is created, it can be used with the shader() function, as in shader(myShader)
.
A shader can optionally describe hooks, which are functions in GLSL that users may choose to provide to customize the behavior of the shader. For the vertex or the fragment shader, users can pass in an object where each key is the type and name of a hook function, and each value is a string with the parameter list and default implementation of the hook. For example, to let users optionally run code at the start of the vertex shader, the options object could include:
{
vertex: {
'void beforeVertex': '() {}'
}
}
Then, in your vertex shader source, you can run a hook by calling a function with the same name prefixed by HOOK_
:
void main() {
HOOK_beforeVertex();
// Add the rest ofy our shader code here!
}
Note: createShader(), createFilterShader(), and loadShader() are the recommended ways to create an instance of this class.
Examples
Syntax
p5.Shader(renderer, vertSrc, fragSrc, [options])
Parameters
WebGL context for this shader.
source code for the vertex shader program.
source code for the fragment shader program.
An optional object describing how this shader can be augmented with hooks. It can include:
vertex
: An object describing the available vertex shader hooks.fragment
: An object describing the available frament shader hooks.
Methods
Logs the hooks available in this shader, and their current implementation.
Each shader may let you override bits of its behavior. Each bit is called a hook. A hook is either for the vertex shader, if it affects the position of vertices, or in the fragment shader, if it affects the pixel color. This method logs those values to the console, letting you know what you are able to use in a call to modify()
.
For example, this shader will produce the following output:
myShader = baseMaterialShader().modify({
declarations: 'uniform float time;',
'vec3 getWorldPosition': `(vec3 pos) {
pos.y += 20. * sin(time * 0.001 + pos.x * 0.05);
return pos;
}`
});
myShader.inspectHooks();
==== Vertex shader hooks: ====
void beforeVertex() {}
vec3 getLocalPosition(vec3 position) { return position; }
[MODIFIED] vec3 getWorldPosition(vec3 pos) {
pos.y += 20. * sin(time * 0.001 + pos.x * 0.05);
return pos;
}
vec3 getLocalNormal(vec3 normal) { return normal; }
vec3 getWorldNormal(vec3 normal) { return normal; }
vec2 getUV(vec2 uv) { return uv; }
vec4 getVertexColor(vec4 color) { return color; }
void afterVertex() {}
==== Fragment shader hooks: ====
void beforeFragment() {}
Inputs getPixelInputs(Inputs inputs) { return inputs; }
vec4 combineColors(ColorComponents components) {
vec4 color = vec4(0.);
color.rgb += components.diffuse * components.baseColor;
color.rgb += components.ambient * components.ambientColor;
color.rgb += components.specular * components.specularColor;
color.rgb += components.emissive;
color.a = components.opacity;
return color;
}
vec4 getFinalColor(vec4 color) { return color; }
void afterFragment() {}
Returns a new shader, based on the original, but with custom snippets of shader code replacing default behaviour.
Each shader may let you override bits of its behavior. Each bit is called a hook. A hook is either for the vertex shader, if it affects the position of vertices, or in the fragment shader, if it affects the pixel color. You can inspect the different hooks available by calling yourShader.inspectHooks()
. You can also read the reference for the default material, normal material, color, line, and point shaders to see what hooks they have available.
modify()
takes one parameter, hooks
, an object with the hooks you want to override. Each key of the hooks
object is the name of a hook, and the value is a string with the GLSL code for your hook.
If you supply functions that aren't existing hooks, they will get added at the start of the shader as helper functions so that you can use them in your hooks.
To add new uniforms to your shader, you can pass in a uniforms
object containing the type and name of the uniform as the key, and a default value or function returning a default value as its value. These will be automatically set when the shader is set with shader(yourShader)
.
You can also add a declarations
key, where the value is a GLSL string declaring custom uniform variables, globals, and functions shared between hooks. To add declarations just in a vertex or fragment shader, add vertexDeclarations
and fragmentDeclarations
keys.
Copies the shader from one drawing context to another.
Each p5.Shader
object must be compiled by calling shader() before it can run. Compilation happens in a drawing context which is usually the main canvas or an instance of p5.Graphics. A shader can only be used in the context where it was compiled. The copyToContext()
method compiles the shader again and copies it to another drawing context where it can be reused.
The parameter, context
, is the drawing context where the shader will be used. The shader can be copied to an instance of p5.Graphics, as in myShader.copyToContext(pg)
. The shader can also be copied from a p5.Graphics object to the main canvas using the window
variable, as in myShader.copyToContext(window)
.
Note: A p5.Shader object created with createShader(), createFilterShader(), or loadShader() can be used directly with a p5.Framebuffer object created with createFramebuffer(). Both objects have the same context as the main canvas.
Sets the shader’s uniform (global) variables.
Shader programs run on the computer’s graphics processing unit (GPU). They live in part of the computer’s memory that’s completely separate from the sketch that runs them. Uniforms are global variables within a shader program. They provide a way to pass values from a sketch running on the CPU to a shader program running on the GPU.
The first parameter, uniformName
, is a string with the uniform’s name. For the shader above, uniformName
would be 'r'
.
The second parameter, data
, is the value that should be used to set the uniform. For example, calling myShader.setUniform('r', 0.5)
would set the r
uniform in the shader above to 0.5
. data should match the uniform’s type. Numbers, strings, booleans, arrays, and many types of images can all be passed to a shader with setUniform()
.
Related References
copyToContext
Copies the shader from one drawing context to another.
inspectHooks
Logs the hooks available in this shader, and their current implementation.
modify
Returns a new shader, based on the original, but with custom snippets of shader code replacing default behaviour.
setUniform
Sets the shader’s uniform (global) variables.