UNPKG

kampos

Version:

Tiny and fast effects compositor on WebGL

172 lines (166 loc) 5.87 kB
/** * @function displacementTransition * @param {Object} [params] * @param {{x: number=0.0, y: number=0.0}} [params.sourceScale] initial displacement scale values of source media * @param {{x: number=0.0, y: number=0.0}} [params.toScale] initial displacement scale values of target media * @returns {displacementTransitionEffect} * @example displacementTransition() */ export default function ({ sourceScale, toScale } = {}) { const { x: sSx, y: sSy } = sourceScale || { x: 0.0, y: 0.0 }; const { x: tSx, y: tSy } = toScale || { x: 0.0, y: 0.0 }; /** * @typedef {Object} displacementTransitionEffect * @property {ArrayBufferView|ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|ImageBitmap} to media source to transition into * @property {ArrayBufferView|ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|ImageBitmap} map displacement map to use * @property {number} progress number between 0.0 and 1.0 * @property {{x: number?, y: number?}} sourceScale displacement scale values of source media * @property {{x: number?, y: number?}} toScale displacement scale values of target media * @property {boolean} disabled * * @example * const img = new Image(); * img.src = 'disp.jpg'; * effect.map = img; * effect.to = document.querySelector('#video-to'); * effect.sourceScale = {x: 0.4}; * effect.toScale = {x: 0.8}; */ return { vertex: { attribute: { a_transitionToTexCoord: 'vec2', a_transitionDispMapTexCoord: 'vec2', }, main: ` v_transitionToTexCoord = a_transitionToTexCoord; v_transitionDispMapTexCoord = a_transitionDispMapTexCoord;`, }, fragment: { uniform: { u_transitionEnabled: 'bool', u_transitionTo: 'sampler2D', u_transitionDispMap: 'sampler2D', u_transitionProgress: 'float', u_sourceDispScale: 'vec2', u_toDispScale: 'vec2', }, source: ` vec3 transDispMap = vec3(1.0); vec2 transDispVec = vec2(0.0); if (u_transitionEnabled) { // read the displacement texture once and create the displacement map transDispMap = texture2D(u_transitionDispMap, v_transitionDispMapTexCoord).rgb - 0.5; // prepare the source coordinates for sampling transDispVec = vec2(u_sourceDispScale.x * transDispMap.r, u_sourceDispScale.y * transDispMap.g); sourceCoord = clamp(sourceCoord + transDispVec * u_transitionProgress, 0.0, 1.0); }`, main: ` if (u_transitionEnabled) { // prepare the target coordinates for sampling transDispVec = vec2(u_toDispScale.x * transDispMap.r, u_toDispScale.y * transDispMap.g); vec2 targetCoord = clamp(v_transitionToTexCoord + transDispVec * (1.0 - u_transitionProgress), 0.0, 1.0); // sample the target vec4 targetPixel = texture2D(u_transitionTo, targetCoord); // mix the results of source and target color = mix(color, targetPixel.rgb, u_transitionProgress); alpha = mix(alpha, targetPixel.a, u_transitionProgress); }`, }, get disabled() { return !this.uniforms[0].data[0]; }, set disabled(b) { this.uniforms[0].data[0] = +!b; }, get progress() { return this.uniforms[3].data[0]; }, set progress(p) { this.uniforms[3].data[0] = p; }, get sourceScale() { const [x, y] = this.uniforms[4].data; return { x, y }; }, set sourceScale({ x, y }) { if (typeof x !== 'undefined') this.uniforms[4].data[0] = x; if (typeof y !== 'undefined') this.uniforms[4].data[1] = y; }, get toScale() { const [x, y] = this.uniforms[5].data; return { x, y }; }, set toScale({ x, y }) { if (typeof x !== 'undefined') this.uniforms[5].data[0] = x; if (typeof y !== 'undefined') this.uniforms[5].data[1] = y; }, get to() { return this.textures[0].data; }, set to(media) { this.textures[0].data = media; }, get map() { return this.textures[1].data; }, set map(img) { this.textures[1].data = img; }, varying: { v_transitionToTexCoord: 'vec2', v_transitionDispMapTexCoord: 'vec2', }, uniforms: [ { name: 'u_transitionEnabled', type: 'i', data: [1], }, { name: 'u_transitionTo', type: 'i', data: [1], }, { name: 'u_transitionDispMap', type: 'i', data: [2], }, { name: 'u_transitionProgress', type: 'f', data: [0], }, { name: 'u_sourceDispScale', type: 'f', data: [sSx, sSy], }, { name: 'u_toDispScale', type: 'f', data: [tSx, tSy], }, ], attributes: [ { name: 'a_transitionToTexCoord', extends: 'a_texCoord', }, { name: 'a_transitionDispMapTexCoord', extends: 'a_texCoord', }, ], textures: [ { format: 'RGBA', update: true, }, { format: 'RGB', }, ], }; }