For very simple pseudorandom-looking stuff, I use this oneliner that I found on the internet somewhere:
float rand(vec2 co){
return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
}
You can also generate a noise texture using whatever PRNG you like, then upload this in the normal fashion and sample the values in your shader; I can dig up a code sample later if you'd like.
Also, check out this file for GLSL implementations of Perlin and Simplex noise, by Stefan Gustavson.
Perlin noise is completely controlled by the different variables you set, i.e. amplitude, frequency and persistance. The amount of octaves has a little change, but not much. In code that I have written in the past I have just played around with the order of magnitude of the frequency and persistance until I have gotten what I needed. I can try to find my old source if needed.
PerlinNoise.h
#pragma once
class PerlinNoise
{
public:
// Constructor
PerlinNoise();
PerlinNoise(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed);
// Get Height
double GetHeight(double x, double y) const;
// Get
double Persistence() const { return persistence; }
double Frequency() const { return frequency; }
double Amplitude() const { return amplitude; }
int Octaves() const { return octaves; }
int RandomSeed() const { return randomseed; }
// Set
void Set(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed);
void SetPersistence(double _persistence) { persistence = _persistence; }
void SetFrequency( double _frequency) { frequency = _frequency; }
void SetAmplitude( double _amplitude) { amplitude = _amplitude; }
void SetOctaves( int _octaves) { octaves = _octaves; }
void SetRandomSeed( int _randomseed) { randomseed = _randomseed; }
private:
double Total(double i, double j) const;
double GetValue(double x, double y) const;
double Interpolate(double x, double y, double a) const;
double Noise(int x, int y) const;
double persistence, frequency, amplitude;
int octaves, randomseed;
};
PerlinNoise.cpp
#include "PerlinNoise.h"
PerlinNoise::PerlinNoise()
{
persistence = 0;
frequency = 0;
amplitude = 0;
octaves = 0;
randomseed = 0;
}
PerlinNoise::PerlinNoise(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed)
{
persistence = _persistence;
frequency = _frequency;
amplitude = _amplitude;
octaves = _octaves;
randomseed = 2 + _randomseed * _randomseed;
}
void PerlinNoise::Set(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed)
{
persistence = _persistence;
frequency = _frequency;
amplitude = _amplitude;
octaves = _octaves;
randomseed = 2 + _randomseed * _randomseed;
}
double PerlinNoise::GetHeight(double x, double y) const
{
return amplitude * Total(x, y);
}
double PerlinNoise::Total(double i, double j) const
{
//properties of one octave (changing each loop)
double t = 0.0f;
double _amplitude = 1;
double freq = frequency;
for(int k = 0; k < octaves; k++)
{
t += GetValue(j * freq + randomseed, i * freq + randomseed) * _amplitude;
_amplitude *= persistence;
freq *= 2;
}
return t;
}
double PerlinNoise::GetValue(double x, double y) const
{
int Xint = (int)x;
int Yint = (int)y;
double Xfrac = x - Xint;
double Yfrac = y - Yint;
//noise values
double n01 = Noise(Xint-1, Yint-1);
double n02 = Noise(Xint+1, Yint-1);
double n03 = Noise(Xint-1, Yint+1);
double n04 = Noise(Xint+1, Yint+1);
double n05 = Noise(Xint-1, Yint);
double n06 = Noise(Xint+1, Yint);
double n07 = Noise(Xint, Yint-1);
double n08 = Noise(Xint, Yint+1);
double n09 = Noise(Xint, Yint);
double n12 = Noise(Xint+2, Yint-1);
double n14 = Noise(Xint+2, Yint+1);
double n16 = Noise(Xint+2, Yint);
double n23 = Noise(Xint-1, Yint+2);
double n24 = Noise(Xint+1, Yint+2);
double n28 = Noise(Xint, Yint+2);
double n34 = Noise(Xint+2, Yint+2);
//find the noise values of the four corners
double x0y0 = 0.0625*(n01+n02+n03+n04) + 0.125*(n05+n06+n07+n08) + 0.25*(n09);
double x1y0 = 0.0625*(n07+n12+n08+n14) + 0.125*(n09+n16+n02+n04) + 0.25*(n06);
double x0y1 = 0.0625*(n05+n06+n23+n24) + 0.125*(n03+n04+n09+n28) + 0.25*(n08);
double x1y1 = 0.0625*(n09+n16+n28+n34) + 0.125*(n08+n14+n06+n24) + 0.25*(n04);
//interpolate between those values according to the x and y fractions
double v1 = Interpolate(x0y0, x1y0, Xfrac); //interpolate in x direction (y)
double v2 = Interpolate(x0y1, x1y1, Xfrac); //interpolate in x direction (y+1)
double fin = Interpolate(v1, v2, Yfrac); //interpolate in y direction
return fin;
}
double PerlinNoise::Interpolate(double x, double y, double a) const
{
double negA = 1.0 - a;
double negASqr = negA * negA;
double fac1 = 3.0 * (negASqr) - 2.0 * (negASqr * negA);
double aSqr = a * a;
double fac2 = 3.0 * aSqr - 2.0 * (aSqr * a);
return x * fac1 + y * fac2; //add the weighted factors
}
double PerlinNoise::Noise(int x, int y) const
{
int n = x + y * 57;
n = (n << 13) ^ n;
int t = (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff;
return 1.0 - double(t) * 0.931322574615478515625e-9;/// 1073741824.0);
}
Best Answer
Since no one is going to write up an answer from the comments, I'm trying myself. Please upvote when I'm correct, comment when not :)
There are several implementations and example code that (try to) implement Perlin noise. First, there is the Improved Noise reference implementation from Ken Perlin himself.
Case 1: Improved Noise reference implementation
The noise function takes three double values and outputs a value. When generating a 2D bitmap using x and y, and keeping z constant, one gets the well known Perlin noise pattern. When z is varied between 0.0 and 1.0, the noise clouds seem to "change" slowly. So a seeding method that sets z, e.g.
z = 10.0 * seed
, could work for "seeding".Another way to seed the noise function would be this: If you always just get noise in a range of [0.0; 64.0[ for x and y, one could seed the noise by adding an offset to x, y or both when calling the noise function: noise(x + 64.0*seed, y + 64.0*seed).
Case 2: Tutorial style Perlin noise code
Then there is an implementation of Perlin noise (adapted and used in many other Perlin noise tutorials) that have a base noise function like this (pseudocode):
My main skepticism came from the magic numbers and the trust of the authors of these pages that the formula leads to uniformly distributed noise. Other authors added the seed value somewhere in this formula.
The solution to add a seed to this type of Perlin noise implementation is to write a function that uniformly distributes output values for given x and y values (and by returning the same value for the same x and y values, of course). This function can be written using Boost.Random (code not tested):
The random number generator has some ctors, among them one that takes a range of uint32_t's that determine the initial state of the RNG.
There also are libraries that generate coherent noise, such as libnoise, that may be of help here.
Simplex Noise
I didn't ask of Simplex noise, but the one implementation (from Stefan Gustavson) I found uses a similar technique (some precomputed tables) like Ken Perlin's reference implementation, and could be seeded just like case 1 above. Commenter Robinson mentioned seeding when generating the look-up table, but I don't know how that would work.