diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt index b206fce5c..a3e3dcd50 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt @@ -48,7 +48,7 @@ object RenderConstants { const val FRUSTUM_CULLING_ENABLED = true const val SHOW_FPS_IN_WINDOW_TITLE = true - const val MAXIMUM_QUEUE_TIME_PER_FRAME = 100L + const val MAXIMUM_QUEUE_TIME_PER_FRAME = 20L const val DISABLE_LIGHTING = false diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt index fc7f7e50a..9652eeead 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt @@ -22,6 +22,7 @@ import de.bixilon.minosoft.data.world.World import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder +import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshes import de.bixilon.minosoft.gui.rendering.block.preparer.AbstractSectionPreparer import de.bixilon.minosoft.gui.rendering.block.preparer.GenericSectionPreparer @@ -67,19 +68,20 @@ class WorldRenderer( private val sectionPreparer: AbstractSectionPreparer = GenericSectionPreparer(renderWindow) private val lightMap = LightMap(connection) private val meshes: SynchronizedMap> = synchronizedMapOf() // all prepared (and up to date) meshes - private var visibleMeshes: MutableSet = mutableSetOf() // ToDo: Split in opaque, transparent, translucent meshes and sort (opaque and transparent front to back, translucent back to front) private var incomplete: MutableSet = synchronizedSetOf() // Queue of chunk positions that can not be rendered yet (data not complete or neighbours not completed yet) private var queue: MutableMap> = synchronizedMapOf() // Chunk sections that can be prepared or have changed, but are not required to get rendered yet (i.e. culled chunks) + private var visibleOpaque: MutableList = mutableListOf() + private var visibleTranslucent: MutableList = mutableListOf() + private var visibleTransparent: MutableList = mutableListOf() - val visibleSize: Int - get() = visibleMeshes.size - val preparedSize: Int - get() = meshes.size - val queuedSize: Int - get() = queue.size - val incompleteSize: Int - get() = incomplete.size + + val visibleOpaqueSize: Int by visibleOpaque::size + val visibleTranslucentSize: Int by visibleTranslucent::size + val visibleTransparentSize: Int by visibleTransparent::size + val preparedSize: Int by meshes::size + val queuedSize: Int by queue::size + val incompleteSize: Int by incomplete::size override fun init() { val asset = Resources.getAssetVersionByVersion(connection.version) @@ -136,17 +138,29 @@ class WorldRenderer( incomplete += neighbourPosition } val meshes = this.meshes.remove(chunkPosition) ?: return - visibleMeshes -= meshes.values if (meshes.isEmpty()) { return } renderWindow.queue += { for (mesh in meshes.values) { + removeMesh(mesh) mesh.unload() } } } + private fun removeMesh(mesh: ChunkSectionMeshes) { + mesh.opaqueMesh?.let { visibleOpaque -= it } + mesh.translucentMesh?.let { visibleTranslucent -= it } + mesh.transparentMesh?.let { visibleTransparent -= it } + } + + private fun addMesh(mesh: ChunkSectionMeshes) { + mesh.opaqueMesh?.let { visibleOpaque += it } + mesh.translucentMesh?.let { visibleTranslucent += it } + mesh.transparentMesh?.let { visibleTransparent += it } + } + /** * @return All 8 fully loaded neighbour chunks or null */ @@ -186,7 +200,7 @@ class WorldRenderer( neighbourChunks[3].sections!![sectionHeight], neighbourChunks[4].sections!![sectionHeight], neighbourChunks[1].sections!![sectionHeight], - neighbourChunks[7].sections!![sectionHeight], + neighbourChunks[6].sections!![sectionHeight], ) } @@ -253,7 +267,7 @@ class WorldRenderer( if (previousMesh != null && !visible) { meshes.remove(sectionHeight) renderWindow.queue += { - visibleMeshes -= previousMesh + removeMesh(previousMesh) previousMesh.unload() } } @@ -281,18 +295,17 @@ class WorldRenderer( private fun prepareSection(chunkPosition: Vec2i, sectionHeight: Int, section: ChunkSection, neighbours: Array, meshes: SynchronizedMap = this.meshes.getOrPut(chunkPosition) { synchronizedMapOf() }) { val mesh = sectionPreparer.prepare(chunkPosition, sectionHeight, section, neighbours) - val currentMesh = meshes.remove(sectionHeight) + val previousMesh = meshes.remove(sectionHeight) renderWindow.queue += { - if (currentMesh != null) { - currentMesh.unload() - this.visibleMeshes -= currentMesh + if (previousMesh != null) { + removeMesh(previousMesh) } mesh.load() meshes[sectionHeight] = mesh if (isChunkVisible(chunkPosition, sectionHeight, mesh.minPosition, mesh.maxPosition)) { - this.visibleMeshes += mesh + addMesh(mesh) } } } @@ -303,8 +316,8 @@ class WorldRenderer( } override fun drawOpaque() { - for (mesh in visibleMeshes) { - mesh.opaqueMesh?.draw() + for (mesh in visibleOpaque) { + mesh.draw() } } @@ -314,8 +327,8 @@ class WorldRenderer( } override fun drawTranslucent() { - for (mesh in visibleMeshes) { - mesh.translucentMesh?.draw() + for (mesh in visibleTranslucent) { + mesh.draw() } } @@ -325,8 +338,8 @@ class WorldRenderer( } override fun drawTransparent() { - for (mesh in visibleMeshes) { - mesh.transparentMesh?.draw() + for (mesh in visibleTransparent) { + mesh.draw() } } @@ -336,14 +349,18 @@ class WorldRenderer( } private fun onFrustumChange() { - val visible: MutableSet = mutableSetOf() + val visibleOpaque: MutableList = mutableListOf() + val visibleTranslucent: MutableList = mutableListOf() + val visibleTransparent: MutableList = mutableListOf() for ((chunkPosition, meshes) in this.meshes.toSynchronizedMap()) { for ((sectionHeight, mesh) in meshes) { if (!isChunkVisible(chunkPosition, sectionHeight, mesh.minPosition, mesh.maxPosition)) { continue } - visible += mesh + mesh.opaqueMesh?.let { visibleOpaque += it } + mesh.translucentMesh?.let { visibleTranslucent += it } + mesh.transparentMesh?.let { visibleTransparent += it } } } @@ -359,8 +376,16 @@ class WorldRenderer( updateSection(chunkPosition, sectionHeight, chunk, neighbours.unsafeCast(), meshes) } } + val cameraPositionLength = connection.player.cameraPosition.length2() - this.visibleMeshes = visible + visibleOpaque.sortBy { it.centerLength - cameraPositionLength } + this.visibleOpaque = visibleOpaque + + visibleTranslucent.sortBy { cameraPositionLength - it.centerLength } + this.visibleTranslucent = visibleTranslucent + + visibleTransparent.sortBy { it.centerLength - cameraPositionLength } + this.visibleTransparent = visibleTransparent } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/block/mesh/ChunkSectionMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/block/mesh/ChunkSectionMesh.kt index 5874f00e4..2c386620d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/block/mesh/ChunkSectionMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/block/mesh/ChunkSectionMesh.kt @@ -22,7 +22,7 @@ import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct import glm_.vec2.Vec2 import glm_.vec3.Vec3 -class ChunkSectionMesh(renderWindow: RenderWindow) : Mesh(renderWindow, SectionArrayMeshStruct, PrimitiveTypes.QUAD, initialCacheSize = 200000) { +class ChunkSectionMesh(renderWindow: RenderWindow, initialCacheSize: Int, val centerLength: Double) : Mesh(renderWindow, SectionArrayMeshStruct, PrimitiveTypes.QUAD, initialCacheSize = initialCacheSize) { fun addVertex(position: FloatArray, uv: Vec2, texture: AbstractTexture, tintColor: Int, light: Int) { val transformedUV = texture.renderData?.transformUV(uv) ?: uv diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/block/mesh/ChunkSectionMeshes.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/block/mesh/ChunkSectionMeshes.kt index 68bca427e..52333b434 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/block/mesh/ChunkSectionMeshes.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/block/mesh/ChunkSectionMeshes.kt @@ -14,16 +14,22 @@ package de.bixilon.minosoft.gui.rendering.block.mesh import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.util.VecUtil.of +import glm_.vec2.Vec2i +import glm_.vec3.Vec3d import glm_.vec3.Vec3i class ChunkSectionMeshes( renderWindow: RenderWindow, + chunkPosition: Vec2i, + sectionHeight: Int, ) { - var opaqueMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow) + private val centerLength = Vec3d(Vec3i.of(chunkPosition, sectionHeight, Vec3i(8, 8, 8))).length2() + var opaqueMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow, 200000, centerLength) private set - var translucentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow) + var translucentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow, 100000, centerLength) private set - var transparentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow) + var transparentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow, 100000, centerLength) private set // used for frustum culling diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/CullSectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/CullSectionPreparer.kt index 08fd01676..d78c822c9 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/CullSectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/CullSectionPreparer.kt @@ -16,7 +16,7 @@ class CullSectionPreparer( ) : AbstractSectionPreparer { override fun prepare(chunkPosition: Vec2i, sectionHeight: Int, section: ChunkSection, neighbours: Array): ChunkSectionMeshes { - val mesh = ChunkSectionMeshes(renderWindow) + val mesh = ChunkSectionMeshes(renderWindow, chunkPosition, sectionHeight) val random = Random(0L) val blocks = section.blocks diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/GreedySectionPreparer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/GreedySectionPreparer.kt index d0a9f23c5..700a7749c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/GreedySectionPreparer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/block/preparer/GreedySectionPreparer.kt @@ -37,8 +37,9 @@ class GreedySectionPreparer( // base taken from https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/ + @Deprecated("TODO") override fun prepare(chunkPosition: Vec2i, sectionHeight: Int, section: ChunkSection, neighbours: Array): ChunkSectionMeshes { - val mesh = ChunkSectionMesh(renderWindow) + val mesh = ChunkSectionMesh(renderWindow, 20000, 0.0) val random = Random(0L) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/DebugHUDElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/DebugHUDElement.kt index 8caaaa85d..dd1ab4656 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/DebugHUDElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/other/DebugHUDElement.kt @@ -85,7 +85,7 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement layout += TextElement(hudRenderer, TextComponent(RunConfiguration.VERSION_STRING, ChatColors.RED)) layout += AutoTextElement(hudRenderer, 1) { "FPS ${renderWindow.renderStats.smoothAvgFPS.round10}" } renderWindow[WorldRenderer]?.apply { - layout += AutoTextElement(hudRenderer, 1) { "C v=$visibleSize, p=$preparedSize, q=$queuedSize, i=$incompleteSize, t=${connection.world.chunks.size}" } + layout += AutoTextElement(hudRenderer, 1) { "C vO=$visibleOpaqueSize, vP=$visibleTransparentSize, vL=$visibleTranslucentSize, p=$preparedSize, q=$queuedSize, i=$incompleteSize, t=${connection.world.chunks.size}" } } layout += AutoTextElement(hudRenderer, 1) { "E t=${connection.world.entities.size}" } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt index 5291b09a5..d3598260c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt @@ -59,7 +59,7 @@ class Camera( val renderWindow: RenderWindow, ) { var fogColor = Previous(ChatColors.GREEN) - var fogStart = 1000.0f + var fogStart = 100.0f private var mouseSensitivity = Minosoft.config.config.game.controls.moseSensitivity @Deprecated("", ReplaceWith("connection.player"))