I'm trying to create a graphic synchronized with a video at 25 frames/sec. I'm trying to save one frame every 40 msec, but I can't get 25 frames per sec, but only one image.
Can someone help me?
int t1;
int count;
void setup(){
size(400,100);
background(0);
stroke(255);
fill(250);
line(10,0,10,100);
line(260,0,260,100);
for (int i=10;i<251;i+=10){
t1=millis();
while(millis()-t1 < 40) {
count++;
}
rect(10,50,i,10);
//saveFrame("line-####.png");
}
}
void draw(){}
The problem in your code is that the canvas is updated only after the end of a frame, which means that your rectangles do exist but are not displayed until your setup() ends. This is why, even tho your code correctly waits 40 milliseconds before drawing a new rectangle, nothing is shown until the for loop ends: before ending the frame, Processing is waiting to complete the for loop.
However, in Processing draw() is called a certain amount of times per second, this amount of times is specified by the function frameRate() (default is 60).
Thus you can just set frameRate to 25 and save an image each time draw() is called.
noLoop() is used to stop calling draw(), in this case, once the rectangles are all drawn.
int count;
void setup()
{
frameRate(25);
size(400,100);
background(0);
stroke(255);
fill(250);
line(10,0,10,100);
line(260,0,260,100);
}
void draw()
{
rect(10,50,count,10);
saveFrame("line-####.png");
count += 10;
if(count > 251)
{
noLoop();
}
}
Related
So I want to have a delay in my Draw function so that when I want to do
Xoffset = Xoffset + 1.5
I do not go from 0 to 30 in a secnd, but I want there to be some delay in the code so that I can easily manage it. I usually use scratch and if you are unfimiliar to that the command for a code delay is
Wait(Insert amount of seconds you want to delay here)
So when you start a part of the code, and the Wait is set to 2, the input will go off, wait 2 seconds, and then move on the the line of code below. I am trying to replicate that but in p5.js.
To detail my comment above, you could do something like this:
var xOffset = 0;
// time delay vars
// current time "snapshot" (imagine pressing the lap time button)
var time;
// the interval to wait between time "snapshots": 2s (2000 milliseconds) in this case
var wait = 2000;
function setup() {
createCanvas(300, 300);
//store the current time
time = millis();
}
function draw() {
background(220);
//check if the difference between now and the previously stored time
// is greater than the wait interval
if(millis() - time >= wait){
console.log(wait, "ms passed");
//if it is, do something
xOffset = xOffset + 1.5;
//also update the stored time
time = millis();
}
circle(xOffset, 150, 60);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
I'm not sure what the main purpose of the delay is:
is it to slow things down for debugging purposes
is to go into a series a states (e.g. ball moves up for 2s, then right
2s, etc.),
is to animate/smoothly interpolate between two positions within a given
time ?
Maybe something else completely ?
If you simply want to slow things down, perhaps it might be simpler to adjust the frameRate():
var xOffset = 0;
function setup() {
createCanvas(300, 300);
// update 1 frame every two seconds => 0.5 fps
frameRate(0.5);
}
function draw() {
background(220);
xOffset = xOffset + 1.5;
circle(xOffset, 150, 60);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
Processing still has a delay() function, but p5.js doesn't.
Personally I'm not a fan of blocking behaviour like this and prefer the millis() options even though it's more verbose. That being said, if the program/demo you write is super simple delay() might just be enough.
Even if delay() is missing you could use js setTimeout() with a Promise, but that's getting into more advanced JS as Paul already mentioned:
var xOffset = 0;
function setup() {
createCanvas(300, 300);
// prevent p5's default draw() updates
noLoop();
}
function draw() {
background(220);
xOffset = xOffset + 1.5;
circle(xOffset, 150, 60);
// wait 2s then call draw() manually
delay(2000).then(draw);
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
Now, if you want to create a smooth animation from a start x offset to an end offset in a set amount of seconds you'd need a different approach.
You can find a p5.js example at the of this answer:
var startTime;
var duration = 2000;
var startValue = 0;
var endValue = 300;
var currentValue = startValue;
function setup(){
createCanvas(300, 300);
textAlign(RIGHT);
startTime = millis();
}
function draw(){
background(255);
moveCircle();
drawCircle();
}
function drawCircle() {
circle(currentValue, 150, 60);
}
function moveCircle(){
var progress = (float)(millis()-startTime)/duration;//millis()-startTime = difference in time from start until now
if(progress < 1.0) currentValue = startValue + (endValue * progress);//the current value is the final value scaled/multiplied by the ratio between the current duration of the update and the total duration
}
function mousePressed(){//reset value and time
currentValue = startValue;
startTime = millis();
}
function keyPressed(){//update duration
if(key == '-') if(duration > 0) duration -= 100;
if(key == '=' || key == '+') duration += 100;
console.log("duration: " + duration);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
And if you're comfortable using external libraries you could simply use a tweening library such as gsap:
var x = 0;
function setup(){
createCanvas(300, 300);
// animate "this" global object's x property to 300 in 2 seconds
gsap.to(this, {x: 300, duration: 2});
}
function draw(){
background(255);
circle(x, 150, 60);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/gsap.min.js"></script>
Notice the animation has a bit of easing (default ease out) which could be nice.
In JavaScript, unlike Scratch, there is not a good way to delay synchronous* code. The reason for this is that all the functionality of a webpage is run using a single thread. Which means that while there can be multiple sequences of instructions performing different pieces of functionality, only one of those sequences can execute at a time. Therefore if you did something to delay the execution of JavaScript within the draw() function, it would block all other functionality, making the browser tab unresponsive (and potentially causing the browser to halt your JavaScript altogether).
Instead of pausing a series of JavaScript statements like one would do in Scratch, it is necessary to either use the amount of time that has elapsed as part of a condition that determines whether some code should run (which is what the example George shared in the comments does), or to use the built in setTimeout() function to schedule some code to run some number of milliseconds in the future (but you would not want to call setTimeout() from draw() because it would repeatedly schedule the code every frame).
* note: there are also ways to create delays using asynchronous javascript code, but this is a more advanced topic
It's like the blur is in never ending loop.
This is what I've wrote so far, it's currently always blurring it up again and again, and I can't make it un-blur.
void draw() {
filter(BLUR, blurRate/60);
nextY = mouseY-blurRate;
blurRate= nextY-mouseY;
}
It will help to split the problem into smaller subproblems.
(Kevin Workman's article is a great start)
The code you shared looks like you're trying to do two things at once:
map the mouse Y position to a blur value
apply the blur value to the blur filter
Let's start with mapping the value.
If you know what the minimum / maximum blur value you need you can make your life easier using Processing's map() function. It takes a value(mouseY in your case) and maps it from one range (mouseY's min/max range: 0 to height) to another range (blur's min/max value, let's say 0 to 6)
The mapping range above (from 0, height to 0, 6) is trivial because can simply divide height / 6 and get the mapped value, but map() is pretty useful and worth getting the hang of.
Here's a minimal mapping example:
void setup(){
}
void draw(){
float blurValue = map(mouseY, 0, height, 0, 6);
background(0);
text("blurValue: " + blurValue, 5, height / 2);
}
The second part is applying the blur filter.
The catch here is avoiding this situation:
currently always blurring it up again and again,
This happens because you apply the blur filter in draw() multiple times per second to the content, so each pass blurs further.
It sounds like what you want is to apply the blur filter to the initial state of your image or graphics. The code you posted doesn't show what is it that you're trying to blur.
If using graphics rendered in processing, one option is to simply clear everything (using background()) and redrawing the graphics before applying the filter. With the filter applied in draw and nothing cleared/redrawn the effect is reapplied to the same (pre blurred) content continously.
Let's take this basic example:
void setup(){
}
void draw(){
line(mouseX, mouseY, pmouseX, pmouseY);
}
Notice that even draw we render a single tiny line, because the graphics aren't cleared (using background()) each tiny line accumulates to form a larger path.
Intuitively, adding blur will accumulate the effect:
void setup(){
}
void draw(){
line(mouseX, mouseY, pmouseX, pmouseY);
filter(BLUR, 0.6);
}
Another option, if you'd rather be more efficient and re-render the same graphics in draw(), you can get an image copy of what's been rendered so far which you could render continuously.
Let's say you're drawing something in setup().
You can easily call get()(with no arguments) to get a "snapshot" of what's been drawn so far a PImage.
Once you have that you can simply render it again and again in draw() as it was drawn in setup() using image().
Once image() is called you can then call filter() with be applied to the global Processing graphics, meaning only what's rendered (while the snapshot PImage will remain intact).
Here's an example illustrating the above:
PImage snapshot;
void setup(){
// draw something
background(0);
noFill();
strokeWeight(3);
for(int i = 0 ; i < 100; i++){
stroke(random(32, 128));
float size = random(3, 27);
ellipse(random(width), random(height), size, size);
}
// take a snapshot of the current graphics
snapshot = get();
}
void draw(){
float blurValue = map(mouseY, 0, height, 0, 6);
// render the image snapshot
image(snapshot, 0, 0);
// blur it
filter(BLUR, blurValue);
// display blur value (should be unblurred)
text("blurValue: " + blurValue, 5, height / 2);
}
Your question doesn't specify, but if you are using PImage, then you need to apply blur to a copy of the image to avoid re-applying blur to an already blurred image. Here's a PImage tweaked version of the above:
PImage snapshot;
void setup(){
// draw something
background(0);
noFill();
strokeWeight(3);
for(int i = 0 ; i < 100; i++){
stroke(random(32, 128));
float size = random(3, 27);
ellipse(random(width), random(height), size, size);
}
// take a snapshot of the current graphics
snapshot = get();
}
void draw(){
float blurValue = map(mouseY, 0, height, 0, 6);
// clone the original image via get()
PImage blurredImage = snapshot.get();
// blur the cloned image
blurredImage.filter(BLUR, blurValue);
// display the blurred image
image(blurredImage, 0, 0);
// display blur value (should be unblurred)
text("blurValue: " + blurValue, 5, height / 2);
}
So i just wanted to make a generator that generates a random value every 10 seconds. And instead it generates a random value every frame after 10 seconds of waiting. Please correct me.
var imgs = [];
var a = 0
function randomizea() {
a = int(random(5));
}
function setup() {
createCanvas(1400, 850);
// for (var i=0; i<5; i++) {
// imgs[i] = loadImage("data/img"+i+".png");
// }
}
function draw() {
background(150, 100, 150);
setInterval(randomizea, 1000);
// image(imgs[a], 0, 0);
text(a, 0, 50);
}
You should generally not use setInterval() with P5.js. Instead, rely on the timing mechanisms that P5.js already gives you.
Here's a simple example that would print something to the console every 10 seconds:
function draw(){
if(frameCount % 600 == 0){
console.log("here");
}
}
Since 60 frames fire per second, then 600 frames is 10 seconds. We use the % modulus operator to check that the frameCount variable is a multiple of 600, which means that we're at a multiple of 10 seconds.
You could also use the millis() function and check whether a certain time has elapsed.
Related posts:
How to make a delay in processing project?
How can I draw only every x frames?
Removing element from ArrayList every 500 frames
Timing based events in Processing
How to add +1 to variable every 10 seconds in Processing?
How to create something happen when time = x
making a “poke back” program in processing
Processing: How do i create an object every “x” time
Timer using frameRate and frame counter reliable?
Adding delay in Processing
Please also consult the P5.js reference for more information.
This is a simple program in processing, all it does is draws four circles in the last four frames (My Graphics card's refresh rate is 60Hz, so it draws them once every second)
But sometimes for some reason it is skipping frames, so I don't see all the four circles. Why is that and what can I do to make it not skip frames.
int counter = 1;
void setup(){
fullScreen();
background(0);
fill(255);
}
void draw(){
background(0);
if(counter == 57){
ellipse(383,383,100,100);
}
else if(counter == 58){
ellipse(583,383,100,100);
}
else if(counter == 59){
ellipse(783,383,100,100);
}
else if(counter == 60){
ellipse(983,383,100,100);
counter = 0;
}
counter++;
}
Think about what happens each time the draw() function is called:
First you call background(0) to clear out old frames.
Then you check which frame it is, and possibly draw a circle.
What happens on frame 61? You're going to clear out the old frames (clearing out the circles you've drawn), and then not draw anything. So each circle is shown for 1/60th of a second, which is probably impossible for you to see.
To fix your problem, you need to think about what you want to happen each frame. Consider getting rid of the call to background() so old frames are not cleared out, or possible redrawing old circles every frame. It depends on exactly what you want your sketch to do.
Side note: you don't need to create your own counter variable. Processing provides a frameCount variable that does exactly this. More info can be found in the reference.
I'm attempting to create a very simple "whack-a-mole" type game, designed for students new to p5.js, and Processing in general.
Currently, I've created an array, and a random search within that array that randomly picks a square and makes it brown (a "mole", for now).
How do I make it so that after selecting a square, it stays there for a couple seconds, and then jumps to the next one, using basic p5?
I've managed to implement noLoop(), which can stop the search, but after a certain time I want it to resume.
Here's the code I have so far:
function setup() {
createCanvas(610,610)
}
function draw() {
var grid = []
for (var x = 0; x < 6; x += 1){
grid[x]=0;
for (var y = 0; y < 6; y += 1){
rand=round(random(360))
grid[x][y]=0
if (rand==0){
grid[x]=1
grid[y]=1
noLoop()
}
if (grid[x]==0 || grid[y]==0){
fill(76,153,0)
rect((x*100+10),(y*100+10),90,90)
}
if (grid[x]>0 && grid[y]>0){
fill(102,51,0)
rect((x*100+10),(y*100+10),90,90)
}
}
}
}
Instead of using noLoop(), you could keep looping at 60 frames per second, but then use the millis() function to keep track of the elapsed time.
Here's an example that shows a circle for 1 second whenever the user clicks:
var clickTime;
function mousePressed(){
clickTime = millis();
}
function draw() {
background(0);
if(millis() < clickTime + 1000){
ellipse(width/2, height/2, width/4, height/4);
}
}
Edit: Another approach is to use the % operator along with the frameCount variable in order to do something every X frames. This examples draws a circle in a random position every 60 frames:
function draw() {
if (frameCount % 60 == 0) {
background(0);
ellipse(random(width), random(height), width / 4, height / 4);
}
}