diff --git a/src/webgl/ShaderGenerator.js b/src/webgl/ShaderGenerator.js index d029ed44ef..e4b3c6ca23 100644 --- a/src/webgl/ShaderGenerator.js +++ b/src/webgl/ShaderGenerator.js @@ -1,6 +1,6 @@ /** * @module 3D -* @submodule ShaderGenerator +* @submodule Material * @for p5 * @requires core */ @@ -1638,3 +1638,507 @@ export default shadergenerator; if (typeof p5 !== 'undefined') { p5.registerAddon(shadergenerator) } + + + +/* ------------------------------------------------------------- */ +/** + * @method getWorldInputs + * @description + * Registers a callback to modify the world-space properties of each vertex in a shader. This hook can be used inside baseColorShader().modify() and similar shader modify calls to customize vertex positions, normals, texture coordinates, and colors before rendering. "World space" refers to the coordinate system of the 3D scene, before any camera or projection transformations are applied. + * + * The callback receives a vertex object with the following properties: + * - `position`: a vector with three components representing the original position of the vertex + * - `normal`: a vector with three components representing the direction the surface is facing + * - `texCoord`: a vector with two components representing the texture coordinates + * - `color`: a vector with four components representing the color of the vertex (red, green, blue, alpha) + * + * This hook is available in: + * - baseMaterialShader() + * - baseNormalShader() + * - baseColorShader() + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which receives a vertex object containing position (vec3), normal (vec3), texCoord (vec2), and color (vec4) properties. The function should return the modified vertex object. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseMaterialShader().modify(() => { + * let t = uniformFloat(() => millis()); + * getWorldInputs(inputs => { + * // Move the vertex up and down in a wave in world space + * // In world space, moving the object (e.g., with translate()) will affect these coordinates +* // The sphere is ~50 units tall here, so 20 gives a noticeable wave + * inputs.position.y += 20 * sin(t * 0.001 + inputs.position.x * 0.05); + * return inputs; + * }); + * }); + * } + * function draw() { + * background(255); + * shader(myShader); + * lights(); + * noStroke(); + * fill('red'); + * sphere(50); + * } + * + *
+ */ + +/** + * @method combineColors + * @description + * Registers a callback to customize how color components are combined in the fragment shader. This hook can be used inside baseMaterialShader().modify() and similar shader modify calls to control the final color output of a material. The callback receives an object with the following properties: + * + * - `baseColor`: a vector with three components representing the base color (red, green, blue) + * - `diffuse`: a single number representing the diffuse reflection + * - `ambientColor`: a vector with three components representing the ambient color + * - `ambient`: a single number representing the ambient reflection + * - `specularColor`: a vector with three components representing the specular color + * - `specular`: a single number representing the specular reflection + * - `emissive`: a vector with three components representing the emissive color + * - `opacity`: a single number representing the opacity + * + * The callback should return a vector with four components (red, green, blue, alpha) for the final color. + * + * This hook is available in: + * - baseMaterialShader() + * + * @param {function} callback + * A callback function which receives the object described above and returns a vector with four components for the final color. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseMaterialShader().modify(() => { + * combineColors(components => { + * // Custom color combination: add a green tint using vector properties + * return [ + * components.baseColor * components.diffuse + + * components.ambientColor * components.ambient + + * components.specularColor * components.specular + + * components.emissive + + * [0, 0.2, 0], // Green tint for visibility + * components.opacity + * ]; + * }); + * }); + * } + * function draw() { + * background(255); + * shader(myShader); + * lights(); + * noStroke(); + * fill('red'); + * sphere(50); + * } + * + *
+ */ + +/** + * @method beforeVertex + * @private + * @description + * Registers a callback to run custom code at the very start of the vertex shader. This hook can be used inside baseColorShader().modify() and similar shader modify calls to set up variables or perform calculations that affect every vertex before processing begins. The callback receives no arguments. + * + * Note: This hook is currently limited to per-vertex operations; storing variables for later use is not supported. + * + * This hook is available in: + * - baseColorShader() + * - baseMaterialShader() + * - baseNormalShader() + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which is called before each vertex is processed. + */ + +/** + * @method afterVertex + * @private + * @description + * Registers a callback to run custom code at the very end of the vertex shader. This hook can be used inside baseColorShader().modify() and similar shader modify calls to perform cleanup or final calculations after all vertex processing is done. The callback receives no arguments. + * + * Note: This hook is currently limited to per-vertex operations; storing variables for later use is not supported. + * + * This hook is available in: + * - baseColorShader() + * - baseMaterialShader() + * - baseNormalShader() + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which is called after each vertex is processed. + */ + +/** + * @method beforeFragment + * @private + * @description + * Registers a callback to run custom code at the very start of the fragment shader. This hook can be used inside baseColorShader().modify() and similar shader modify calls to set up variables or perform calculations that affect every pixel before color calculations begin. The callback receives no arguments. + * + * This hook is available in: + * - baseColorShader() + * - baseMaterialShader() + * - baseNormalShader() + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which is called before each fragment is processed. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseColorShader().modify(() => { + * beforeFragment(() => { + * // Set a value for use in getFinalColor + * this.brightness = 0.5 + 0.5 * sin(millis() * 0.001); + * }); + * getFinalColor(color => { + * // Use the value set in beforeFragment to tint the color + * color.r *= this.brightness; // Tint red channel + * return color; + * }); + * }); + * } + * function draw() { + * background(220); + * shader(myShader); + * noStroke(); + * fill('teal'); + * box(100); + * } + * + *
+ */ + +/** + * @method getPixelInputs + * @description + * Registers a callback to modify the properties of each fragment (pixel) before the final color is calculated in the fragment shader. This hook can be used inside baseMaterialShader().modify() and similar shader modify calls to adjust per-pixel data before lighting/mixing. + * + * The callback receives an `Inputs` object. Available fields depend on the shader: + * + * - In baseMaterialShader(): + * - `normal`: a vector with three components representing the surface normal + * - `texCoord`: a vector with two components representing the texture coordinates (u, v) + * - `ambientLight`: a vector with three components representing the ambient light color + * - `ambientMaterial`: a vector with three components representing the material's ambient color + * - `specularMaterial`: a vector with three components representing the material's specular color + * - `emissiveMaterial`: a vector with three components representing the material's emissive color + * - `color`: a vector with four components representing the base color (red, green, blue, alpha) + * - `shininess`: a number controlling specular highlights + * - `metalness`: a number controlling the metalness factor + * + * - In baseStrokeShader(): + * - `color`: a vector with four components representing the stroke color (red, green, blue, alpha) + * - `tangent`: a vector with two components representing the stroke tangent + * - `center`: a vector with two components representing the cap/join center + * - `position`: a vector with two components representing the current fragment position + * - `strokeWeight`: a number representing the stroke weight in pixels + * + * Return the modified object to update the fragment. + * + * This hook is available in: + * - baseMaterialShader() + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which receives the fragment inputs object and should return it after making any changes. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseMaterialShader().modify(() => { + * let t = uniformFloat(() => millis()); + * getPixelInputs(inputs => { + * // Animate alpha (transparency) based on x position + * inputs.color.a = 0.5 + 0.5 * sin(inputs.texCoord.x * 10.0 + t * 0.002); + * return inputs; + * }); + * }); + * } + * function draw() { + * background(240); + * shader(myShader); + * lights(); + * noStroke(); + * fill('purple'); + * circle(0, 0, 100); + * } + * + *
+ */ + +/** + * @method shouldDiscard + * @private + * @description + * Registers a callback to decide whether to discard (skip drawing) a fragment (pixel) in the fragment shader. This hook can be used inside baseStrokeShader().modify() and similar shader modify calls to create effects like round points or custom masking. The callback receives a boolean: + * - `willDiscard`: true if the fragment would be discarded by default + * + * Return true to discard the fragment, or false to keep it. + * + * This hook is available in: + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which receives a boolean and should return a boolean. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseStrokeShader().modify({ + * 'bool shouldDiscard': '(bool outside) { return outside; }' + * }); + * } + * function draw() { + * background(255); + * strokeShader(myShader); + * strokeWeight(30); + * line(-width/3, 0, width/3, 0); + * } + * + *
+ */ + +/** + * @method getFinalColor + * @description + * Registers a callback to change the final color of each pixel after all lighting and mixing is done in the fragment shader. This hook can be used inside baseColorShader().modify() and similar shader modify calls to adjust the color before it appears on the screen. The callback receives a four component vector representing red, green, blue, and alpha. + * + * Return a new color array to change the output color. + * + * This hook is available in: + * - baseColorShader() + * - baseMaterialShader() + * - baseNormalShader() + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which receives the color array and should return a color array. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseColorShader().modify(() => { + * getFinalColor(color => { + * // Add a blue tint to the output color + * color.b += 0.2; + * return color; + * }); + * }); + * } + * function draw() { + * background(230); + * shader(myShader); + * noStroke(); + * fill('green'); + * circle(0, 0, 100); + * } + * + *
+ */ + +/** + * @method afterFragment + * @private + * @description + * Registers a callback to run custom code at the very end of the fragment shader. This hook can be used inside baseColorShader().modify() and similar shader modify calls to perform cleanup or final per-pixel effects after all color calculations are done. The callback receives no arguments. + * + * This hook is available in: + * - baseColorShader() + * - baseMaterialShader() + * - baseNormalShader() + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which is called after each fragment is processed. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseColorShader().modify(() => { + * getFinalColor(color => { + * // Add a purple tint to the color + * color.b += 0.2; + * return color; + * }); + * afterFragment(() => { + * // This hook runs after the final color is set for each fragment. + * // You could use this for debugging or advanced effects. + * }); + * }); + * } + * function draw() { + * background(240); + * shader(myShader); + * noStroke(); + * fill('purple'); + * sphere(60); + * } + * + *
+ */ + +/** + * @method getColor + * @description + * Registers a callback to set the final color for each pixel in a filter shader. This hook can be used inside baseFilterShader().modify() and similar shader modify calls to control the output color for each pixel. The callback receives the following arguments: + * - `inputs`: an object with the following properties: + * - `texCoord`: a vector with two components representing the texture coordinates (u, v) + * - `canvasSize`: a vector with two components representing the canvas size in pixels (width, height) + * - `texelSize`: a vector with two components representing the size of a single texel in texture space + * - `canvasContent`: a texture containing the sketch's contents before the filter is applied + * + * Return a four-component vector `[r, g, b, a]` for the pixel. + * + * This hook is available in: + * - baseFilterShader() + * + * @param {function} callback + * A callback function which receives the inputs object and canvasContent, and should return a color array. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseFilterShader().modify(() => { + * getColor((inputs, canvasContent) => { + * // Warp the texture coordinates for a wavy effect + * let warped = [inputs.texCoord.x, inputs.texCoord.y + 0.1 * sin(inputs.texCoord.x * 10.0)]; + * return getTexture(canvasContent, warped); + * }); + * }); + * } + * function draw() { + * background(180); + * // Draw something to the canvas + * fill('yellow'); + * circle(0, 0, 150); + * filter(myShader); + * } + * + *
+ */ + +/** + * @method getObjectInputs + * @description + * Registers a callback to modify the properties of each vertex before any transformations are applied in the vertex shader. This hook can be used inside baseColorShader().modify() and similar shader modify calls to move, color, or otherwise modify the raw model data. The callback receives an object with the following properties: + * - `position`: a vector with three components representing the original position of the vertex + * - `normal`: a vector with three components representing the direction the surface is facing + * - `texCoord`: a vector with two components representing the texture coordinates + * - `color`: a vector with four components representing the color of the vertex (red, green, blue, alpha) + * + * Return the modified object to update the vertex. + * + * This hook is available in: + * - baseColorShader() + * - baseMaterialShader() + * - baseNormalShader() + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which receives the vertex object and should return it after making any changes. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseColorShader().modify(() => { + * let t = uniformFloat(() => millis()); + * getObjectInputs(inputs => { + * // Create a sine wave along the x axis in object space + * inputs.position.y += 20 * sin(t * 0.001 + inputs.position.x * 0.05); + * return inputs; + * }); + * }); + * } + * function draw() { + * background(220); + * shader(myShader); + * noStroke(); + * fill('orange'); + * sphere(100); + * } + * + *
+ */ + +/** + * @method getCameraInputs + * @description + * Registers a callback to adjust vertex properties after the model has been transformed by the camera, but before projection, in the vertex shader. This hook can be used inside baseColorShader().modify() and similar shader modify calls to create effects that depend on the camera's view. The callback receives an object with the following properties: + * - `position`: a vector with three components representing the position after camera transformation + * - `normal`: a vector with three components representing the normal after camera transformation + * - `texCoord`: a vector with two components representing the texture coordinates + * - `color`: a vector with four components representing the color of the vertex (red, green, blue, alpha) + * + * Return the modified object to update the vertex. + * + * This hook is available in: + * - baseColorShader() + * - baseMaterialShader() + * - baseNormalShader() + * - baseStrokeShader() + * + * @param {function} callback + * A callback function which receives the vertex object and should return it after making any changes. + * + * @example + *
+ * + * let myShader; + * function setup() { + * createCanvas(200, 200, WEBGL); + * myShader = baseColorShader().modify(() => { + * getCameraInputs(inputs => { + * // Move vertices in camera space based on their x position + * let t = uniformFloat(() => millis()); + * inputs.position.y += 30 * sin(inputs.position.x * 0.05 + t * 0.001); + * // Tint all vertices blue + * inputs.color.b = 1; + * return inputs; + * }); + * }); + * } + * function draw() { + * background(200); + * shader(myShader); + * noStroke(); + * fill('blue'); + * sphere(100); + * } + * + *
+ */ \ No newline at end of file