@absulit/points
Version:
A Generative Art library made in WebGPU
398 lines (354 loc) • 11.5 kB
JavaScript
/* @ts-self-types="./RenderPasses.d.ts" */
import color$1 from './core/RenderPasses/color/index.js';
import grayscale from './core/RenderPasses/grayscale/index.js';
import chromaticAberration from './core/RenderPasses/chromaticAberration/index.js';
import pixelate from './core/RenderPasses/pixelate/index.js';
import lensDistortion from './core/RenderPasses/lensDistortion/index.js';
import filmgrain from './core/RenderPasses/filmgrain/index.js';
import bloom from './core/RenderPasses/bloom/index.js';
import blur from './core/RenderPasses/blur/index.js';
import waves from './core/RenderPasses/waves/index.js';
import { RenderPass } from 'points';
import './RenderPass.js';
const vert = /*wgsl*/`
fn main(in: VertexIn) -> FragmentIn {
return defaultVertexBody(in.position, in.color, in.uv, in.normal);
}
`;
/**
* A few color constants and wgsl methods to work with colors.
* <br>
* <br>
* These are wgsl functions, not js functions.
* The function is enclosed in a js string constant,
* to be appended into the code to reference it in the string shader.
* @module points/color
*/
/**
* RED color;
* @type {vec4f}
*
* @example
* // js
* import { RED } from 'points/color';
*
* // wgsl string
* ${RED}
* let value = RED * vec4f(.5);
*/
const RED = /*wgsl*/`
const RED = vec4(1.,0.,0.,1.);
`;
/**
* GREEN color;
* @type {vec4f}
*
* @example
* // js
* import { GREEN } from 'points/color';
*
* // wgsl string
* ${GREEN}
* let value = GREEN * vec4f(.5);
*/
const GREEN = /*wgsl*/`
const GREEN = vec4(0.,1.,0.,1.);
`;
/**
* BLUE color;
* @type {vec4f}
*
* @example
* // js
* import { BLUE } from 'points/color';
*
* // wgsl string
* ${BLUE}
* let value = BLUE * vec4f(.5);
*/
const BLUE = /*wgsl*/`
const BLUE = vec4(0.,0.,1.,1.);
`;
/**
* These are wgsl functions, not js functions.
* The function is enclosed in a js string constant,
* to be appended into the code to reference it in the string shader.
* @module points/image
*/
/**
* Places a texture. The texture being an image loaded from the JS side.
* @type {String}
* @param {texture_2d<f32>} texture `texture_2d<f32>`
* @param {sampler} aSampler `sampler`
* @param {vec2f} uv `vec2f`
* @param {bool} crop `bool`
* @returns {vec4f}
*
* @example
*
* // js
* import { texture } from 'points/image';
*
* await points.setTextureImage('image', 'myimage.jpg');
*
* // wgsl string
* ${texture}
* let value = texture(image, imageSampler, uvr, true);
*/
const texture = /*wgsl*/`
fn texture(texture:texture_2d<f32>, aSampler:sampler, uv:vec2f, crop:bool) -> vec4f {
let flipTexture = vec2(1.,-1.);
let flipTextureCoordinates = vec2(-1.,1.);
let dims:vec2u = textureDimensions(texture, 0);
let dimsF32 = vec2f(dims);
let minScreenSize = params.screen.y;
let imageRatio = dimsF32 / minScreenSize;
let displaceImagePosition = vec2(0., 1.);
let imageUV = uv / imageRatio * flipTexture + displaceImagePosition;
var rgbaImage = textureSample(texture, aSampler, imageUV);
// e.g. if uv.x < 0. OR uv.y < 0. || uv.x > imageRatio.x OR uv.y > imageRatio.y
if (crop && (any(uv < vec2(0.0)) || any(uv > imageRatio))) {
rgbaImage = vec4(0.);
}
return rgbaImage;
}
`;
/**
* A few signed distance functions.
* <br>
* <br>
* These are wgsl functions, not js functions.
* The function is enclosed in a js string constant,
* to be appended into the code to reference it in the string shader.
* @module points/sdf
*/
/**
* Create a rectangle with two coordinates.
* @type {String}
* @param {vec2f} startPoint first coordinate, one corner of the rectangle
* @param {vec2f} endPoint second coordinate, opposite corner of the rectangle
* @param {vec2f} uv
* @return {f32}
*
* @example
* // wgsl string
* sdfRect(vec2f(), vec2f(1), in.uvr);
*
*/
const sdfRect = /*wgsl*/`
fn sdfRect(startPoint:vec2f, endPoint:vec2f, uv:vec2f) -> f32 {
let value = select(
0.,
1.,
(startPoint.x < uv.x) &&
(startPoint.y < uv.y) &&
(uv.x < endPoint.x) &&
(uv.y < endPoint.y)
);
return smoothstep(0, .5, value);
}
`;
/**
* Math utils
*
* These are wgsl functions, not js functions.
* The function is enclosed in a js string constant,
* to be appended into the code to reference it in the string shader.
* @module points/math
*/
/**
* Rotates a vector an amount of radians
* @type {String}
* @param {vec2f} p vector to rotate
* @param {f32} rads angle in radians
*
* @example
* // js
* import { rotateVector } from 'points/math';
*
* // wgsl string
* ${rotateVector}
* let value = rotateVector(position, radians);
*/
const rotateVector = /*wgsl*/`
fn rotateVector(p:vec2f, rads:f32 ) -> vec2f {
let s = sin(rads);
let c = cos(rads);
let xnew = p.x * c - p.y * s;
let ynew = p.x * s + p.y * c;
return vec2(xnew, ynew);
}
`;
/**
* Utilities for animation.
* <br>
* Functions that use sine and `params.time` to increase and decrease a value over time.
* <br>
* <br>
* These are wgsl functions, not js functions.
* The function is enclosed in a js string constant,
* to be appended into the code to reference it in the string shader.
* @module points/animation
*/
/**
* Animates `sin()` over `params.time` and a provided `speed`.
* The value is normalized, so in the range 0..1
* @type {String}
* @param {f32} speed
* @example
* // js
* import { fnusin } from 'points/animation';
*
* // wgsl string
* ${fnusin}
* let value = fnusin(2.);
*/
const fnusin = /*wgsl*/`
fn fnusin(speed: f32) -> f32{
return (sin(params.time * speed) + 1.) * .5;
}
`;
const frag = /*wgsl*/`
${fnusin}
${sdfRect}
${rotateVector}
${texture}
${RED + GREEN + BLUE}
const NUMCOLUMNS = 200.;
fn main(in: FragmentIn) -> vec4f {
let numColumns = NUMCOLUMNS * params.crt_scale;
let numRows = NUMCOLUMNS * params.crt_scale;
let pixelsWidth = params.screen.x / numColumns;
let pixelsHeight = params.screen.y / numRows;
let dx = pixelsWidth * (1. / params.screen.x);
let dy = pixelsHeight * (1. / params.screen.y);
// if column is pair then displace by this amount
let x = select(0., .5, floor(in.uvr.x / dx) % 2 == 0.);
let pixeleduv = vec2(dx*floor( in.uvr.x / dx), dy * floor(in.uvr.y / dy + x));
let pixeleduvColor = vec4(pixeleduv, 0, 1);
let subuv = fract(in.uvr * vec2(numColumns, numRows) + vec2(0,x));
let subuvColor = vec4(subuv, 0, 1);
// --------- chromatic displacement vector
let cdv = vec2(params.crt_displacement, 0.);
let imageColorG = texture(renderpass_feedbackTexture, renderpass_feedbackSampler, pixeleduv, true).g;
let imageColorR = texture(renderpass_feedbackTexture, renderpass_feedbackSampler, pixeleduv + cdv, true).r;
let imageColorB = texture(renderpass_feedbackTexture, renderpass_feedbackSampler, pixeleduv - cdv, true).b;
let bottom_left = vec2(.0, .0);
let top_right = bottom_left + vec2(.33, 1.);
let margin = vec2(.01,0.) * 4;
let margin_v = vec2(.0, .01) * 8;
let offset = vec2(.33,0);
let redSlot = RED * imageColorR * sdfRect(margin+margin_v+bottom_left + offset * 0, top_right - margin - margin_v + offset * 0, subuv); // subuv
let greenSlot = GREEN * imageColorG * sdfRect(margin+margin_v+bottom_left + offset * 1, top_right - margin - margin_v + offset * 1, subuv);
let blueSlot = BLUE * imageColorB * sdfRect(margin+margin_v+bottom_left + offset * 2, top_right - margin - margin_v + offset * 2, subuv);
let finalColor = redSlot + greenSlot + blueSlot;
return finalColor;
}
`;
const color = new RenderPass(vert, frag, null, 8, 8, 1, (points, params) => {
points.setSampler('renderpass_feedbackSampler', null).internal = true;
points.setTexture2d('renderpass_feedbackTexture', true).internal = true;
points.setUniform('crt_scale', params.scale || .390);
points.setUniform('crt_displacement', params.displacement || .013);
});
color.required = ['scale', 'displacement'];
color.name = 'CRT';
/**
* List of predefined Render Passes for Post Processing.
* Parameters required are shown as a warning in the JS console.
* @class
*
* @example
* import Points, { RenderPass, RenderPasses } from 'points';
* const points = new Points('canvas');
*
* // option 1: along with the RenderPasses pased into `Points.init()`
* let renderPasses = [
* new RenderPass(vert1, frag1, compute1),
* new RenderPass(vert2, frag2, compute2)
* ];
*
* // option 2: calling `points.addRenderPass()` method
* points.addRenderPass(RenderPasses.GRAYSCALE);
* points.addRenderPass(RenderPasses.CHROMATIC_ABERRATION, { distance: .02 });
* points.addRenderPass(RenderPasses.COLOR, { color: [.5, 1, 0, 1], blendAmount: .5 });
* points.addRenderPass(RenderPasses.PIXELATE);
* points.addRenderPass(RenderPasses.LENS_DISTORTION);
* points.addRenderPass(RenderPasses.FILM_GRAIN);
* points.addRenderPass(RenderPasses.BLOOM);
* points.addRenderPass(RenderPasses.BLUR, { resolution: [100, 100], direction: [.4, 0], radians: 0 });
* points.addRenderPass(RenderPasses.WAVES, { scale: .05 });
*
* await points.init(renderPasses);
*
* points.update(update);
*
* function update() {
* // update uniforms and other animation variables
* }
*/
class RenderPasses {
/**
* Apply a color {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.COLOR, { color: [.5, 1, 0, 1], blendAmount: .5 });
*/
static COLOR = color$1;
/**
* Apply a grayscale {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.GRAYSCALE);
*/
static GRAYSCALE = grayscale;
/**
* Apply a chromatic aberration {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.CHROMATIC_ABERRATION, { distance: .02 });
*/
static CHROMATIC_ABERRATION = chromaticAberration;
/**
* Apply a pixelation {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.PIXELATE);
*/
static PIXELATE = pixelate;
/**
* Apply a lens distortion {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.LENS_DISTORTION);
*/
static LENS_DISTORTION = lensDistortion;
/**
* Apply a film grain {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.FILM_GRAIN);
*/
static FILM_GRAIN = filmgrain;
/**
* Apply a bloom {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.BLOOM);
*/
static BLOOM = bloom;
/**
* Apply a blur {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.BLUR, { resolution: [100, 100], direction: [.4, 0], radians: 0 });
*/
static BLUR = blur;
/**
* Apply a waives noise {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.WAVES, { scale: .05 });
*/
static WAVES = waves;
/**
* Apply a CRT tv pixels effect {@link RenderPass}
* @example
* points.addRenderPass(RenderPasses.CRT, { scale: .05 });
*/
static CRT = color;
}
export { RenderPasses as default };