(horn toots)
- Hello, welcome to a coding challenge
entitled 4D Open Simplex Noise Loop.
That's got to be a click bait title
if I ever heard one, right?
(laughs)
Anyway, let me thank somebody.
The artist Etienne Jacob, who I've referred to
in like the last 307 coding challenge videos that I've made,
because I keep doing this topic over and over again,
has been really an inspiration for these videos.
Makes these amazing noise loop GIFs,
and I've talked a little bit about some techniques
for doing that using classic Perlin noise,
the noise function in processing,
which you can also refer to as fractal noise.
Recently, through feedback and research,
been turned on to this idea of Simplex Noise
and Open Simplex Noise and I made an entire video
all about that and the differences and a little bit
about the history there.
I'll refer you to that video if you want to find out more.
In this particular video, all I'm going to do
is I now have the processing 3D noise example,
which you'll see nothing is three-dimensional here.
There's really a two-dimensional space
of noise and the third dimension
is what's creating the animation frame.
You can think of that third dimension almost as time.
I'm seeing frame by frame by frame.
What I want to do with this is take this and make it loop.
I want to have this noisy scene,
and this is using Open Simplex Noise,
which has a different quality and character to it.
It has less what are known as directional artifacts
that I referred to in the previous video
as like this herky jerky feeling of what the noise algorithm
can sometimes do if you also stop and turn around.
The smoothness of this is quite pleasant
and has a visual quality that's,
for a lot of scenarios, better.
There's more to say about that,
you can go watch the other video.
What I want to do is make this run just over a few seconds
and then render it as a GIFs that loops seamlessly.
I took a quick break there just
to render out that processing sketch.
I rendered out a few seconds, and as you'll see,
I rendered it to a GIF and every few seconds,
you see this jarring thing happen
where it goes back to the beginning.
The last frame of this noisy scene
doesn't match the first frame.
This is something that I talked about
in previous coding challenge videos,
how to get a sequence of values,
a one-dimensional array of random values
where the last value matches up with the first.
You close that loop.
The way that I did that was, I want one dimension of values,
let me walk around a circle,
a circular path in a 2D noise space.
Now what we're doing is
I want two-dimensional looping values,
so I need to basically walk around to space of a torus.
I need all of these values to move around and come on back.
First, what I want to do is...
Let me just be clear, this is
the processing noise 3D example and the only changed
is I've added this OpenSimplex Noise code from Kurt Spencer.
I will link to where that code and some background
about this open source implementation where it comes from
in the video's description.
Instead of calling Processing's noise function,
I'm calling noise.eval from Kurt Spencer's OpenSimplex Noise
and that gives me a double,
so I have to convert that into a float.
It also gives me a range of values between -1 and 1,
which is different than the values between 0 and 1.
What I would like to do is make this
a bit more visually obvious what's going on,
so I'm going to change this.
I'm going to threshold this
to render the color either black or white.
One way I can do that
is with a nice little ternary expression.
I can say brightness equals,
like is noise greater than zero?
If the noise value that comes out is greater than zero,
then I want to see 255,
otherwise I want to see 0.
If I do that, you'll see we get this.
I can play with the increment values,
like maybe let me make the increment a little less
but make it go through the zSpace faster, I don't know.
So, now we can see.
So this, this would be...
I should've rendered this to a GIF,
so you could see it not looping,
but this is what I want to have loop.
Also, look at the beauty of this particular noise algorithm.
It's very smooth, it doesn't feel like it's...
It doesn't have that directional art effect.
It doesn't feel like it's slowing down to a stop
and then going backwards, it just keeps going
with this kind of beautiful organic randomness.
Now that I have this, let's turn this into a GIF loop.
All of these videos are now kind of, this series,
everything's depending on each other.
I did have a previous coding challenge
where I made processing code that just renders out
the frames for a GIF loop and at the demonstration
is just a rotating square.
What I want to do is, I'm going to use that as my basis.
Let me grab all the code before set up from here,
which is all of this.
I'm going to put that into my GIF loop code.
Then, I wanted to make the new OpenSimplexNoise object,
and I'm going to put that in here.
Now, it's complaining to me, it doesn't know
what OpenSimplexNoise is, so I do need to make a new tab.
I'm going to call it OpenSimplexNoise.java.
And... whoops.
It needs to be .java because this particular
OpenSimplexNoise class is using some features
of the Java programming language
that don't work super elegantly in processing.
I can then just go copy and paste it over.
Certainly, there's more streamlined ways
of importing a Java class,
but just copying it over is one way.
Then I'm going to come back to here
and what I'm going to do is everything that's in draw()
is what should go into
this render function.
This render function should now
have all of the drawing code.
Here, now we have this running.
It's not looping yet, I've got to figure that out.
I also want to give myself more frames probably and...
Actually let's make it short,
'cause I really want to make sure it's looping.
Let's make it 640 by 360,
it's kind of nice to have that aspect ratio.
Now, this is what I want to render as a perfect loop.
So, what's going on?
Here's the thing, the thing that needs to loop
is the z-axis, the z-axis instead of moving forward in time
should move around in a circular path
to create that donut in three-dimensional space.
How do I do that exactly?
It turns out that the way I can do that
is let me actually get rid of this idea of z offset
and I want to have...
Let's see if I can diagram this.
Alright, this is my two-dimensional plane of noise
in three-dimensional space and at any given point,
what I want to do is kind of walk around in a circle.
If this were the flat plane,
the circle would come out like this.
I don't know if this is really...
So, what I need is an angle.
I need to rotate around,
I need to use that polar coordinate formula,
to rotate around a circular path within
one plane of three-dimensional space.
To do that, I used four-dimensional noise,
because what I'm doing here is, I get...
Remember, in looping a GIF, I want a percentage
from 0 to 100%, so I can not now have an angle
which is equal to map that percent
which goes between 0 and 1, to between 0 and TWO_PI.
Then I can have, I'm going to call this u offset
for the third dimension and I'm going to call this
a v offset for the fourth dimension.
What those are is I'm going to say cosine of the angle
and sine of the angle, right?
I'm going to use the polar
to Cartesian coordinate transformation
and map these values,
which go between 0 and 1.
No, sorry, they go between -1 and 1, to between
some noise radius and noise diameter.
This is a concept I talked about
in the previous looping video,
but it's very hard to type and talk at the same time.
Sometimes I do a good job, sometimes I'm a mess,
and right now I'm a mess.
This is very hard to explain.
This is exactly the same technique that I did
in the first noise loop video,
where I just had an x and a y.
Now, I have an x and a y, but the looping
is happening in the u and the v.
That's where the size of this circle is important.
I'm not sure whether in the Open Simplex Noise algorithm
whether I can have negative values or not,
but to be safe, I'm just going to map these between 0 and 2.
I'm picking sort of an arbitrary, this I think we called
noise diameter or something like that,
I'm picking an arbitrary value.
Now, down here, change this to u offset, v offset,
and let's run this.
Did I get everything right?
No, no.
Oh, I have an extra 0 in here,
because I'm going crazy.
z offset is not a thing anymore,
and here we go.
(bell dings)
Okay, so one this to note here,
(laughs)
is that 4D,
the implementation for getting 4D noise is quite slow.
You can see this frame rate sort of chugging along.
The good news is we're here to render out to a loop,
so I don't care about the speed, the frame rate,
I am just going to turn record to true
and I'm going to run this again
and I will see you when it finishes rendering.
(playful synth music)
All right, it finished rendering.
The good news, just to reiterate,
because 3D noise worked quite smoothly,
if you're not rendering out to a loop,
you don't need that fourth dimension!
You can just use the third dimension
and watch your real-time software
in your media art installation work beautifully.
But, if you're rendering it out, I want to close that loop,
I do need that fourth dimension.
Okay, I'm going to switch over to my terminal window
and I'm in the GIF_loop_4D sketches folder
and now I'm going to use ffmpeg
to render all those frames into a GIF.
So, I'm going to say ffmpeg -for image2,
and ffmpeg is a utility
you would have to install separately.
I'll include a link to how to do that
in this video's description.
- f image2 -framerate, let's give it 30 frames per second,
- i, the file path, which is output/gif...
Each file is gif dash and then a number,
so %3d.png and then I'll call it noiseloop.gif
and I'm going to render that out.
I am going to take a look at it, here it is.
Let's take a look.
By golly, if that doesn't loop, I don't know what loops.
This is about four seconds long.
Of course, you can see.
(laughs)
You might be able to detect the loop because it's so short,
but if I made I a little longer and if there was a bit more,
if I was more artistic and had more creative ideas
about how to vary the visual quality,
we might be able to create something more like
what I showed you in those original Etienne Jacob GIFs.
Hi, so this might be the strangest,
most nontraditional ending of a coding training video ever,
'cause you probably were just watching me
in the studio coding, but I was going to record
a new ending to it today in the studio, but it's a snow day.
Just buried in snow here, can barely walk.
(laughs)
Anyway, what you have just seen is a coding challenge
where I added Open Simplex Noise.
Really, I think what you should take away from this
is the quality of Open Simplex Noise
rather than classic Perlin noise and think about
the kinds of projects you might make that run in real time
that don't actually need to loop.
But, if you're making a looping GIF,
this is sort of an interesting technique.
I'm going to show you right now this terrain.
This is basically my coding challenge before
but with Open Simplex Noise instead of classic Perlin noise.
That's a challenge to you.
If you can make this looping terrain happen,
then try that.
I'm going to do that in a video, I'll come back this Wednesday
during my regular livestream and I will create this terrain
with Open Simplex Noise as a follow up video.
I hope you enjoyed this short coding challenge
with Open Simplex Noise and looping in four dimensions
and all sorts of wackiness like that,
and I'll see you next time on the coding train, choo choo!
(upbeat pop music)