mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-09 07:20:04 -04:00
integrate world renderer with new chunk format (performance optimizations)
This commit is contained in:
parent
6032900b42
commit
a147fb3c02
@ -153,7 +153,7 @@ class Chunk(
|
||||
val neighbours: Array<Chunk> = world.getChunkNeighbours(chunkPosition).unsafeCast()
|
||||
val cacheBiomeAccessor = world.cacheBiomeAccessor
|
||||
if (cacheBiomeAccessor != null && biomesInitialized && neighboursLoaded) {
|
||||
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor, world)
|
||||
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor)
|
||||
}
|
||||
sections[sectionIndex] = section
|
||||
}
|
||||
@ -195,7 +195,7 @@ class Chunk(
|
||||
for ((sectionIndex, section) in sections!!.withIndex()) {
|
||||
section ?: continue
|
||||
val sectionHeight = sectionIndex + lowestSection
|
||||
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor, world)
|
||||
section.buildBiomeCache(chunkPosition, sectionHeight, this, neighbours, cacheBiomeAccessor)
|
||||
}
|
||||
biomesInitialized = true
|
||||
}
|
||||
@ -211,7 +211,7 @@ class Chunk(
|
||||
if (section == null) {
|
||||
// ToDo: Faster
|
||||
val chunkPosition = Vec3i(x, y, z).chunkPosition
|
||||
return connection.world.cacheBiomeAccessor?.getBiome(x, y, z, chunkPosition.x, chunkPosition.y, this, null, world)
|
||||
return connection.world.cacheBiomeAccessor?.getBiome(x, y, z, chunkPosition.x, chunkPosition.y, this, null)
|
||||
}
|
||||
return section.biomes[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z]
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ class ChunkSection(
|
||||
}
|
||||
}
|
||||
|
||||
fun buildBiomeCache(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, neighbours: Array<Chunk>, biomeAccessor: NoiseBiomeAccessor, world: World) {
|
||||
fun buildBiomeCache(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, neighbours: Array<Chunk>, biomeAccessor: NoiseBiomeAccessor) {
|
||||
val chunkPositionX = chunkPosition.x
|
||||
val chunkPositionZ = chunkPosition.y
|
||||
val blockOffset = Vec3i.of(chunkPosition, sectionHeight)
|
||||
@ -98,7 +98,7 @@ class ChunkSection(
|
||||
val z = blockOffset.z
|
||||
val biomes: Array<Biome?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION)
|
||||
for (index in 0 until ProtocolDefinition.BLOCKS_PER_SECTION) {
|
||||
biomes[index] = biomeAccessor.getBiome(x + (index and 0x0F), y + ((index shr 8) and 0x0F), z + ((index shr 4) and 0x0F), chunkPositionX, chunkPositionZ, chunk, neighbours, world) //!!
|
||||
biomes[index] = biomeAccessor.getBiome(x + (index and 0x0F), y + ((index shr 8) and 0x0F), z + ((index shr 4) and 0x0F), chunkPositionX, chunkPositionZ, chunk, neighbours) //!!
|
||||
}
|
||||
this.biomes.setData(biomes.unsafeCast())
|
||||
}
|
||||
|
@ -17,12 +17,13 @@ import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.data.registries.biomes.Biome
|
||||
import de.bixilon.minosoft.data.world.Chunk
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.data.world.biome.noise.FuzzyNoiseBiomeCalculator
|
||||
import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray
|
||||
import de.bixilon.minosoft.util.MMath
|
||||
import glm_.vec2.Vec2i
|
||||
|
||||
class NoiseBiomeAccessor(private val world: World) {
|
||||
|
||||
fun getBiome(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array<Chunk>?, world: World): Biome? {
|
||||
fun getBiome(x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array<Chunk>?): Biome? {
|
||||
val biomeY = if (world.dimension?.supports3DBiomes == true) {
|
||||
y
|
||||
} else {
|
||||
@ -40,6 +41,139 @@ class NoiseBiomeAccessor(private val world: World) {
|
||||
return null
|
||||
}
|
||||
|
||||
return FuzzyNoiseBiomeCalculator.getBiome(world.hashedSeed, x, biomeY, z, chunkPositionX, chunkPositionZ, chunk, neighbours, world)
|
||||
return getBiome(world.hashedSeed, x, biomeY, z, chunkPositionX, chunkPositionZ, chunk, neighbours)
|
||||
}
|
||||
|
||||
|
||||
private fun getBiome(seed: Long, x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array<Chunk>?): Biome? {
|
||||
val m = x - 2
|
||||
val n = y - 2
|
||||
val o = z - 2
|
||||
|
||||
val p = m shr 2
|
||||
val q = n shr 2
|
||||
val r = o shr 2
|
||||
|
||||
val d = (m and 0x03) / 4.0
|
||||
val e = (n and 0x03) / 4.0
|
||||
val f = (o and 0x03) / 4.0
|
||||
|
||||
var s = 0
|
||||
var g = Double.POSITIVE_INFINITY
|
||||
|
||||
for (i in 0 until 8) {
|
||||
var u = p
|
||||
var xFraction = d
|
||||
if (i and 0x04 != 0) {
|
||||
u++
|
||||
xFraction -= 1.0
|
||||
}
|
||||
|
||||
var v = q
|
||||
var yFraction = e
|
||||
if (i and 0x02 != 0) {
|
||||
v++
|
||||
yFraction -= 1.0
|
||||
}
|
||||
|
||||
var w = r
|
||||
var zFraction = f
|
||||
if (i and 0x01 != 0) {
|
||||
w++
|
||||
zFraction -= 1.0
|
||||
}
|
||||
|
||||
|
||||
val d3 = calculateFiddle(seed, u, v, w, xFraction, yFraction, zFraction)
|
||||
if (g > d3) {
|
||||
s = i
|
||||
g = d3
|
||||
}
|
||||
}
|
||||
|
||||
var biomeX = p
|
||||
if (s and 0x04 != 0) {
|
||||
biomeX++
|
||||
}
|
||||
var biomeY = q
|
||||
if (s and 0x02 != 0) {
|
||||
biomeY++
|
||||
}
|
||||
var biomeZ = r
|
||||
if (s and 0x01 != 0) {
|
||||
biomeZ++
|
||||
}
|
||||
|
||||
var biomeChunk: Chunk? = null
|
||||
val biomeChunkX = biomeX shr 2
|
||||
val biomeChunkZ = biomeZ shr 2
|
||||
|
||||
if (neighbours == null) {
|
||||
return world[Vec2i(biomeChunkX, biomeChunkZ)]?.biomeSource?.getBiome(biomeX, biomeY, biomeZ)
|
||||
}
|
||||
|
||||
val deltaChunkX = biomeChunkX - chunkPositionX
|
||||
val deltaChunkZ = biomeChunkZ - chunkPositionZ
|
||||
|
||||
when (deltaChunkX) {
|
||||
0 -> when (deltaChunkZ) {
|
||||
0 -> biomeChunk = chunk
|
||||
-1 -> biomeChunk = neighbours[3]
|
||||
1 -> biomeChunk = neighbours[4]
|
||||
}
|
||||
-1 -> when (deltaChunkZ) {
|
||||
0 -> biomeChunk = neighbours[1]
|
||||
-1 -> biomeChunk = neighbours[0]
|
||||
1 -> biomeChunk = neighbours[2]
|
||||
}
|
||||
1 -> when (deltaChunkZ) {
|
||||
0 -> biomeChunk = neighbours[6]
|
||||
-1 -> biomeChunk = neighbours[5]
|
||||
1 -> biomeChunk = neighbours[7]
|
||||
}
|
||||
}
|
||||
|
||||
return biomeChunk?.biomeSource?.getBiome(biomeX, biomeY, biomeZ)
|
||||
}
|
||||
|
||||
private fun calculateFiddle(seed: Long, x: Int, y: Int, z: Int, xFraction: Double, yFraction: Double, zFraction: Double): Double {
|
||||
var ret = seed
|
||||
|
||||
ret = next(ret, x)
|
||||
ret = next(ret, y)
|
||||
ret = next(ret, z)
|
||||
ret = next(ret, x)
|
||||
ret = next(ret, y)
|
||||
ret = next(ret, z)
|
||||
|
||||
val xFractionSalt = distribute(ret)
|
||||
|
||||
ret = next(ret, seed)
|
||||
|
||||
val yFractionSalt = distribute(ret)
|
||||
|
||||
ret = next(ret, seed)
|
||||
|
||||
val zFractionSalt = distribute(ret)
|
||||
|
||||
return MMath.square(xFraction + xFractionSalt) + MMath.square(yFraction + yFractionSalt) + MMath.square(zFraction + zFractionSalt)
|
||||
}
|
||||
|
||||
private fun distribute(seed: Long): Double {
|
||||
val d = Math.floorMod(seed shr 24, 1024L).toInt() / 1024.0
|
||||
return (d - 0.5) * 0.9
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Linear_congruential_generator
|
||||
private fun next(seed: Long): Long {
|
||||
return seed * (seed * 6364136223846793005L + 1442695040888963407L)
|
||||
}
|
||||
|
||||
private fun next(seed: Long, salt: Int): Long {
|
||||
return next(seed) + salt
|
||||
}
|
||||
|
||||
private fun next(seed: Long, salt: Long): Long {
|
||||
return next(seed) + salt
|
||||
}
|
||||
}
|
||||
|
@ -1,142 +0,0 @@
|
||||
package de.bixilon.minosoft.data.world.biome.noise
|
||||
|
||||
import de.bixilon.minosoft.data.registries.biomes.Biome
|
||||
import de.bixilon.minosoft.data.world.Chunk
|
||||
import de.bixilon.minosoft.data.world.World
|
||||
import de.bixilon.minosoft.util.MMath.square
|
||||
import glm_.vec2.Vec2i
|
||||
|
||||
object FuzzyNoiseBiomeCalculator {
|
||||
|
||||
fun getBiome(seed: Long, x: Int, y: Int, z: Int, chunkPositionX: Int, chunkPositionZ: Int, chunk: Chunk, neighbours: Array<Chunk>?, world: World): Biome? {
|
||||
val m = x - 2
|
||||
val n = y - 2
|
||||
val o = z - 2
|
||||
|
||||
val p = m shr 2
|
||||
val q = n shr 2
|
||||
val r = o shr 2
|
||||
|
||||
val d = (m and 0x03) / 4.0
|
||||
val e = (n and 0x03) / 4.0
|
||||
val f = (o and 0x03) / 4.0
|
||||
|
||||
var s = 0
|
||||
var g = Double.POSITIVE_INFINITY
|
||||
|
||||
for (i in 0 until 8) {
|
||||
var u = p
|
||||
var xFraction = d
|
||||
if (i and 0x04 != 0) {
|
||||
u++
|
||||
xFraction -= 1.0
|
||||
}
|
||||
|
||||
var v = q
|
||||
var yFraction = e
|
||||
if (i and 0x02 != 0) {
|
||||
v++
|
||||
yFraction -= 1.0
|
||||
}
|
||||
|
||||
var w = r
|
||||
var zFraction = f
|
||||
if (i and 0x01 != 0) {
|
||||
w++
|
||||
zFraction -= 1.0
|
||||
}
|
||||
|
||||
|
||||
val d3 = calculateFiddle(seed, u, v, w, xFraction, yFraction, zFraction)
|
||||
if (g > d3) {
|
||||
s = i
|
||||
g = d3
|
||||
}
|
||||
}
|
||||
|
||||
var biomeX = p
|
||||
if (s and 0x04 != 0) {
|
||||
biomeX++
|
||||
}
|
||||
var biomeY = q
|
||||
if (s and 0x02 != 0) {
|
||||
biomeY++
|
||||
}
|
||||
var biomeZ = r
|
||||
if (s and 0x01 != 0) {
|
||||
biomeZ++
|
||||
}
|
||||
|
||||
var biomeChunk: Chunk? = null
|
||||
val biomeChunkX = biomeX shr 2
|
||||
val biomeChunkZ = biomeZ shr 2
|
||||
|
||||
if (neighbours == null) {
|
||||
return world[Vec2i(biomeChunkX, biomeChunkZ)]?.biomeSource?.getBiome(biomeX, biomeY, biomeZ)
|
||||
}
|
||||
|
||||
val deltaChunkX = biomeChunkX - chunkPositionX
|
||||
val deltaChunkZ = biomeChunkZ - chunkPositionZ
|
||||
|
||||
when (deltaChunkX) {
|
||||
0 -> when (deltaChunkZ) {
|
||||
0 -> biomeChunk = chunk
|
||||
-1 -> biomeChunk = neighbours[3]
|
||||
1 -> biomeChunk = neighbours[4]
|
||||
}
|
||||
-1 -> when (deltaChunkZ) {
|
||||
0 -> biomeChunk = neighbours[1]
|
||||
-1 -> biomeChunk = neighbours[0]
|
||||
1 -> biomeChunk = neighbours[2]
|
||||
}
|
||||
1 -> when (deltaChunkZ) {
|
||||
0 -> biomeChunk = neighbours[6]
|
||||
-1 -> biomeChunk = neighbours[5]
|
||||
1 -> biomeChunk = neighbours[7]
|
||||
}
|
||||
}
|
||||
|
||||
return biomeChunk?.biomeSource?.getBiome(biomeX, biomeY, biomeZ)
|
||||
}
|
||||
|
||||
private fun calculateFiddle(seed: Long, x: Int, y: Int, z: Int, xFraction: Double, yFraction: Double, zFraction: Double): Double {
|
||||
var ret = seed
|
||||
|
||||
ret = next(ret, x)
|
||||
ret = next(ret, y)
|
||||
ret = next(ret, z)
|
||||
ret = next(ret, x)
|
||||
ret = next(ret, y)
|
||||
ret = next(ret, z)
|
||||
|
||||
val xFractionSalt = distribute(ret)
|
||||
|
||||
ret = next(ret, seed)
|
||||
|
||||
val yFractionSalt = distribute(ret)
|
||||
|
||||
ret = next(ret, seed)
|
||||
|
||||
val zFractionSalt = distribute(ret)
|
||||
|
||||
return square(xFraction + xFractionSalt) + square(yFraction + yFractionSalt) + square(zFraction + zFractionSalt)
|
||||
}
|
||||
|
||||
private fun distribute(seed: Long): Double {
|
||||
val d = Math.floorMod(seed shr 24, 1024L).toInt() / 1024.0
|
||||
return (d - 0.5) * 0.9
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Linear_congruential_generator
|
||||
private fun next(seed: Long): Long {
|
||||
return seed * (seed * 6364136223846793005L + 1442695040888963407L)
|
||||
}
|
||||
|
||||
private fun next(seed: Long, salt: Int): Long {
|
||||
return next(seed) + salt
|
||||
}
|
||||
|
||||
private fun next(seed: Long, salt: Long): Long {
|
||||
return next(seed) + salt
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshes
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.chunk.ChunkUtil.acquire
|
||||
import de.bixilon.minosoft.util.chunk.ChunkUtil.release
|
||||
import glm_.vec2.Vec2i
|
||||
import glm_.vec3.Vec3i
|
||||
import java.util.*
|
||||
@ -21,6 +23,8 @@ class CullSectionPreparer(
|
||||
val random = Random(0L)
|
||||
|
||||
val blocks = section.blocks
|
||||
section.acquire()
|
||||
neighbours.acquire()
|
||||
var block: BlockState?
|
||||
val neighbourBlocks: Array<BlockState?> = arrayOfNulls(Directions.SIZE)
|
||||
|
||||
@ -31,41 +35,41 @@ class CullSectionPreparer(
|
||||
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
|
||||
for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) {
|
||||
for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
|
||||
block = blocks[ChunkSection.getIndex(x, y, z)]
|
||||
block = blocks.unsafeGet(x, y, z)
|
||||
val model = block?.model ?: continue
|
||||
|
||||
// ToDo: Chunk borders
|
||||
neighbourBlocks[Directions.DOWN.ordinal] = if (y == 0) {
|
||||
neighbours[Directions.DOWN.ordinal]?.blocks?.get(ChunkSection.getIndex(x, ProtocolDefinition.SECTION_MAX_Y, z))
|
||||
neighbours[Directions.DOWN.ordinal]?.blocks?.unsafeGet(x, ProtocolDefinition.SECTION_MAX_Y, z)
|
||||
} else {
|
||||
blocks[ChunkSection.getIndex(x, y - 1, z)]
|
||||
blocks.unsafeGet(x, y - 1, z)
|
||||
}
|
||||
neighbourBlocks[Directions.UP.ordinal] = if (y == ProtocolDefinition.SECTION_MAX_Y) {
|
||||
neighbours[Directions.UP.ordinal]?.blocks?.get(ChunkSection.getIndex(x, 0, z))
|
||||
neighbours[Directions.UP.ordinal]?.blocks?.unsafeGet(x, 0, z)
|
||||
} else {
|
||||
blocks[ChunkSection.getIndex(x, y + 1, z)]
|
||||
blocks.unsafeGet(x, y + 1, z)
|
||||
}
|
||||
|
||||
neighbourBlocks[Directions.NORTH.ordinal] = if (z == 0) {
|
||||
neighbours[Directions.NORTH.ordinal]?.blocks?.get(ChunkSection.getIndex(x, y, ProtocolDefinition.SECTION_MAX_Z))
|
||||
neighbours[Directions.NORTH.ordinal]?.blocks?.unsafeGet(x, y, ProtocolDefinition.SECTION_MAX_Z)
|
||||
} else {
|
||||
blocks[ChunkSection.getIndex(x, y, z - 1)]
|
||||
blocks.unsafeGet(x, y, z - 1)
|
||||
}
|
||||
neighbourBlocks[Directions.SOUTH.ordinal] = if (z == ProtocolDefinition.SECTION_MAX_Z) {
|
||||
neighbours[Directions.SOUTH.ordinal]?.blocks?.get(ChunkSection.getIndex(x, y, 0))
|
||||
neighbours[Directions.SOUTH.ordinal]?.blocks?.unsafeGet(x, y, 0)
|
||||
} else {
|
||||
blocks[ChunkSection.getIndex(x, y, z + 1)]
|
||||
blocks.unsafeGet(x, y, z + 1)
|
||||
}
|
||||
|
||||
neighbourBlocks[Directions.WEST.ordinal] = if (x == 0) {
|
||||
neighbours[Directions.WEST.ordinal]?.blocks?.get(ChunkSection.getIndex(ProtocolDefinition.SECTION_MAX_X, y, z))
|
||||
neighbours[Directions.WEST.ordinal]?.blocks?.unsafeGet(ProtocolDefinition.SECTION_MAX_X, y, z)
|
||||
} else {
|
||||
blocks[ChunkSection.getIndex(x - 1, y, z)]
|
||||
blocks.unsafeGet(x - 1, y, z)
|
||||
}
|
||||
neighbourBlocks[Directions.EAST.ordinal] = if (x == ProtocolDefinition.SECTION_MAX_X) {
|
||||
neighbours[Directions.EAST.ordinal]?.blocks?.get(ChunkSection.getIndex(0, y, z))
|
||||
neighbours[Directions.EAST.ordinal]?.blocks?.unsafeGet(0, y, z)
|
||||
} else {
|
||||
blocks[ChunkSection.getIndex(x + 1, y, z)]
|
||||
blocks.unsafeGet(x + 1, y, z)
|
||||
}
|
||||
|
||||
val position = Vec3i(offsetX + x, offsetY + y, offsetZ + z)
|
||||
@ -77,6 +81,8 @@ class CullSectionPreparer(
|
||||
}
|
||||
}
|
||||
}
|
||||
section.release()
|
||||
neighbours.release()
|
||||
|
||||
|
||||
return mesh
|
||||
|
@ -272,4 +272,16 @@ object ChunkUtil {
|
||||
neighbourChunks[6][sectionHeight],
|
||||
)
|
||||
}
|
||||
|
||||
fun Array<ChunkSection?>.acquire() {
|
||||
for (section in this) {
|
||||
section?.acquire()
|
||||
}
|
||||
}
|
||||
|
||||
fun Array<ChunkSection?>.release() {
|
||||
for (section in this) {
|
||||
section?.release()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user