Reference p5.Shader

p5.Shader

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

renderer
p5.RendererGL:

WebGL context for this shader.

vertSrc
String:

source code for the vertex shader program.

fragSrc
String:

source code for the fragment shader program.

options
Object:

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

inspectHooks

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() {}
modify

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.

copyToContext

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.

setUniform

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().

Notice any errors or typos? Please let us know. Please feel free to edit src/webgl/p5.Shader.js and open a pull request!

Related References