cleanup solid mesher a bit, fix light heightmap

Might be a little bit slower now...
This commit is contained in:
Moritz Zwerger 2025-03-07 23:46:06 +01:00
parent 8b0ac1944f
commit d6223cf873
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
3 changed files with 43 additions and 56 deletions

View File

@ -91,6 +91,12 @@ class SectionOcclusionTest {
assertEquals(occlusion.occlusion, BooleanArray(15) { if (it <= 4) true else false })
}
fun `everything except bottom line filled opaque`() {
val occlusion = create()
occlusion[0, 1, 0, 15, 15, 15] = opaque
assertEquals(occlusion.occlusion, booleanArrayOf(true, false, false, false, false, true, true, true, true, false, false, false, false, false, false))
}
fun `y=1 line filled opaque`() {
val occlusion = create()
occlusion[0, 1, 0, 15, 1, 15] = opaque

View File

@ -184,14 +184,10 @@ class ChunkRenderer(
lock.lock()
meshingQueue.tasks.interrupt(chunkPosition)
culledQueue.remove(chunkPosition, false)
meshingQueue.remove(chunkPosition)
loadingQueue.abort(chunkPosition, false)
loaded.unload(chunkPosition, false)
lock.unlock()

View File

@ -13,7 +13,6 @@
package de.bixilon.minosoft.gui.rendering.chunk.mesher
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.kutil.cast.CastUtil.nullCast
import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.minosoft.data.direction.Directions
@ -29,7 +28,7 @@ import de.bixilon.minosoft.data.registries.blocks.types.fluid.FluidBlock
import de.bixilon.minosoft.data.registries.blocks.types.properties.offset.OffsetBlock
import de.bixilon.minosoft.data.world.chunk.ChunkSection
import de.bixilon.minosoft.data.world.chunk.chunk.Chunk
import de.bixilon.minosoft.data.world.chunk.light.SectionLight
import de.bixilon.minosoft.data.world.chunk.light.SectionLight.Companion.SKY_LIGHT_MASK
import de.bixilon.minosoft.data.world.chunk.neighbours.ChunkNeighbourArray
import de.bixilon.minosoft.data.world.positions.BlockPosition
import de.bixilon.minosoft.data.world.positions.InChunkPosition
@ -69,16 +68,12 @@ class SolidSectionMesher(
val entities: ArrayList<BlockEntityRenderer<*>> = ArrayList(section.blockEntities.count)
val tint = IntArray(1)
var position = BlockPosition()
var inSectionPosition = InSectionPosition(0, 0, 0)
val neighbourBlocks: Array<BlockState?> = arrayOfNulls(Directions.SIZE)
val light = ByteArray(Directions.SIZE + 1) // last index (6) for the current block
val cameraOffset = context.camera.offset.offset
val offsetX = sectionPosition.x * ProtocolDefinition.SECTION_WIDTH_X
val offsetY = sectionPosition.y * ProtocolDefinition.SECTION_HEIGHT_Y
val offsetZ = sectionPosition.z * ProtocolDefinition.SECTION_WIDTH_Z
val offset = BlockPosition.of(sectionPosition)
val floatOffset = FloatArray(3)
@ -88,55 +83,50 @@ class SolidSectionMesher(
for (y in blocks.minPosition.y..blocks.maxPosition.y) {
inSectionPosition = inSectionPosition.with(y = y)
position = position.with(y = offsetY + y)
floatOffset[1] = (position.y - cameraOffset.y).toFloat()
val fastBedrock = y == 0 && isLowestSection && fastBedrock
for (x in blocks.minPosition.x..blocks.maxPosition.x) {
inSectionPosition = inSectionPosition.with(x = x)
position = position.with(x = offsetX + x)
floatOffset[0] = (position.x - cameraOffset.x).toFloat()
for (z in blocks.minPosition.z..blocks.maxPosition.z) {
inSectionPosition = inSectionPosition.with(z = z)
val state = blocks[inSectionPosition] ?: continue
val inSection = InSectionPosition(x, y, z)
val state = blocks[inSection] ?: continue
if (state.block is FluidBlock) continue // fluids are rendered in a different renderer
val model = state.block.model ?: state.model
val blockEntity = section.blockEntities[inSectionPosition]
val blockEntity = section.blockEntities[inSection]
val renderedBlockEntity = blockEntity?.nullCast<RenderedBlockEntity<*>>()
if (model == null && renderedBlockEntity == null) continue
light[SELF_LIGHT_INDEX] = section.light[inSectionPosition]
position = position.with(z = offsetZ + z)
val position = offset + inSection
val inChunk = InChunkPosition(inSection.x, position.y, inSection.z)
floatOffset[0] = (position.x - cameraOffset.x).toFloat()
floatOffset[1] = (position.y - cameraOffset.y).toFloat()
floatOffset[2] = (position.z - cameraOffset.z).toFloat()
val maxHeight = chunk.light.heightmap[inSectionPosition.xz]
if (position.y >= maxHeight) {
light[SELF_LIGHT_INDEX] = (light[SELF_LIGHT_INDEX].toInt() or 0xF0).toByte()
checkDown(state, fastBedrock, inSection, isLowestSection, neighbourBlocks, neighbours, light, section, chunk)
checkUp(isHighestSection, inSection, neighbourBlocks, neighbours, light, section, chunk)
setZ(neighbourBlocks, inChunk, neighbours, light, neighbourChunks, section, chunk)
setX(neighbourBlocks, inChunk, neighbours, light, neighbourChunks, section, chunk)
val maxHeight = chunk.light.heightmap[inSection.xz]
light[SELF_LIGHT_INDEX] = section.light[inSection]
if (position.y > maxHeight) {
light[O_UP] = (light[O_UP].toInt() or SKY_LIGHT_MASK).toByte()
}
if (position.y >= maxHeight) {
light[SELF_LIGHT_INDEX] = (light[SELF_LIGHT_INDEX].toInt() or SKY_LIGHT_MASK).toByte()
}
if (position.y - 1 >= maxHeight) {
light[O_DOWN] = (light[O_DOWN].toInt() or SKY_LIGHT_MASK).toByte()
}
checkDown(state, fastBedrock, inSectionPosition, isLowestSection, neighbourBlocks, neighbours, light, section, chunk)
checkUp(isHighestSection, inSectionPosition, neighbourBlocks, neighbours, light, section, chunk)
setZ(neighbourBlocks, inSectionPosition, neighbours, light, neighbourChunks, section, chunk)
setX(neighbourBlocks, inSectionPosition, neighbours, light, neighbourChunks, section, chunk)
// TODO: cull neighbours
if (position.y - 1 >= maxHeight) {
light[O_UP] = (light[O_UP].toInt() or 0xF0).toByte()
light[O_DOWN] = (light[O_DOWN].toInt() or 0xF0).toByte()
} else if (position.y + 1 >= maxHeight) {
light[O_UP] = (light[O_UP].toInt() or 0xF0).toByte()
}
var offset: Vec3? = null
if (state.block is OffsetBlock) {
offset = state.block.offsetModel(position)
floatOffset[0] += offset.x
floatOffset[1] += offset.y
floatOffset[2] += offset.z
val randomOffset = state.block.offsetModel(position)
floatOffset[0] += randomOffset.x
floatOffset[1] += randomOffset.y
floatOffset[2] += randomOffset.z
}
ao?.clear()
@ -148,12 +138,6 @@ class SolidSectionMesher(
renderedBlockEntity?.getRenderer(context, state, position, light[SELF_LIGHT_INDEX].toInt())?.let { rendered = true; entities += it }
if (offset != null) {
floatOffset[0] -= offset.x
floatOffset[1] -= offset.y
// z is automatically reset
}
if (rendered) {
mesh.addBlock(x, y, z)
}
@ -188,7 +172,7 @@ class SolidSectionMesher(
}
}
private inline fun setZ(neighbourBlocks: Array<BlockState?>, position: InSectionPosition, neighbours: Array<ChunkSection?>, light: ByteArray, neighbourChunks: ChunkNeighbourArray, section: ChunkSection, chunk: Chunk) {
private inline fun setZ(neighbourBlocks: Array<BlockState?>, position: InChunkPosition, neighbours: Array<ChunkSection?>, light: ByteArray, neighbourChunks: ChunkNeighbourArray, section: ChunkSection, chunk: Chunk) {
if (position.z == 0) {
setNeighbour(neighbourBlocks, position.with(z = ProtocolDefinition.SECTION_MAX_Z), light, neighbours[O_NORTH], neighbourChunks[Directions.NORTH], O_NORTH)
setNeighbour(neighbourBlocks, position.plusZ(), light, section, chunk, O_SOUTH)
@ -202,7 +186,7 @@ class SolidSectionMesher(
}
private inline fun setX(neighbourBlocks: Array<BlockState?>, position: InSectionPosition, neighbours: Array<ChunkSection?>, light: ByteArray, neighbourChunks: ChunkNeighbourArray, section: ChunkSection, chunk: Chunk) {
private inline fun setX(neighbourBlocks: Array<BlockState?>, position: InChunkPosition, neighbours: Array<ChunkSection?>, light: ByteArray, neighbourChunks: ChunkNeighbourArray, section: ChunkSection, chunk: Chunk) {
if (position.x == 0) {
setNeighbour(neighbourBlocks, position.with(x = ProtocolDefinition.SECTION_MAX_X), light, neighbours[O_WEST], neighbourChunks[Directions.WEST], O_WEST)
setNeighbour(neighbourBlocks, position.plusX(), light, section, chunk, O_EAST)
@ -215,11 +199,12 @@ class SolidSectionMesher(
}
}
private inline fun setNeighbour(blocks: Array<BlockState?>, position: InSectionPosition, light: ByteArray, section: ChunkSection?, chunk: Chunk?, direction: Int) {
blocks[direction] = section?.blocks?.let { it[position] }
var level = section?.light?.get(position) ?: 0x00
private inline fun setNeighbour(blocks: Array<BlockState?>, position: InChunkPosition, light: ByteArray, section: ChunkSection?, chunk: Chunk?, direction: Int) {
val inSection = position.inSectionPosition
blocks[direction] = section?.blocks?.let { it[inSection] }
var level = section?.light?.get(inSection) ?: 0x00
if (chunk != null && position.y >= chunk.light.heightmap[position.xz]) {
level = (level.toInt() or SectionLight.SKY_LIGHT_MASK).toByte() // set sky light to 0x0F
level = (level.toInt() or SKY_LIGHT_MASK).toByte() // set sky light to 0x0F
}
light[direction] = level
}