mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 18:34:56 -04:00
refactor and document more of the veronoi noise
This commit is contained in:
parent
1fab559a68
commit
255e14cd82
@ -23,7 +23,7 @@ import org.testng.annotations.Test
|
|||||||
class VoronoiBiomeAccessorTest {
|
class VoronoiBiomeAccessorTest {
|
||||||
private val getBiomeOffset = VoronoiBiomeAccessor::class.java.getDeclaredMethod("getBiomeOffset", Long::class.java, Int::class.java, Int::class.java, Int::class.java).apply { isAccessible = true }
|
private val getBiomeOffset = VoronoiBiomeAccessor::class.java.getDeclaredMethod("getBiomeOffset", Long::class.java, Int::class.java, Int::class.java, Int::class.java).apply { isAccessible = true }
|
||||||
|
|
||||||
// TODO: those values are too far off. They match vanilla, yes, but I am still not going to allow that. The noise should be fairly smooth around the data
|
// Those values are actually undefined, the getBiomeOffset method only allows values from 0 to 15
|
||||||
@Test(enabled = false)
|
@Test(enabled = false)
|
||||||
fun testBiomeNoise1() {
|
fun testBiomeNoise1() {
|
||||||
assertEquals(calculate(129, 3274, 91, 1823123L), Vec3i(32, 818, 22))
|
assertEquals(calculate(129, 3274, 91, 1823123L), Vec3i(32, 818, 22))
|
||||||
@ -48,14 +48,52 @@ class VoronoiBiomeAccessorTest {
|
|||||||
assertEquals(calculate(0, 3, 1, -33135639), Vec3i(0, 0, 0))
|
assertEquals(calculate(0, 3, 1, -33135639), Vec3i(0, 0, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(enabled = false)
|
||||||
fun testBiomeNoise6() {
|
fun testBiomeNoise6() {
|
||||||
assertEquals(calculate(16, 15, -16, 561363374), Vec3i(4, 3, -4))
|
assertEquals(calculate(16, 15, -16, 561363374), Vec3i(4, 3, -4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(enabled = false)
|
||||||
fun testBiomeNoise7() {
|
fun testBiomeNoise7() {
|
||||||
assertEquals(calculate(16, -15, -16, 79707367), Vec3i(4, -4, -5))
|
assertEquals(calculate(16, -15, -16, 79707367), Vec3i(4, -4, -5))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun `noise at (0,0,0) seed1`() {
|
||||||
|
assertEquals(calculate(0, 0, 0, -33135639), Vec3i(-1, 0, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `noise at (0,0,0) seed2`() {
|
||||||
|
assertEquals(calculate(0, 0, 0, 1234567891234567891L), Vec3i(-1, 0, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `noise at (0,0,0) seed3`() {
|
||||||
|
assertEquals(calculate(0, 0, 0, -987654321987654319L), Vec3i(-1, 0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `noise at (15,15,15) seed1`() {
|
||||||
|
assertEquals(calculate(15, 15, 15, -33135639), Vec3i(3, 3, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `noise at (15,15,15) seed2`() {
|
||||||
|
assertEquals(calculate(15, 15, 15, 1234567891234567891L), Vec3i(3, 3, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `noise at (15,15,15) seed3`() {
|
||||||
|
assertEquals(calculate(15, 15, 15, -987654321987654319L), Vec3i(3, 3, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `noise at (8,15,4) seed1`() {
|
||||||
|
assertEquals(calculate(8, 15, 4, -33135639), Vec3i(1, 3, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `noise at (8,15,4) seed2`() {
|
||||||
|
assertEquals(calculate(8, 15, 4, 1234567891234567891L), Vec3i(1, 3, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `noise at (8,15,4) seed3`() {
|
||||||
|
assertEquals(calculate(8, 15, 4, -987654321987654319L), Vec3i(1, 4, 0))
|
||||||
|
}
|
||||||
|
|
||||||
private fun calculate(x: Int, y: Int, z: Int, seed: Long): Vec3i {
|
private fun calculate(x: Int, y: Int, z: Int, seed: Long): Vec3i {
|
||||||
val accessor = VoronoiBiomeAccessor::class.java.allocate()
|
val accessor = VoronoiBiomeAccessor::class.java.allocate()
|
||||||
val index = getBiomeOffset.invoke(accessor, seed, x, y, z) as Int
|
val index = getBiomeOffset.invoke(accessor, seed, x, y, z) as Int
|
||||||
|
@ -16,6 +16,7 @@ package de.bixilon.minosoft.data.world.biome.accessor.noise
|
|||||||
import de.bixilon.kutil.math.simple.DoubleMath.square
|
import de.bixilon.kutil.math.simple.DoubleMath.square
|
||||||
import de.bixilon.minosoft.data.registries.biomes.Biome
|
import de.bixilon.minosoft.data.registries.biomes.Biome
|
||||||
import de.bixilon.minosoft.data.world.World
|
import de.bixilon.minosoft.data.world.World
|
||||||
|
import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray
|
||||||
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
|
||||||
|
|
||||||
class VoronoiBiomeAccessor(
|
class VoronoiBiomeAccessor(
|
||||||
@ -41,61 +42,65 @@ class VoronoiBiomeAccessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getBiomeOffset(seed: Long, x: Int, y: Int, z: Int): Int {
|
private fun getBiomeOffset(seed: Long, x: Int, y: Int, z: Int): Int {
|
||||||
val m = x - 2
|
// all xyz coordinates are from 0..15
|
||||||
val n = y - 2
|
|
||||||
val o = z - 2
|
|
||||||
|
|
||||||
val p = m shr 2
|
// target biome can also be on the negative side, offset by -2
|
||||||
val q = n shr 2
|
val cX = x - 2
|
||||||
val r = o shr 2
|
val cY = y - 2
|
||||||
|
val cZ = z - 2
|
||||||
|
|
||||||
val d = (m and 0x03) / 4.0
|
// array source
|
||||||
val e = (n and 0x03) / 4.0
|
val sX = cX shr 2
|
||||||
val f = (o and 0x03) / 4.0
|
val sY = cY shr 2
|
||||||
|
val sZ = cZ shr 2
|
||||||
|
|
||||||
var s = 0
|
// in array
|
||||||
var g = Double.POSITIVE_INFINITY
|
val iX = (cX and 0x03) / 4.0
|
||||||
|
val iY = (cY and 0x03) / 4.0
|
||||||
|
val iZ = (cZ and 0x03) / 4.0
|
||||||
|
|
||||||
for (i in 0 until 8) {
|
var minXYZ = 0
|
||||||
var u = p
|
var minDistance = Double.POSITIVE_INFINITY
|
||||||
var xFraction = d
|
|
||||||
if (i and 0x04 != 0) {
|
for (xyz in 0 until 2 * 2 * 2) {
|
||||||
u++
|
var uX = sX
|
||||||
xFraction -= 1.0
|
var offsetX = iX
|
||||||
|
if (xyz and 0x04 != 0) {
|
||||||
|
uX++
|
||||||
|
offsetX -= 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
var v = q
|
var uY = sY
|
||||||
var yFraction = e
|
var offsetY = iY
|
||||||
if (i and 0x02 != 0) {
|
if (xyz and 0x02 != 0) {
|
||||||
v++
|
uY++
|
||||||
yFraction -= 1.0
|
offsetY -= 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
var w = r
|
var uZ = sZ
|
||||||
var zFraction = f
|
var offsetZ = iZ
|
||||||
if (i and 0x01 != 0) {
|
if (xyz and 0x01 != 0) {
|
||||||
w++
|
uZ++
|
||||||
zFraction -= 1.0
|
offsetZ -= 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val d3 = calculateFiddle(seed, u, v, w, xFraction, yFraction, zFraction)
|
val distance = noiseDistance(seed, uX, uY, uZ, offsetX, offsetY, offsetZ)
|
||||||
if (g > d3) {
|
if (distance > minDistance) continue
|
||||||
s = i
|
minXYZ = xyz
|
||||||
g = d3
|
minDistance = distance
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var biomeX = p
|
var biomeX = sX
|
||||||
if (s and 0x04 != 0) {
|
if (minXYZ and 0x04 != 0) {
|
||||||
biomeX++
|
biomeX++
|
||||||
}
|
}
|
||||||
var biomeY = q
|
var biomeY = sY
|
||||||
if (s and 0x02 != 0) {
|
if (minXYZ and 0x02 != 0) {
|
||||||
biomeY++
|
biomeY++
|
||||||
}
|
}
|
||||||
var biomeZ = r
|
var biomeZ = sZ
|
||||||
if (s and 0x01 != 0) {
|
if (minXYZ and 0x01 != 0) {
|
||||||
biomeZ++
|
biomeZ++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,32 +108,32 @@ class VoronoiBiomeAccessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun calculateFiddle(seed: Long, x: Int, y: Int, z: Int, xFraction: Double, yFraction: Double, zFraction: Double): Double {
|
private fun noiseDistance(seed: Long, x: Int, y: Int, z: Int, offsetX: Double, offsetY: Double, offsetZ: Double): Double {
|
||||||
var ret = seed
|
var ret = mix(seed, x, y, z)
|
||||||
|
|
||||||
ret = next(ret, x)
|
val noiseX = nextNoiseOffset(ret); ret = next(ret, seed)
|
||||||
ret = next(ret, y)
|
val noiseY = nextNoiseOffset(ret); ret = next(ret, seed)
|
||||||
ret = next(ret, z)
|
val noiseZ = nextNoiseOffset(ret)
|
||||||
ret = next(ret, x)
|
|
||||||
ret = next(ret, y)
|
|
||||||
ret = next(ret, z)
|
|
||||||
|
|
||||||
val xSalt = distribute(ret)
|
return (offsetX + noiseX).square() + (offsetY + noiseY).square() + (offsetZ + noiseZ).square()
|
||||||
|
|
||||||
ret = next(ret, seed)
|
|
||||||
|
|
||||||
val ySalt = distribute(ret)
|
|
||||||
|
|
||||||
ret = next(ret, seed)
|
|
||||||
|
|
||||||
val zSalt = distribute(ret)
|
|
||||||
|
|
||||||
return (xFraction + xSalt).square() + (yFraction + ySalt).square() + (zFraction + zSalt).square()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun distribute(seed: Long): Double {
|
private fun mix(seed: Long, x: Int, y: Int, z: Int): Long {
|
||||||
val d = Math.floorMod(seed shr 24, 1024L).toInt() / 1024.0
|
var mixed = seed
|
||||||
return (d - 0.5) * 0.9
|
mixed = next(mixed, x)
|
||||||
|
mixed = next(mixed, y)
|
||||||
|
mixed = next(mixed, z)
|
||||||
|
mixed = next(mixed, x)
|
||||||
|
mixed = next(mixed, y)
|
||||||
|
mixed = next(mixed, z)
|
||||||
|
return mixed
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nextNoiseOffset(seed: Long): Double {
|
||||||
|
val floor = Math.floorMod(seed shr 24, SpatialBiomeArray.SIZE.toLong()).toInt()
|
||||||
|
val double = (floor - (SpatialBiomeArray.SIZE / 2)) / SpatialBiomeArray.SIZE.toDouble()
|
||||||
|
|
||||||
|
return double * 0.9
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Linear_congruential_generator
|
// https://en.wikipedia.org/wiki/Linear_congruential_generator
|
||||||
|
Loading…
x
Reference in New Issue
Block a user