Coding Challenge #136.1: Polar Perlin Noise Loops

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
(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)
Info
Channel: The Coding Train
Views: 142,319
Rating: undefined out of 5
Keywords: daniel shiffman, coding, the coding train, coding challenge, creative coding, code challenge, javascript (programming language), programming challenge, coding tutorial, gif loop, creative coding tutorials, creative coding art, noise loop, perlin noise loop, polar perlin noise, perlin loop, perlin noise, 2d perlin noise, p5js noise, p5js perlin noise
Id: ZI1dmHv3MeM
Channel Id: undefined
Length: 22min 1sec (1321 seconds)
Published: Mon Feb 25 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.