commonMain.ru.casperix.math.perlin.PerlinNoise.kt Maven / Gradle / Ivy
package ru.casperix.math.perlin
import ru.casperix.math.vector.float64.Vector2d
import kotlin.math.cos
import kotlin.math.sin
/**
* https://en.wikipedia.org/wiki/Perlin_noise
*/
object PerlinNoise {
/* Function to linearly interpolate between a0 and a1
* Weight w should be in the range [0.0, 1.0]
*/
fun interpolate(a0:Double, a1:Double, w:Double):Double {
/* // You may want clamping by inserting:
* if (0.0 > w) return a0;
* if (1.0 < w) return a1;
*/
return (a1 - a0) * w + a0;
/* // Use this cubic interpolation [[Smoothstep]] instead, for a smooth appearance:
* return (a1 - a0) * (3.0 - w * 2.0) * w * w + a0;
*
* // Use [[Smootherstep]] for an even smoother result with a second derivative equal to zero on boundaries:
* return (a1 - a0) * (x * (w * 6.0 - 15.0) * w * w *w + 10.0) + a0;
*/
}
/* Create random direction vector
*/
fun randomGradient(ix:Int, iy:Int): Vector2d {
// Random float. No precomputed gradients mean this works for any number of grid coordinates
val random = 2920.0 * sin(ix * 21942.0 + iy * 171324.0 + 8912.0) * cos(ix * 23157.0 * iy * 217832.0 + 9758.0);
return Vector2d(cos(random), sin(random))
}
// Computes the dot product of the distance and gradient vectors.
fun dotGridGradient(ix:Int, iy:Int, x:Double, y:Double):Double {
// Get gradient from integer coordinates
val gradient = randomGradient(ix, iy)
// Compute the distance vector
val dx = x - ix.toDouble()
val dy = y - iy.toDouble()
// Compute the dot-product
return (dx*gradient.x + dy*gradient.y)
}
// Compute Perlin noise at coordinates x, y
fun perlin(x:Double, y:Double):Double {
// Determine grid cell coordinates
val x0 = x.toInt()
val x1 = x0 + 1
val y0 = y.toInt()
val y1 = y0 + 1
// Determine interpolation weights
// Could also use higher order polynomial/s-curve here
val sx = x - x0.toDouble()
val sy = y - y0.toDouble()
// Interpolate between grid point gradients
val n0 = dotGridGradient(x0, y0, x, y)
val n1 = dotGridGradient(x1, y0, x, y)
val ix0 = interpolate(n0, n1, sx)
val n2 = dotGridGradient(x0, y1, x, y)
val n3 = dotGridGradient(x1, y1, x, y)
val ix1 = interpolate(n2, n3, sx)
return interpolate(ix0, ix1, sy)
}
}