
commonMain.casperix.math.perlin.ValueNoise2D.kt Maven / Gradle / Ivy
package casperix.math.perlin
import casperix.math.vector.float64.Vector3d
import casperix.misc.pow
import casperix.math.function.Random2DFunction
import casperix.math.function.Random3DFunction
import casperix.math.function.primeNumberList
import casperix.math.function.random2dFunctions
import casperix.math.function.Function2D
import casperix.math.interpolation.float64.InterpolateDoubleFunction
import casperix.math.interpolation.float64.cosineInterpolate
import kotlin.math.pow
/**
* https://habr.com/ru/post/142592/
*/
class ValueNoise2D(val persistence: Double = 0.5, val octaveAmount: Int = 8, val scale: Vector3d = Vector3d.ONE, val interpolateFunction: InterpolateDoubleFunction = cosineInterpolate, val smoothed: Boolean = true) {
class OctaveCache(val frequencyX: Double, val frequencyY: Double, val amplitude: Double, val primeNumber: Int, val randomFunction: Random2DFunction)
val normalizer: Double
val octaves: Array
companion object {
val randomWithFactor: Random3DFunction =
{ x, y, factor ->
val it = x + y * factor
val n = (it shl 13) xor it
(1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) and 0x7FFFFFFF) / 1073741824.0)
}
}
init {
if (octaveAmount < 1) throw Error("Octave amount must be positive (now: $octaveAmount)")
this.octaves = Array(octaveAmount) { index ->
val frequency = 2.pow(index)
val amplitude = persistence.pow(index)
val primeNumber = primeNumberList[(index + 128) % primeNumberList.size]
OctaveCache(frequency.toDouble() * scale.x, frequency.toDouble() * scale.y, amplitude, primeNumber, random2dFunctions[index % random2dFunctions.size])
}
var amplitude = 0.0
octaves.forEach { amplitude += it.amplitude }
normalizer = ((if (smoothed) 2.0 else 1.0) / amplitude) * scale.z
}
val output: Function2D = { x, y ->
var total = 0.0
for (octave in octaves) {
total += interpolate2dFlat(x * octave.frequencyX, y * octave.frequencyY, octave.primeNumber) * octave.amplitude
}
total * normalizer
}
private fun interpolate2dFlat(x: Double, y: Double, randomFactor: Int): Double {
val baseX = x.toInt()
val fractionalX = x - baseX
val baseY = y.toInt()
val fractionalY = y - baseY
val v1 = randomWithFactor(baseX, baseY, randomFactor)
val v2 = randomWithFactor(baseX + 1, baseY, randomFactor)
val v3 = randomWithFactor(baseX, baseY + 1, randomFactor)
val v4 = randomWithFactor(baseX + 1, baseY + 1, randomFactor)
val i1 = interpolateFunction(v1, v2, fractionalX)
val i2 = interpolateFunction(v3, v4, fractionalX)
return interpolateFunction(i1, i2, fractionalY)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy