So I am working on a particle system, mainly as a learning exercise on the CPU, using Visual Studio C++. It's looking pretty neat!
The latest thing I'm attempting is to add turbulence using 3D perlin noise. I found this fellow's code: https://blog.kazade.co.uk/2014/05/a-public-domain-c11-1d2d3d-perlin-noise.html
I implemented it correctly. I know this, because I can draw solid, working Perlin noise within my app, and it draws it correctly, also taking into account octaves, amplitude and frequency, which I added access to. So far, so good.
The problem is that I don't know how to use this correctly for displacing particle motion. This is currently my implementation (px0, py0, pz0 are my particle positions in -1.0 to 1.0 screen-space range. 0.1 is just to scale values down to a usable amount):
//Initialize octaves, seed, amplitude, frequency
noise::PerlinOctave perlin(octaves, seed, amplitude, frequency);
// Call the noise function
float n = perlin.noise(px0,py0,pz0) * 0.1;
px0 += n;
py0 += n;
pz0 += n;
This produces ok results but when I adjust the amplitude, my particles move diagonally. This is usually due to using addition which makes me think perhaps I shouldn't be adding noise to the particle positions but rather multiplying. However, I haven't had any success trying that.
I also tried unsuccessfully assigning 1D Perlin noise to every axis like this:
px0 += perlin.noise(px0) * 0.1;
py0 += perlin.noise(py0) * 0.1;
pz0 += perlin.noise(pz0) * 0.1;
The noise function returns a value of -1.0 to 1.0 (I believe) and my particle screen-space also works that same range so there should be no need to remap the noise to 0.0-1.0.
So I can't think of anything else to try. Any ideas where I'm going wrong?
Thank you all in advance! -Richard
I think you may have a few things backwards here.
3D Perlin noise defines a noise function that takes a 3D input, to provide you with a 1D output. What you need is something that takes a 3D input, and gives you a 3D output.
You could achieve this by having 3x3D noises....
noise::PerlinOctave3D perlinX(octaves, seedX, amplitudeX, frequencyX);
noise::PerlinOctave3D perlinY(octaves, seedY, amplitudeY, frequencyY);
noise::PerlinOctave3D perlinZ(octaves, seedZ, amplitudeZ, frequencyZ);
// Call the noise function(s)
float nx = perlinX.noise(px0,py0,pz0) * 0.1;
float ny = perlinY.noise(px0,py0,pz0) * 0.1;
float nz = perlinZ.noise(px0,py0,pz0) * 0.1;
px0 += nx;
py0 += ny;
pz0 += nz;
Using 3x1D noise funcs would also work (maybe not that well, but it will work)
noise::PerlinOctave1D perlinX(octaves, seedX, amplitudeX, frequencyX);
noise::PerlinOctave1D perlinY(octaves, seedY, amplitudeY, frequencyY);
noise::PerlinOctave1D perlinZ(octaves, seedZ, amplitudeZ, frequencyZ);
// Call the noise function(s)
float nx = perlinX.noise(px0) * 0.1;
float ny = perlinY.noise(py0) * 0.1;
float nz = perlinZ.noise(pz0) * 0.1;
px0 += nx;
py0 += ny;
pz0 += nz;
Even using 2D funcs would work (and be a bit cheaper than 3x3D funcs).
noise::PerlinOctave2D perlinX(octaves, seedX, amplitudeX, frequencyX);
noise::PerlinOctave2D perlinY(octaves, seedY, amplitudeY, frequencyY);
noise::PerlinOctave2D perlinZ(octaves, seedZ, amplitudeZ, frequencyZ);
// Call the noise function(s)
float nx = perlinX.noise(px0, py0) * 0.1;
float ny = perlinY.noise(py0, pz0) * 0.1;
float nz = perlinZ.noise(pz0, px0) * 0.1;
px0 += nx;
py0 += ny;
pz0 += nz;
If you are modelling turbulence though, you probably want to be extracting the noise to be used as a force to apply to the particles, rather than simply using the result to directly modify the position.