Last active
November 23, 2024 19:59
-
-
Save wschutzer/dd5827e77c771caaf770458348c9e17d to your computer and use it in GitHub Desktop.
Motion Blur Template
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Motion Blur Template | |
* --------------------- | |
* This code uses shaders to aproximate the motion blur effect by averaging the pixels along a sequence | |
* of frames. | |
* | |
* Copyright (C) 2024 Waldeck Schutzer (@infinitymathart) | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <https://www.gnu.org/licenses/>. | |
*/ | |
final boolean recording = false; | |
final int duration = 2; // Seconds | |
final int fps = 60; // Frames Per Second | |
final float num_frames = fps*duration; | |
// Motion blur: | |
final int samples_per_frame = 10; // How many frames to average? | |
final float shutter_angle = 1.5; // How distant the frames are in time? | |
final int frameWidth = recording ? 2160 : 800; | |
final float fac = 1.0*frameWidth/800; | |
float t = 0; // Normalized animation time in the interval 0 - 1. | |
PShader motionBlur; | |
PGraphics gtex0; // Each frame is drawn here | |
// Vertex shader code | |
String[] motionBlurVertShader = { | |
"#version 100", | |
"#define PROCESSING_TEXTURE_SHADER", | |
"uniform mat4 transformMatrix;", | |
"uniform mat4 texMatrix;", | |
"attribute vec4 position;", | |
"attribute vec4 color;", | |
"attribute vec2 texCoord;", | |
"varying vec4 vertColor;", | |
"varying vec4 vertTexCoord;", | |
"void main() {", | |
"gl_Position = transformMatrix * position;", | |
"vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);", | |
"vertColor = color;", | |
"}"}; | |
String[] motionBlurFragShader = { | |
"#version 100", | |
"#ifdef GL_ES", | |
"precision mediump float;", | |
"precision mediump int;", | |
"#endif", | |
"#define PROCESSING_TEXTURE_SHADER", | |
"uniform sampler2D texture; // Source and result frame, works as an accumulator", | |
"uniform sampler2D tex0; // Currently drawn frame to be added", | |
"uniform float alpha;", | |
"uniform float beta;", | |
"varying vec4 vertColor; // Seems to be white", | |
"varying vec4 vertTexCoord;", | |
"void main()", | |
"{", | |
" vec4 curColor = texture2D(tex0, vertTexCoord.xy); // Color of current pixel ", | |
" vec4 accColor = texture2D(texture, vertTexCoord.xy); // Color in accumulator", | |
" gl_FragColor = beta*(alpha*accColor + curColor); // Blending", | |
"}"}; | |
void settings() | |
{ | |
size(frameWidth, frameWidth, P2D); // Use P2D renderer for shader support | |
} | |
void setup() | |
{ | |
gtex0 = createGraphics(width, height, P2D); | |
motionBlur = new PShader(this, motionBlurVertShader, motionBlurFragShader); | |
} | |
void draw() | |
{ | |
background(0); | |
for(int i=0; i<samples_per_frame; i++) | |
{ | |
t = map((recording ? 1.0*(frameCount-1): 1.0*mouseX/width*num_frames) + i*shutter_angle/samples_per_frame, 0, num_frames, 0, 1)%1; | |
draw_(gtex0,t); // Draw on gtex1 | |
motionBlur.set("tex0", gtex0); | |
motionBlur.set("alpha", (float)(i)); | |
motionBlur.set("beta", (float)(1.0/(i+1))); | |
filter(motionBlur); // Averages the frames with a moving average | |
} | |
if (recording) | |
{ | |
saveFrame("/tmp/f/frame_####.png"); | |
if (frameCount >= num_frames) | |
exit(); | |
} | |
} | |
void draw_(PGraphics g,float t) | |
{ | |
g.beginDraw(); | |
g.background(0); // Clear the canvas | |
g.noStroke(); | |
g.fill(255, 0, 0); | |
// Draw a moving circle | |
float x = width / 2 + cos(TAU*t) * 200*fac; | |
float y = height / 2 + sin(TAU*t) * 200*fac; | |
g.ellipse(x, y, 50*fac, 50*fac); | |
g.endDraw(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment