Converting custom javascript noise/offset functions to p5's native functions - javascript

I took a sketch from Processing's Java version and adapted it to p5.js that creates a field of nice wavy lines.
But I am learning p5.js and looking to simplify the code further by getting the noise and the offset values through p5's in-built functions like noise(), lerp() etc.
I am trying a lot to get my head over achieving the 2 functions,
periodicFunction() and offset() and the value of t somehow with p5's own helper functions but no luck yet.
I watched Daniel Shiffman's amazing video on Polar Perlin Noise Loops several times but still can't progress because instead of linking the noise values to a circular shape (like in his video), I want to adapt it to my sketch here.
Any help would be greatly appreciated.
Code:
function setup()
{
createCanvas(500,500);
}
let numFrames = 80;
function periodicFunction(p)
{
return 1.0*sin(TWO_PI*p);
}
function offset( x, y)
{
return 0.005*(x - 2 * y);
}
function draw()
{
background(255);
let t = 1.0*frameCount/numFrames;
let m = 50;
stroke(0);
for(let i=0;i<m;i++)
{
for(let j=0;j<m;j++)
{
let x = map(i,0,m-1,0,width);
let y = map(j,0,m-1,0,height);
push();
translate(x,y);
let rot = periodicFunction(t-offset(x,y));
rotate(rot);
line(-5,0,5,0);
pop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>

The code cannot be simplified any further with P5.js built-in API functions. From my understanding, the P5.js API is a subset of the full Processing API with a few changes due to the differences between JavaScript and Java.
The Processing API already includes lerp(), noise(), and constrain(). So there is no reason the original Processing script could not use these functions.
Furthermore, your code doesn't use any noise, lerping, or constraining. Let me explain why the functions cannot be simplified:
function periodicFunction(p)
{
return 1.0*sin(TWO_PI*p);
}
Function periodicFunction() simply scales the sin() function's amplitude by 1.0 and frequency by 1/TWO_PI. You can replace periodicFunction() with just sin(). The effect will be basically the same, although more "stretched" or "compressed."
function offset( x, y)
{
return 0.005*(x - 2 * y);
}
The function offset() simply calculates an "offset" value based on the x and y coordinates. This causes the "diagonal" effect because different parts of the sine wave are being used based on the x,y values. If you replace offset() with a constant like 0, all the "waves" will appear to line up.
let t = 1.0*frameCount/numFrames;
Finally, the value of t is calculated to give a value that slowly increases between frames. Using frameCount may help keep the animation more smooth? You could modify this to increase by a constant like t += 0.1; (if t is initialized outside this function).
Note: I think the pattern 1.0* ... is used several times to coerce integer values into floating point values. Otherwise frameCount/numFrames may result in integer values. This doesn't seem to be necessary in JavaScript (3/2 is 1.5 in JS).
I have made all the simplifications described above in the snippet below. As you can see, the basic animation is similar; just less interesting:
function setup()
{
createCanvas(500,500);
}
function periodicFunction(p)
{
return sin(p); // Simplified to simple sin() function.
}
function offset( x, y)
{
return 0; // Simplified to return a constant value.
}
let t = 0; // Need to declare/initialize outside function.
function draw()
{
background(255);
t += 0.1; // Simplified to increment by constant value;
let m = 50;
stroke(0);
for(let i=0;i<m;i++)
{
for(let j=0;j<m;j++)
{
let x = map(i,0,m-1,0,width);
let y = map(j,0,m-1,0,height);
push();
translate(x,y);
let rot = periodicFunction(t-offset(x,y));
rotate(rot);
line(-5,0,5,0);
pop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
update: Here is an example of how to incorporate noise into the sketch. Variable t is incremented randomly, but smoothly using noise so the animation seems to randomly speed up and slow down:
function setup()
{
createCanvas(500,500);
}
let numFrames = 80;
function periodicFunction(p)
{
return 1.0*sin(TWO_PI*p);
}
function offset( x, y)
{
return 0.005*(x - 2 * y);
}
let t = 0
function draw()
{
background(255);
t += noise(frameCount/100)/40; // Increment randomly, but smoothly using noise.
let m = 50;
stroke(0);
for(let i=0;i<m;i++)
{
for(let j=0;j<m;j++)
{
let x = map(i,0,m-1,0,width);
let y = map(j,0,m-1,0,height);
push();
translate(x,y);
let rot = periodicFunction(t-offset(x,y));
rotate(rot);
line(-5,0,5,0);
pop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>

Related

I have a problem with a code rendering a recursive tree with iteration in draw function in Javascript p5.js

I have the below code rendering a set of trees, The problem with this code is it includes noLoop. if noLoop is removed, the trees keep pulsing and generating new trees. I need to move this tree function to another long code, which is actually a game with a lot of objects in it. The noLoop in this function stop everything else in my draw function. and I wasn't able to restructure the code to make part of it in the setup.
The code below :
function setup() {
createCanvas(windowWidth, windowHeight);
background(200);
}
function draw() {
noLoop(); // NoLoop must be in draw in order for the code tho work
branchIteration(width / 2, height / 4);
}
function branch(len, firstTime = false, x, y) {
translate(x, y);
if (firstTime) {
translate(width / 2, height / 2);
firstTime = true;
}
angleMode(DEGREES);
push();
if (len > 10) {
strokeWeight(map(len, 10, 100, 1, 15));
stroke(70, 40, 20);
line(0, 0, 0, -len);
translate(0, -len);
rotate(random(-20, -30));
console.log(random(-20, -30));
branch(len * random(0.7, 0.9), 0, 0 - len);
rotate(random(50, 60));
branch(len * random(0.7, 0.9), 0, 0 - len);
} else {
var r = 80 + random(-20, 20);
var g = 120 + random(-20, 20);
var b = 40 + random(-20, 20);
fill(r, g, b, 150);
noStroke();
ellipse(0, 0, 10);
beginShape();
for (var i = 135; i > 40; i--) {
var rad = 15;
var x = rad * cos(i);
var y = rad * sin(-i) + 20;
vertex(x, y);
}
endShape(CLOSE);
}
pop();
}
function branchIteration(xPos, yPos) {
for (var j = 0; j < 10; j++) {
push();
var xPosOffset = -2000 + j * 350;
translate(xPos + xPosOffset, yPos);
branch(60, true);
pop();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
Link to try the code https://editor.p5js.org/josefalk/sketches/taCAyFI4X
I want noLoop removed from draw.
Others advised me to place the function in setup. I cannot load this function in the setup, Because I'm doing a transformation in the destination code draw function and I want trees to move with other objects. as below:
Draw ();
push(); translate(-cameraPosX * 0.2, 0);
function mountain
function clouds
some other functions
tree code function here // which I cannot add
pop(); // transform end status.
I want noLoop removed
I don't want to use conditional statements. e.g if (!branchesDrawn) {branchIteration(width / 2, height / 4); branchesDrawn = true; }
because it disappears quickly because other items render on top of it.
I tried also importing values from the setup function, but It did not work.
I need:
re-structure the code without noLoop and the program loading the same set of tree every frame. When you re-load the page new trees will be generated.
In the code, you see a lone logging random value to the console : console.log (random (-20, -30)) . The console is logging a lot of random value lines then it stop. even it has noLoop in it. But if you place the same random console logging in setup, You will only get one line random value. why the random value generating few more number in draw but it generate only one number in setup? I'm missing some knowledge here.
Trees are random, so every time you generate one it will look different.
One option is to include a randomSeed(42) at the beginning of your draw function, so everytime trees are generated they will look the same. (you can put any number, 42 is just an example)
function draw() {
randomSeed(42);
branchIteration(width / 2, height / 4);
}
However trees are expensive to generate (specially if your recursion goes very deep), so I'd instead generate them once, then use saveCanvas() to save the current canvas as an image and then use that image in the draw function.
If redrawing your background at every frame drops your fps there are other techniques to only update a desired part of the image and leave the rest of the background static.
Take a look at the library https://osteele.github.io/p5.libs/p5.layers/ that includes a lot of useful tools for drawing at different layers, so you can leave some layers static and only update other layers, making your program performance increase.
Finally, I'd recommend you start using classes, so your code gets more organized. Make a class Tree and put it in a different file, so your main file keeps as simple and clean as possible. That's important as you will start adding more and more things, and keeping things encapsulated in classes is a very good idea.

Why does this script lag delay in Javascript?

I've made a script where there are supposed to be little balls that attract eachother in real time. The problem it is EXTREMELY slow. I used animation frame, so I think it should be updating every frame, but it isn't. Here is the code:
$(function() {
var mouseDown
var c = document.getElementById('myCanvas');
var ctx = c.getContext("2d");
var objects = []
c.addEventListener("mousedown", onMouseDown);
c.addEventListener("mouseup", onMouseUp);
function createSquare(x, y, size, direction, xVel, yVel) {
this.x = x;
this.y = y;
this.size = size;
this.drawStylus = drawStylus;
};
function drawStylus() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
};
function getDistance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
function draw() {
ctx.clearRect(0, 0, 5000, 5000);
for (i = 0; i < objects.length; i++) {
var x = objects[i][0]
var y = objects[i][1]
var size = objects[i][2]
var dir = Math.random() * Math.PI * 2
var force = 0
var xVel = 0
var yVel = 0
for (n = 0; n < objects.length; n++) {
if (n != i) {
force = 100 * objects[n][2] / getDistance(x, y, objects[n][0], objects[n][1])
angle = Math.atan2(y - objects[n][1], x - objects[n][0])
xVel += force * -Math.cos(angle)
yVel += force * -Math.sin(angle)
window.requestAnimationFrame(draw)
};
};
ctx.beginPath();
ctx.arc(x + xVel, y + yVel, size, 0, 2 * Math.PI);
ctx.fill();
};
};
function onMouseDown() {
mouseDown = true
x = event.clientX
y = event.clientY
size = 100
animation = function() {
size = size + 20
var cursorSquare = new createSquare(x, y, size);
cursorSquare.drawStylus();
anim = window.requestAnimationFrame(animation)
};
window.requestAnimationFrame(animation)
};
function onMouseUp() {
if (mouseDown) {
window.cancelAnimationFrame(anim)
var newSquare = new createSquare(x, y, size);
objects.push([x, y, size])
mouseDown = false
};
};
function loop() {
draw();
window.requestAnimationFrame(loop);
};
function init() {
loop();
};
init()
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<canvas id='myCanvas' width="5000" height="5000" style="border:1px solid #000000;"></canvas>
You are calling requestAnimationFrame for each object, this is the wrong way to use requestAnimationFrame (RAF).
You should only call it once per frame not once per object.
function mainLoop(time){ // main loop RAF will add the time in milliseconds to the arguments.
ctx.clearRect(0,0,canvas.width,canvas.height); // clear
draw(); // call the draw loop
requestAnimationFrame(loop); // request next frame
}
requestAnimationFrame(loop); // request next frame
Using the draw functions like ctx.arc is very slow. You will get much better performance if you render images instead ctx.drawImage. You can create a canvas, draw the arc on that canvas and then draw that canvas with ctx.drawImage(canvasImage,... to get a much faster update.
The other answer advised you to use forEach, don't use forEach or any of the array functions that involve callbacks as they are MUCH slower than using standard loops (for, while, do)
UPDATE
As things change rapidly in the browser world I have tested the use of forEach in this case and in this case the news is not good. forEach still adds a significant additional overhead on each iteration when compared to for, while , and do while
The important thing to note (and why I striked out the last paragraph) is that the overhead is per iteration, if you have a small number of iterations and a large amount of code per iteration then the overhead is insignificant and not worth the bother, personal coding style should make the choice of what style to use in those cases.
If on the other hand you have a large number of iterations and a small amount of processing per iteration then using forEach will significantly impact the performance of the loop.
This holds true for Chrome, Edge, and Firefox with all showing the standard iteration (for loops) with inline code (not calling a function) to be the quickest, next and 10% slower than standard iteration is standard iteration with a function call (like forEach), and then forEach with an additional overhead per iteration of over 2X. (each test used a 15-20 to 1 code balance, that is the code inside the iteration is 15-20 times longer than the minimum code required to iterate. So one line for the for, forEach loop and 10-15 lines of code inside the loop.)
If you are handling an array of a few thousand to tens of thousands the difference is not worth bothering with, If you are handling 100s of thousands to millions plus you should avoid forEach.
Note: I did not test forEach on typed arrays as that is not applicable in this case.
Tested on
Chrome Version 50.0.2661.37 beta-m
Firefox 46.0b2
Edge 25.10586
A couple of things that might help.
Take objects.length out of the for loop and assign it to a var before you start the loop. Currently your counting the length of objects on every interaction of your loop.
Better yet use objects.forEach to iterate over the arrays.
Lastly why does draw() call itself at the bottom of the two for loops? This is going to fill up the event loop very quickly and suspect the main reason for the slow down.

JS randomize lineTo

I need to randomize the coordinates of shapes.
I know I need to somehow introduce the Math.floor(Math.Random * num); line in there, but nothing I do seems to work.
This is the block with the filled in coordinates I am trying to randomize.
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.lineWidth="5";
ctx.strokeStyle="black";
ctx.moveTo;
ctx.lineTo(100,20);
ctx.lineTo(30,400);
ctx.lineTo(300,40);
ctx.lineTo(10,20);
ctx.stroke();
I've searched and searched and found nothing directly on this for some reason.
Sorry this is such a basic question too, I'm really new to this and still learning the basics.
Thank you in advance
Here is a fiddle showing the things I explain below.
Check this page for syntax regarding the Canvas.
If you want to be able to quickly and easily designate random coordinates, you can wrap it up in a function.
function randCoord(factor){
return Math.random() * factor;
}
and then use it like this:
// all of these will go to different points
ctx.moveTo(randCoord(300),randCoord(100));
ctx.lineTo(randCoord(300),randCoord(100));
ctx.lineTo(randCoord(300),randCoord(100));
ctx.lineTo(randCoord(300),randCoord(100));
You could set a default scale:
function randCoord(factor){
if (factor == undefined){
factor = 100;
}
return Math.random() * factor;
}
Which would allow you to simply write the function name.
ctx.lineTo(randCoord(),randCoord());
You can also make another function that just adds a random additional point
function addRandomPoint(xFactor, yFactor) {
ctx.lineTo( randCoord(xFactor), randCoord(yFactor) );
}
// these will all add new points
addRandomPoint();
addRandomPoint();
addRandomPoint(200, 300);
addRandomPoint(-100, 25);
And then wrap it up in loop to make many points
// this will add 10 new points
for (var i = 0; i < 10; i++) {
addRandomPoint();
}
So you could do this:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.lineWidth="5";
ctx.strokeStyle="black";
ctx.moveTo(10, 10);
for (var i = 0; i < 10; i++) {
addRandomPoint();
}
ctx.stroke();

This is an infinite loop, but I cannot for the life of me figure out why

So pretty much I'm making a little web app to get better with using the canvas, but I'm stuck. I would like a rotating n-sided polygon (the drawing of lines already works). The game loop loops through a grid array (each point on the grid holds a subclass of a Point() object), and calls the tick() method on each. Everything works fine until it hits a ShapePoint() object (middle mouse to place on canvas). The ShapePoint's tick() method is somehow an infinite loop. If you put a console.log("hi") inside it, it will give you about 2000 "hi" messages, so it's working (in theory). The funny bit is, even though it is looping through stoke()'es, nothing is happening!
//################################################################
// THIS IS THE PROBLEM CLASS.
// So pretty much, when the game loop calls the tick() funciton
// of ANY ShapePoint object, everything hangs. The game is still
// looping through the ENTIRE tick() function (put console.log()
// functions in and you'll see what I mean) continually, but the
// effects it is supposed to display aren't shown.
//
//################################################################
function ShapePoint(x, y, sides) {
//position variable
this.positionOnCanvas = [x, y];
//number of sides
this.N = sides;
//current step
this.step = 0;
//the array to store all the angle data
this.thetas = new Array(this.N);
//the array to store all the vertex data
this.vertList = new Array(this.N);
//function to increase all the angels by an even amount
this.stepPoints = function(s) {
//for every side
for (i=0; i<this.N; i++) {
//multiply the current 'i' value by ((360/number of sides) + current step). This serves to create points at even intervals all the way around a circle, and have it increase by s every loop
this.thetas[i] = i*((360/this.N) + s);
//get the x value with 40*cos(angle for this point). Same for y, only with sin. Round both to 2 decimal places
this.vertList[i] = [Math.round((40*(Math.cos(this.thetas[i])))*100)/100, Math.round((40*(Math.sin(this.thetas[i])))*100)/100];
//if the current angle is between 90 and 180...
if (this.thetas[i]>=90 && this.thetas[i]<=180) {
//invert the x value
this.vertList[i][0] *= -1;
//else if the angle is between 180 and 270...
} else if (this.thetas[i]>=180 && this.thetas[i]<=270) {
//invert both the x and the y values
this.vertList[i][0] *= -1;
this.vertList[i][1] *= -1;
//else if the angle is between 270 and 360...
} else if (this.thetas[i]>=270 && this.thetas[i]<=360) {
//invert the y value
this.vertList[i][1] *= -1;
}
//nothing needed for 0-90 because both are positive
}
}
this.tick = function() { //<<<<<<<<THIS IS THE PROBLEM FUNCTION!
//setup all the points forward
this.stepPoints(this.step);
//for every side in this polyogn...
for (i=0; i<this.N; i++) {
//shorten the location of the positions
var posX = this.vertList[i][0] + this.positionOnCanvas[0];
var posY = this.vertList[i][1] + this.positionOnCanvas[1];
//begin drawing
ctx.beginPath();
//move to the x and y location of the current point
ctx.moveTo(posX, posY);
//if point is not the last in the array...
if (i < this.N-1) {
//draw a line to the next point in the array
ctx.lineTo(this.vertList[i+1][0] + this.positionOnCanvas[0], this.vertList[i+1][1] + this.positionOnCanvas[1]);
//else...
} else {
//draw a line to the first point in the array
ctx.lineTo(this.vertList[0][0] + this.positionOnCanvas[0], this.vertList[0][1] + this.positionOnCanvas[1]);
}
//draw a line
ctx.strokeStyle = "#000000";
ctx.lineWidth = 0.5;
//end
ctx.stroke();
//draw the vertex
ctx.fillStyle = "orange";
ctx.fillRect(posX-2, posY-2, 4, 4);
}
//draw the origin of the polygon
ctx.fillStyle = "lightPurple";
ctx.fillRect(this.positionOnCanvas[0]-2, this.positionOnCanvas[1]-2, 4, 4);
//if the step is greater than 360, set it to 0
this.step = this.step % 36; //(thanks Neikos!)
}
}
ShapePoint.prototype = new Point();
So I've spent hours tweaking different things, and I cannot for the life of me see what the problem is! If anybody can figure it out, it would be fantastic. If you need more context as to how exactly this is implemented, I've created a JSFiddle for you. Thanks in advance, this place is always so helpfull!
EDIT :: I do realize my code is a bit clunky, but I typing out what everything does really helps me learn for the next time
user2310289 is correct in his/her comment above: you're using a single global i variable in both stepPoints and tick, so these methods are interfering with each other.
There are some languages where a variable used in a method is implicitly local unless declared otherwise, but JavaScript is not one of those languages. In JavaScript you need to use the var keyword to declare your local variables, otherwise they are implicitly global.

Simulating movement similar to dust particles

I've tried a setInterval loop with css and animate. Both ways of movement consists of tiny movement from oldpos1 -> newpos1 with no random curve movement, easing however occured with jQuery animate but only between randomly generated 1-3 pixels, which is not what I want
.
Does the problem lies in setInterval's clock, where only linear time units flow?
Where should I start, to make below images exist in jQuery?
What I would like to do:
Dodge behaviour:
A, B - particle
AB1 - common dodge area, only certain amount
2 Movement:
Av, Bv - random circular movement
Aacc, Bacc - where the tiny random acceleration occurs (on image marked as more condenced dashed lines)
I would not rely on jQuery's animate for this as your case is rather special ... instead, use the "game loop pattern": Have a game object which keeps a collection of particles, which are moved (and collided ...) and then drawn in regular intervals.
Here's a basic structure:
function Particle(x, y) {
this.x = x;
this.y = y;
this.speed = 0; // in pixels per second
this.direction = 0; // in radians per second
}
Particle.prototype.move = function(d_time) {
this.x += Math.cos(this.direction) * this.speed;
this.y += Math.sin(this.direction) * this.speed;
}
Particle.prototype.draw = function() {
// either set the position of a DOM object belonging to this particle
// or draw to a canvas
}
function Game() {
this.particles = Array();
this.MS_PER_FRAME = 20; // in milliseconds
this.D_TIME = 1000.0 / this.MS_PER_FRAME;
}
Game.prototype.tick = function() {
$.each(this.particles, function(_, particle) {
particle.move(this.D_TIME);
particle.draw();
})
}
Game.prototype.go = function() {
setInterval(this.tick, this.MS_PER_FRAME)
})
Then you can manipulate speed and direction of particles as you like, maybe by introducing additional members d_speed (acceleration) and d_direction or so.

Categories

Resources