(bell dings) - Hello, and welcome
to a Coding Challenge. Woof! (gasps) If you can't tell, I'm really
excited about this one, so I found this GIF the
other day by Etienne Jacob, Etienne Jacob with my
American pronunciation, and look at it. It might look familiar to you. It looks like that heart curve that I made in a Coding
Challenge previously. Now, I can't say for sure
whether this GIF was made based on my heart curve Coding Challenge, but I can say for sure
that the work of Etienne is amazing, and phenomenal,
and uses a special technique, one that I have recently
rediscovered in a dream. It came to me in a dream, (giggles) and yet it's been on the
Internet at least since 2017, if not before that, so what's going on here that's
so fabulous and exciting is this chaotic scene, this scene of randomness
and smoky heart beauty is actually a perfect GIF loop. How is it that the end
matches the beginning? And this is something I talked about in my previous Coding Challenge, GIF loop, where we looked at, ah-kay, well, we can move something across the window. We can rotate something, and
as long as the last frame matches up with the
first frame it will loop, but if it's all random and
chaotic, how do you do that, and so there is a
technique for doing this. Golan Levin actually also
has an example bit of code which describes this in more detail, which I will show you later in this video, but mostly what I want
to do is highlight to you this blog post from Necessary Disorder, Etienne, from November 15th, 2017, which explains this technique
of creating GIFs like this. Here's another one! How could this even possibly work? And so to begin this discussion, I mean, hopefully we're
going to get to lots, I mean, I could probably
make videos on this topic for the rest of my life, (giggles) but to begin this topic I'm going to return to a
previous Coding Challenge. You may remember me from Coding Challenges such as Coding Challenge
number 36, blobby. It's when I used to wear T-shirts with this other logo on them
during my Coding Challenges, so what is the issue with blobby, so I'm actually, even though I
could just pull up that code, I'm going to (fingers snap)
speed-code blobby again. You're going to see, watch, this is like two Coding Challenges in one, so I'm going to what I'm going
to do is I'm just going to say, let a equal zero, a is less than TW0_PI, and what I'm going to do is I'm going to use my
polar-to-cartesian coordinate ♪ Song ♪ and I'm going to say let x equal r times cosine of that angle. Let y equal r times sine of that angle, and then I'm going to
make up some value of r. r is going to be 100. I'm going to translate to
the center of the window, and then I am going to say beginShape. I am going to say endShape,
and I'm going to set a vertex, vertex at x, y, and I'm going to say, and I spelled TWO_PI with a zero, which is really complaining. I mean, I'm just saying,
stroke 255, and noFill, and there we go. Look, I just wrote the
code for drawing a circle because this is a for loop, I'm going to go through
all these different angles. I'm going to calculate. I'm going to increment the angle. I'm going to keep the radius constant, and I'm going to set all the
vertices x, y of the circle. Now, if r is random, and this is basically
what I did in blobby, if I say random 50 to
100, look what we've got. We've got this kind of like
crazy, flickering thing, and that's almost, that's kind
of interesting unto itself, and I could make this
a little more evident by making the time step, not the time step, the delta
angle, the amount of angle, the amount of vertices I'm drawing, fewer. I could make sure it connects
at the end by saying CLOSE, and I could also, just
for right now, say noLoop so we only get one of them, so each time I run this sketch I'm going to get a new random pattern. Now, here's the thing. This actually looks like
it's a nice, closed loop because it's all random. It doesn't matter if the last vertex doesn't match up with the first vertex, and I, it would be somewhat smart of me to be more thoughtful about
what this delta angle is, like maybe it should be something that divides perfectly into TWO_PI, or the radians equivalent of 360 degrees, but again, I'm not going
to worry about that. What I'm going to do is I'm now going to add Perlin noise to this. Now, if you've never heard
of Perlin noise before, I will refer you to a playlist where I talk about what Perlin
noise is, and how it works, and a whole bunch of other
videos (giggles) related to this, so go and watch those now if you want, or I also link to some
articles about Perlin noise, but I'm going to assume
knowledge of Perlin noise for the purpose of this Coding Challenge, so right now, what I'm going to do is I'm going to say let t equal zero, so I'm going to use t as my offset through the one-dimensional
Perlin noise space. I'm going to change that to
x offset in a little bit, but let's just keep it at t right now. Then I'm going to say r is noise of t times 100, so interestingly enough, let me, we get a different size circle
every time I run the sketch because we're getting a new, randomly seeded set of
Perlin noise values, (sighs) and I'm never moving
through that time space, so each vertex is exactly the same, so what I want to do
now is say, in the loop, t plus equal some amount of delta, so you now you can see look at this, ew, the amount is changing,
but it doesn't match up, so first of all, let me
clean this up a little bit by saying map, let me
use the map function, which I think will make
things a little simpler. Perlin noise always has a
range between zero and one, and let's say I want that range to go between like 100 and 200 now, so we can see, look at that. Now, there's just this
little every time I run it you can see that the
last Perlin noise value doesn't match the first one. This is the problem. This is getting at this idea
of a perfect Perlin noise loop, and let's also have delta t, the way I move through
the Perlin noise space. Siri, what should delta t be? (crickets chirping) (computer boops) Let me change that to this and you could see even if I move t faster, and I get this kind of
smoother blobby-like shape, it always has this artifact:
the last and by the way, if I took off this close,
this will be more evident. Why, right? The last vertex doesn't
match up with the first one. This is the problem, so I have my title of
this video right here, Perlin Noise Loops. Perlin noise, if we're talking about
one-dimensional Perlin noise, Perlin noise values in
a one-dimensional space, with this being the t-axis, the time axis, although really I should
call this x offset, 'cause it's like the x offset. This is maybe a graph of those values, and if I'm arbitrarily going from zero to some fixed endpoint as I get to the end of that circle, whatever value I get here,
which may be, let's say, if this is between like zero and one, maybe this is 0.3, and this is like 0.621, right? They don't match up. If I were to take this and
twist it around into a circle, they don't match up. There is another way to look at a space of Perlin noise values. This is a way of looking
at it in one dimension. Let's now look at it in two dimensions, so instead of having a sort
of one-dimensional graph of Perlin noise values, I present to you a grid of Perlin noise values. The idea is each one of
these represents some value between zero and one. Now, in this two-dimensional space, each one of these values represents, uh, is also a number between zero and one, so I might have like 0.2
here, 0.3 here, and 0.31 here, and 0.26 here, and 0.19 here, right? Every single space has a value. Now, here, in one dimension, any number in one-dimensional space is quite similar to its neighbors, and it only has two neighbors: a neighbor on the left and
a neighbor on the right, or a neighbor after and a neighbor before. Here, each value has how many neighbors? One, two, three, four,
five, six, seven, eight. It has neighbors above,
and neighbors below, and neighbors to the right,
and neighbors diagonally down, so the idea here is that what if I could walk around through a two-dimensional
Perlin noise to get space to get random values and always
end up back where I started? And why not just walk in a circular path? I mean, that's kind of what
I'm programming anyway, so why not just do that? What if I were to start here and get this Perlin noise
value, then this one, then this one, then
this one, then this one, then this one, then this one,
then this one, then this one, then this one, then
this one, then this one, then this one? I would have one, two,
three, four, five, six, seven, eight, nine, 10, 11, 12, 13 random numbers, and the last one is going to
match up with the first one if I keep going, so I could get those random
numbers over and over again, and if the amount of
numbers there is so vast, it's going to appear like it is a continuous
sequence of total randomness, smoothed with Perlin noise, so this is the theory, so let's now go and apply this theory to this particular blobby shape, so before I get back to the blobby code, what I have here is a processing sketch that is visualizing Perlin noise
in a two-dimensional space, so this a pretty sort of
like classic visualization of 2-D Perlin noise as
this cloudy like texture, and this is literally
(giggles) exactly this, where each number, each random Perlin noise value
in the two-dimensional space, is represented as a pixel with a brightness value
between zero and 255, and when you look at that you
get this cloud-like pattern because the color seamlessly,
smoothly moves between white, to black, to gray, to
black, to gray, to white, so the idea here is what
is what I want to do is walk around this space and
pull those numeric values, but map them to something
else besides a pixel value, and walking around in a circle is a nice way to create a loop, but you don't necessarily have to have that be in the circle. All right, so let's go
back to the blobby code. Now, there's a (giggles) a
bit confusing about this, because in addition to the walking around
the Perlin noise space in a circular path, I also happen to be walking
around the 2-D canvas in circular path to draw
this circular shape, so I'm kind of using the same idea, but with two different points of view, and hopefully that is something
that makes sense to you. Hmm, okay, so what I
want to change this is I no longer want to have t. What I want to have is x offset and a y offset, and I want to get the Perlin
noise at x offset, y offset, so this is now what I had before if the, if the x offset and the y offset, right, basically, if what I'm doing is I'm asking for what is the
Perlin noise value at this spot it's going to give me some random value, and then it's going to make
that the radius of the circle, the blob shape, as it
goes all the way around, so I want to start moving, but I actually don't want to start here. I want to start over here, so
I have to deal with the fact that I need to find this point if zero, zero's in the top-left, 'cause I can't have negative values in the Perlin noise space, so this is a little bit
of a tricky piece of this, but I want to use that same polar two-cartesian-coordinate formula, or I want to say x offset
equals cosine of that angle, y offset equals sine of that angle. Now, look at this. I've kind of got something,
but it's weirdly symmetrical, and the reason is this exactly
what I just alluded to. These x offset and y offset values are going between negative one and one, and so in fact I'm trying to
look at Perlin noise values over here, right, and
these, this doesn't exist. The Perlin noise space is all positive, so there's actually a very
simple solution to this, which is just to add one, and let me add the CLOSE back in, and let's run this a bunch of times, and we can see, there we go, we have this nice random blobby shape where the end matches the beginning. Now, I want to do, let's
do some more stuff here. All right, so first of all, what happened to that like incrementer? What happened to t plus equal 0.01? Now I have x offset and y offset. Why aren't I saying x
offset plus equal one, 0.1 y offset plus equal one, one, well, actually, the incrementer is this. It is the 0.1 here. It's cosine of the angle, and in truth (giggles) I could (gasps) have a separate variable from the one that's
incrementing in the loop, 'cause I could move through, but I need to go all the way to TWO_PI, so that I don't want to do. I think a way for me to vary
this in a more flexible way is actually to use the map function, so if I map cosine of a, which goes between negative one and one, and then map that to a
range between zero and two, we have, and this is sine, we have exactly what I had
before, and I can keep, I can keep rewriting the sketch, and I'm getting a new
version of the shape, but interestingly enough, what happens? This is really now something
that I should make a parameter, so for example, what if I were to say let, I'm going to make this a global variable, let, I'm going to call
this noiseMax equal two, and I'm going to put this here, and watch what happens
if I make this five, versus 10, versus 120, versus 0.1, and look at this, 0.3, 0.5, look at this. This is really kind of interesting. With just a little bit of noise, I have what appears almost
like a perfect circle, but it kind of looks like
a human being like me with faults, I have lots of faults, drew that circle. It's got some slight so Perlin noise can actually be used as a nice way, with a little subtle Perlin noise, of making some perfect shape, like a letterform, or
a circle, or a square, have a little bit of wiggle to it that makes it seem more hand-drawn, so that's a nice thing to see. The other thing we could see
here very quickly is like, it would make sense for
me to create a slider. I'm going to say, and this I'm using the p5
dom library to do this, which is a really quick way. I'm going to create a
slider which has a range between like 0.1 and 10, and I'm going to start it at, actually let's make it
between zero and 10, and I'm going to start it at zero, so I have the slider here now, and then I want noiseMax to equal, noiseMax to equal
slider.value, so watch this. Okay, that didn't work. (giggles) Oh, I have noLoop in here. No wonder. Take out the noLoop,
and now let me slide it. Oh, we need to make that, so first of all I need to
give myself smaller time steps when moving the slider, so let's do this. Oh, look at that. Look how it kind of like unfurls, because it's the same noise space; I'm just stretching or shrinking it. That is a really imagine now if I oscillated
that like along a sine wave, so another thing that I
could demonstrate to you is interesting, like a
always starts at zero, 'cause I'm going from zero to TWO_PI, but if I am walking around
the path of a circle, there's no reason why I
couldn't start over here and then go around, or start
over here and then go around, and why not vary that? That would be like the phase. You go back to my Fourier,
all of this stuff, it's so crazily interrelated it's amazing, but if you go back to my
Fourier transform videos, where we created these orbiting epicycles, we had this concept of phase, which is where does that orbit start, so let me show you another thing here. Okay, what I'm going to do is show you so let me make a variable called phase, and we have that be zero. I'm going to have cosine
of angle plus phase, sine of angle plus phase, what do you think's going to
happen if I increment phase? Well, it looks like the shape is rotating. I mean, it is rotating,
or it's not rotating. I mean, visually it's rotating, but I'm actually just starting at a different point in the noise space. Interestingly enough, like, and if I make that much smaller,
you'll actually see that, like smaller than the
amount of vertices I have, you start to see a wiggle
between them, so interest, like I could make this 0.2, and that's going to be even more apparent. Like, look at that crazy weird wiggle as those vertices adjust their spot, and then I want to show you
something even crazier, I think, like let me put it back. Let me sync it so this is
like a nice perfect rotation. What if I only apply the phase to the x offset or the y
offset, like different phases? That is really, oh, it's kind of too fast, so let me do like this. Like, this is really weird. You can sort of see it's almost like there's something
crawling around the edge. (screams in mock horror) There's so much weirdness stuff going on, so anyway you see the sort of
like exciting possibilities of thinking about Perlin noise values as one-dimensional, values that might pull over time in a sort of one-dimensional fashion, but actually pull them
from the path of a circle in the two-dimensional Perlin noise space. Now, what I happen to be doing in this is taking a very literal
approach. (giggles) I'm taking those Perlin noise path values walking around a circle, and applying them to like the distance from the center of a circle over, as I'm drawing it, so it's very like, it's a very literal sort
of like visualization of Perlin noise values in a circle to the edge points of a circle, but if you start to think of other ways you could apply those values, the creative possibilities explode, and so in other words, if
this is what I started with, I have Perlin noise at the beginning. Sorry, I have Perlin noise
values in one-dimensional space, but they don't loop, why not take those looping values here, along the path of a circle, and then unfurl them back into the sort of
one-dimensional line, and then use those to apply to any value in any visualization to make a perfect GIF loop. That's the idea, so I'm going
to just put that out there. I'm putting this out into the universe. I mean, I didn't put
it out in the universe. Lots of other people, Etienne, and Golan, and many others I'm sure
I'm forgetting to reference, have done this for years,
so give that a try. In the next video I'm going to
come back and actually do that, so I'm going to see if
I can take this idea and just apply it to something. Probably won't be that
visually interesting, but this will hopefully
give you lots of ideas of what you might make. Let's add one more thing to this. I think I can. This video's not too long so far. All right, let's add one
more thing, so first of all let me take out this idea
of phase for a second. Just going to comment that out
and put it back to what it was, which is just this, so every time I run it I get
a new Perlin noise space, and incidentally, the only reason why I'm getting
a new Perlin noise space is because p5, behind the scenes, will seed Perlin noise with
a random seed each time, but I could actually control it. If I were to say noiseSeed, and pick some arbitrary seed value, and random number seeds is
maybe a topic for another video. Every time I run this I'm going to get exactly
the same shape each time, so anyway, just pointing that out, but there is something else. There is another way I could animate this, and it has to do with
three-dimensional Perlin noise, and Perlin noise can exist
in any n-dimensional space. In p5 and in processing, I think the functions that give it to you just support one, two,
and three dimensions, but let's talk about how you might use three dimensions here, so for example, if this is my
visualization of Perlin noise in two-dimensional
space, that cloudy image, well, I could make sort of
like a cloudy set of cubes in three-dimensional space, but another way of thinking about it is have that third dimension
be slices of an animation, so I could show you the Perlin noise space over time while incrementing a z-value, a z offset, and show you Perlin noise
for a z offset equals zero, then z offset equals
0.1, then 0.2, then 0.3, and so that actually, all
of those will have numbers. Each one of these numbers is now has all of its neighbors to up, and down, and left, and right, and
forward, and backward, are similar random values, so this is actually a really
easy thing for me to add. I just need one more global
variable called z offset, and this needs to be global 'cause I'm not resetting it
back every time through draw. Each time through draw
I'm incrementing it, and I can just add zoff right there to the Perlin noise function, and then I can say zoff plus
equal some amount, like 0.1, and you can see we get this wiggle. I can make it 0.01, and I'm going to move through
the Perlin noise space much more slowly, and once again we could see, like, there's all sorts of
things I could do here, like this could be 0.3,
and this could be 0.1. There's so many parameters
that you can explore here. I think we've made, actually,
a super-interesting shape for like a crazy animated
game version of Asteroids, like you can imagine having Perlin noise jiggling, oscillating, looping, noisy, polar Asteroids. That's a thing you should make, so anyway, so I hope you find
some variations for this, and I look forward to
seeing what you make, and stay tuned for the next video. (bell dings) (playful music) (bell dings)