xxxxxxxxxx
/*
Back in 2019 I made an OpenFrameworks sketch that did something like this.
*/
let capture
const buffers = []
let blendShader
function setup() {
createCanvas(640, 480, WEBGL)
pixelDensity(1)
setAttributes({ alpha: true, premultipliedAlpha: true })
capture = createCapture(VIDEO)
capture.hide()
blendShader = createShader(blendShaderSource())
centerCanvas()
// Each frame basically contributes one horizontal slice of the frame. This
// variable controls how many slices there are.
// Bigger number --> less wiggly looking, less delay
// Lower number --> more wiggly, but with more delay
const heightPerFrame = 4
for (let i = 0; i < height; i += heightPerFrame) {
buffers.push(createFramebuffer())
}
}
function draw() {
clear()
background(0)
imageMode(CENTER)
const bufferIdx = frameCount % buffers.length
buffers[bufferIdx].draw(() => {
clear()
drawingContext.disable(drawingContext.BLEND)
image(
capture,
0, 0, width, height,
0, 0, capture.width, capture.height,
COVER, CENTER, CENTER, // hell yeah new p5 feature
)
})
push()
drawingContext.disable(drawingContext.DEPTH_TEST)
noStroke()
textureMode(NORMAL)
shader(blendShader)
// In my old sketch I just drew one rectangle from each past frame in
// the buffer. This time, I'm using a shader to do a ✨GRADIENT MASK✨
// so that the edges between rectangles are a little smoother.
//
// This variable controls how many rectangles long the blended area
// should be. The more rows blended, the less you'll see hard horizontal
// lines between frames (but you'll still see some vertical ones.)
const rowsToBlend = 20
for (let i = 0; i < buffers.length; i++) {
const rowBuffer = ((bufferIdx - i) % buffers.length + buffers.length) % buffers.length
blendShader.setUniform('tex', buffers[rowBuffer].color)
drawingContext.enable(drawingContext.BLEND)
drawingContext.blendEquation(drawingContext.FUNC_ADD)
drawingContext.blendFunc(
drawingContext.ONE,
drawingContext.ONE_MINUS_SRC_ALPHA
)
beginShape(QUAD_STRIP)
for (const offY of [-rowsToBlend, 0, 1]) {
for (const sideX of [-1, 1]) {
const x = sideX * width/2
const y = map(i + offY, 0, buffers.length, -height/2, height/2)
const u = map(sideX, -1, 1, 1, 0)
const v = map(i + offY, 0, buffers.length, 1, 0)
fill(255, 255, 255, map(offY, -rowsToBlend, 0, 0, 255, true))
vertex(x, y, u, v)
}
}
endShape()
}
pop()
}