SiNoise Part2
Read the first part here
So now I've come to the implementing the actual thing. And yes I have a name for it, which should be apparent by now- SiNoise.
I'll be explaining the simplex approach here, perlin is pretty simple compared to that and I'll leave a link to the code.
The full code for Simplex approach is here and Perlin approach is here.
For brevity, here's the relevant function-
public float noiseWrapper(int x, int y, float xCenter, float yCenter, float minDistance, float maxDistance) {
Vector2f relative = new Vector2f((float) x - xCenter, (float) y - yCenter);
if (relative.equals(Vector2f.zero())) {
return 1.0f;
}
float scaledAngle = (((float) Math.atan2(relative.y, relative.x) + (float) Math.PI) * ((float) gridSize * simplexMagicNumber)) / (2.0f * (float) Math.PI);
float b = 1.0f / minDistance;
float a = 1.0f / maxDistance - b;
float adjustedNoise = (a * ((tileableNoise.noise(scaledAngle, scaledAngle) + 1.0f) / 2.0f) + b) * relative.length();
return 1.0f - TeraMath.clamp(adjustedNoise);
}
x
,y
being the coordinates for which noise in required, xCenter
,yCenter
being the geometric centre of the area reserved. and minDistance
,maxDistance
being the minimum and maximum distance a peripheral point can have from the centre.
Walkthrough time
return 1.0f - TeraMath.clamp(adjustedNoise);
Wait... this is the last line. But yeah the thing is notice here that noise values are being flipped over here i.e. before this adjustedNoise = 1
on peripheri and adjustedNoise = 0
at centre. This makes things easier to comprehend as you'll see later.
Vector2f relative = new Vector2f((float) x - xCenter, (float) y - yCenter);
Save the coordinates in a vector, so I can spare calculating the distance by hand.
if (relative.equals(Vector2f.zero())) {
return 1.0f;
}
This is a corner case as we can't really have an angle defined for the centre and the noise value of 1.0
signifies that this is the centre.
float scaledAngle = (((float) Math.atan2(relative.y, relative.x) + (float) Math.PI) * ((float) gridSize * simplexMagicNumber)) / (2.0f * (float) Math.PI);
((float) Math.atan2(relative.y, relative.x) + (float) Math.PI)
gets the angle for the point and shift it from [-π,π] to [0, 2π]. / (2.0f * (float) Math.PI)
map to [0,1]. * ((float) gridSize * simplexMagicNumber)
map to [0, edgeOfDiagonal](hint: read last post).
float b = 1.0f / minDistance;
float a = 1.0f / maxDistance - b;
This is to impose the new constraints of minDistance
and maxDistance
. The idea of maxDistance
was introduced in the last post but now there's minDistance
as well, so, consider this-
f(θ, distance) = (a * Noise(θ) + b) * distance
Noise(θ) ∈ [0,1]
, so lets have a look at the extreme conditions and apply the constraints there.
When Noise(θ) == 0
, f == 1
for distance == minDistance
Similarly,
When Noise(θ) == 1
, f == 1
for distance == maxDistance
2 equations, 2 variables, solve it and you'll get the values I got.
float adjustedNoise = (a * ((tileableNoise.noise(scaledAngle, scaledAngle) + 1.0f) / 2.0f) + b) * relative.length();
¯\_(ツ)_/¯
Now to show you some results-
Perlin with gridSize = 4
, minDistance = 20
, maxDistance = 50
Perlin with gridSize = 20
, rest same
Now you dhould be able to appreciate the control over gridSize
:)
Next up... Volcano!!!
#procgen #proceduralgeneration #noise #perlin #simplex #volcano