mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-13 01:16:46 -04:00
world-renderer: split visible meshes, sort them
This commit is contained in:
parent
dcb058c960
commit
611f55fd82
@ -48,7 +48,7 @@ object RenderConstants {
|
|||||||
const val FRUSTUM_CULLING_ENABLED = true
|
const val FRUSTUM_CULLING_ENABLED = true
|
||||||
const val SHOW_FPS_IN_WINDOW_TITLE = 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
|
const val DISABLE_LIGHTING = false
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import de.bixilon.minosoft.data.world.World
|
|||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
import de.bixilon.minosoft.gui.rendering.Renderer
|
import de.bixilon.minosoft.gui.rendering.Renderer
|
||||||
import de.bixilon.minosoft.gui.rendering.RendererBuilder
|
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.mesh.ChunkSectionMeshes
|
||||||
import de.bixilon.minosoft.gui.rendering.block.preparer.AbstractSectionPreparer
|
import de.bixilon.minosoft.gui.rendering.block.preparer.AbstractSectionPreparer
|
||||||
import de.bixilon.minosoft.gui.rendering.block.preparer.GenericSectionPreparer
|
import de.bixilon.minosoft.gui.rendering.block.preparer.GenericSectionPreparer
|
||||||
@ -67,19 +68,20 @@ class WorldRenderer(
|
|||||||
private val sectionPreparer: AbstractSectionPreparer = GenericSectionPreparer(renderWindow)
|
private val sectionPreparer: AbstractSectionPreparer = GenericSectionPreparer(renderWindow)
|
||||||
private val lightMap = LightMap(connection)
|
private val lightMap = LightMap(connection)
|
||||||
private val meshes: SynchronizedMap<Vec2i, SynchronizedMap<Int, ChunkSectionMeshes>> = synchronizedMapOf() // all prepared (and up to date) meshes
|
private val meshes: SynchronizedMap<Vec2i, SynchronizedMap<Int, ChunkSectionMeshes>> = synchronizedMapOf() // all prepared (and up to date) meshes
|
||||||
private var visibleMeshes: MutableSet<ChunkSectionMeshes> = mutableSetOf() // ToDo: Split in opaque, transparent, translucent meshes and sort (opaque and transparent front to back, translucent back to front)
|
|
||||||
private var incomplete: MutableSet<Vec2i> = synchronizedSetOf() // Queue of chunk positions that can not be rendered yet (data not complete or neighbours not completed yet)
|
private var incomplete: MutableSet<Vec2i> = synchronizedSetOf() // Queue of chunk positions that can not be rendered yet (data not complete or neighbours not completed yet)
|
||||||
private var queue: MutableMap<Vec2i, MutableSet<Int>> = synchronizedMapOf() // Chunk sections that can be prepared or have changed, but are not required to get rendered yet (i.e. culled chunks)
|
private var queue: MutableMap<Vec2i, MutableSet<Int>> = 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<ChunkSectionMesh> = mutableListOf()
|
||||||
|
private var visibleTranslucent: MutableList<ChunkSectionMesh> = mutableListOf()
|
||||||
|
private var visibleTransparent: MutableList<ChunkSectionMesh> = mutableListOf()
|
||||||
|
|
||||||
val visibleSize: Int
|
|
||||||
get() = visibleMeshes.size
|
val visibleOpaqueSize: Int by visibleOpaque::size
|
||||||
val preparedSize: Int
|
val visibleTranslucentSize: Int by visibleTranslucent::size
|
||||||
get() = meshes.size
|
val visibleTransparentSize: Int by visibleTransparent::size
|
||||||
val queuedSize: Int
|
val preparedSize: Int by meshes::size
|
||||||
get() = queue.size
|
val queuedSize: Int by queue::size
|
||||||
val incompleteSize: Int
|
val incompleteSize: Int by incomplete::size
|
||||||
get() = incomplete.size
|
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
val asset = Resources.getAssetVersionByVersion(connection.version)
|
val asset = Resources.getAssetVersionByVersion(connection.version)
|
||||||
@ -136,17 +138,29 @@ class WorldRenderer(
|
|||||||
incomplete += neighbourPosition
|
incomplete += neighbourPosition
|
||||||
}
|
}
|
||||||
val meshes = this.meshes.remove(chunkPosition) ?: return
|
val meshes = this.meshes.remove(chunkPosition) ?: return
|
||||||
visibleMeshes -= meshes.values
|
|
||||||
if (meshes.isEmpty()) {
|
if (meshes.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
renderWindow.queue += {
|
renderWindow.queue += {
|
||||||
for (mesh in meshes.values) {
|
for (mesh in meshes.values) {
|
||||||
|
removeMesh(mesh)
|
||||||
mesh.unload()
|
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
|
* @return All 8 fully loaded neighbour chunks or null
|
||||||
*/
|
*/
|
||||||
@ -186,7 +200,7 @@ class WorldRenderer(
|
|||||||
neighbourChunks[3].sections!![sectionHeight],
|
neighbourChunks[3].sections!![sectionHeight],
|
||||||
neighbourChunks[4].sections!![sectionHeight],
|
neighbourChunks[4].sections!![sectionHeight],
|
||||||
neighbourChunks[1].sections!![sectionHeight],
|
neighbourChunks[1].sections!![sectionHeight],
|
||||||
neighbourChunks[7].sections!![sectionHeight],
|
neighbourChunks[6].sections!![sectionHeight],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +267,7 @@ class WorldRenderer(
|
|||||||
if (previousMesh != null && !visible) {
|
if (previousMesh != null && !visible) {
|
||||||
meshes.remove(sectionHeight)
|
meshes.remove(sectionHeight)
|
||||||
renderWindow.queue += {
|
renderWindow.queue += {
|
||||||
visibleMeshes -= previousMesh
|
removeMesh(previousMesh)
|
||||||
previousMesh.unload()
|
previousMesh.unload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,18 +295,17 @@ class WorldRenderer(
|
|||||||
private fun prepareSection(chunkPosition: Vec2i, sectionHeight: Int, section: ChunkSection, neighbours: Array<ChunkSection?>, meshes: SynchronizedMap<Int, ChunkSectionMeshes> = this.meshes.getOrPut(chunkPosition) { synchronizedMapOf() }) {
|
private fun prepareSection(chunkPosition: Vec2i, sectionHeight: Int, section: ChunkSection, neighbours: Array<ChunkSection?>, meshes: SynchronizedMap<Int, ChunkSectionMeshes> = this.meshes.getOrPut(chunkPosition) { synchronizedMapOf() }) {
|
||||||
val mesh = sectionPreparer.prepare(chunkPosition, sectionHeight, section, neighbours)
|
val mesh = sectionPreparer.prepare(chunkPosition, sectionHeight, section, neighbours)
|
||||||
|
|
||||||
val currentMesh = meshes.remove(sectionHeight)
|
val previousMesh = meshes.remove(sectionHeight)
|
||||||
|
|
||||||
renderWindow.queue += {
|
renderWindow.queue += {
|
||||||
if (currentMesh != null) {
|
if (previousMesh != null) {
|
||||||
currentMesh.unload()
|
removeMesh(previousMesh)
|
||||||
this.visibleMeshes -= currentMesh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh.load()
|
mesh.load()
|
||||||
meshes[sectionHeight] = mesh
|
meshes[sectionHeight] = mesh
|
||||||
if (isChunkVisible(chunkPosition, sectionHeight, mesh.minPosition, mesh.maxPosition)) {
|
if (isChunkVisible(chunkPosition, sectionHeight, mesh.minPosition, mesh.maxPosition)) {
|
||||||
this.visibleMeshes += mesh
|
addMesh(mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,8 +316,8 @@ class WorldRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun drawOpaque() {
|
override fun drawOpaque() {
|
||||||
for (mesh in visibleMeshes) {
|
for (mesh in visibleOpaque) {
|
||||||
mesh.opaqueMesh?.draw()
|
mesh.draw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,8 +327,8 @@ class WorldRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun drawTranslucent() {
|
override fun drawTranslucent() {
|
||||||
for (mesh in visibleMeshes) {
|
for (mesh in visibleTranslucent) {
|
||||||
mesh.translucentMesh?.draw()
|
mesh.draw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,8 +338,8 @@ class WorldRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun drawTransparent() {
|
override fun drawTransparent() {
|
||||||
for (mesh in visibleMeshes) {
|
for (mesh in visibleTransparent) {
|
||||||
mesh.transparentMesh?.draw()
|
mesh.draw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,14 +349,18 @@ class WorldRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onFrustumChange() {
|
private fun onFrustumChange() {
|
||||||
val visible: MutableSet<ChunkSectionMeshes> = mutableSetOf()
|
val visibleOpaque: MutableList<ChunkSectionMesh> = mutableListOf()
|
||||||
|
val visibleTranslucent: MutableList<ChunkSectionMesh> = mutableListOf()
|
||||||
|
val visibleTransparent: MutableList<ChunkSectionMesh> = mutableListOf()
|
||||||
|
|
||||||
for ((chunkPosition, meshes) in this.meshes.toSynchronizedMap()) {
|
for ((chunkPosition, meshes) in this.meshes.toSynchronizedMap()) {
|
||||||
for ((sectionHeight, mesh) in meshes) {
|
for ((sectionHeight, mesh) in meshes) {
|
||||||
if (!isChunkVisible(chunkPosition, sectionHeight, mesh.minPosition, mesh.maxPosition)) {
|
if (!isChunkVisible(chunkPosition, sectionHeight, mesh.minPosition, mesh.maxPosition)) {
|
||||||
continue
|
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)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct
|
|||||||
import glm_.vec2.Vec2
|
import glm_.vec2.Vec2
|
||||||
import glm_.vec3.Vec3
|
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) {
|
fun addVertex(position: FloatArray, uv: Vec2, texture: AbstractTexture, tintColor: Int, light: Int) {
|
||||||
val transformedUV = texture.renderData?.transformUV(uv) ?: uv
|
val transformedUV = texture.renderData?.transformUV(uv) ?: uv
|
||||||
|
@ -14,16 +14,22 @@
|
|||||||
package de.bixilon.minosoft.gui.rendering.block.mesh
|
package de.bixilon.minosoft.gui.rendering.block.mesh
|
||||||
|
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
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
|
import glm_.vec3.Vec3i
|
||||||
|
|
||||||
class ChunkSectionMeshes(
|
class ChunkSectionMeshes(
|
||||||
renderWindow: RenderWindow,
|
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
|
private set
|
||||||
var translucentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow)
|
var translucentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow, 100000, centerLength)
|
||||||
private set
|
private set
|
||||||
var transparentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow)
|
var transparentMesh: ChunkSectionMesh? = ChunkSectionMesh(renderWindow, 100000, centerLength)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
// used for frustum culling
|
// used for frustum culling
|
||||||
|
@ -16,7 +16,7 @@ class CullSectionPreparer(
|
|||||||
) : AbstractSectionPreparer {
|
) : AbstractSectionPreparer {
|
||||||
|
|
||||||
override fun prepare(chunkPosition: Vec2i, sectionHeight: Int, section: ChunkSection, neighbours: Array<ChunkSection?>): ChunkSectionMeshes {
|
override fun prepare(chunkPosition: Vec2i, sectionHeight: Int, section: ChunkSection, neighbours: Array<ChunkSection?>): ChunkSectionMeshes {
|
||||||
val mesh = ChunkSectionMeshes(renderWindow)
|
val mesh = ChunkSectionMeshes(renderWindow, chunkPosition, sectionHeight)
|
||||||
val random = Random(0L)
|
val random = Random(0L)
|
||||||
|
|
||||||
val blocks = section.blocks
|
val blocks = section.blocks
|
||||||
|
@ -37,8 +37,9 @@ class GreedySectionPreparer(
|
|||||||
|
|
||||||
|
|
||||||
// base taken from https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/
|
// 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<ChunkSection?>): ChunkSectionMeshes {
|
override fun prepare(chunkPosition: Vec2i, sectionHeight: Int, section: ChunkSection, neighbours: Array<ChunkSection?>): ChunkSectionMeshes {
|
||||||
val mesh = ChunkSectionMesh(renderWindow)
|
val mesh = ChunkSectionMesh(renderWindow, 20000, 0.0)
|
||||||
|
|
||||||
val random = Random(0L)
|
val random = Random(0L)
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class DebugHUDElement(hudRenderer: HUDRenderer) : LayoutedHUDElement<GridLayout>
|
|||||||
layout += TextElement(hudRenderer, TextComponent(RunConfiguration.VERSION_STRING, ChatColors.RED))
|
layout += TextElement(hudRenderer, TextComponent(RunConfiguration.VERSION_STRING, ChatColors.RED))
|
||||||
layout += AutoTextElement(hudRenderer, 1) { "FPS ${renderWindow.renderStats.smoothAvgFPS.round10}" }
|
layout += AutoTextElement(hudRenderer, 1) { "FPS ${renderWindow.renderStats.smoothAvgFPS.round10}" }
|
||||||
renderWindow[WorldRenderer]?.apply {
|
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}" }
|
layout += AutoTextElement(hudRenderer, 1) { "E t=${connection.world.entities.size}" }
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class Camera(
|
|||||||
val renderWindow: RenderWindow,
|
val renderWindow: RenderWindow,
|
||||||
) {
|
) {
|
||||||
var fogColor = Previous(ChatColors.GREEN)
|
var fogColor = Previous(ChatColors.GREEN)
|
||||||
var fogStart = 1000.0f
|
var fogStart = 100.0f
|
||||||
private var mouseSensitivity = Minosoft.config.config.game.controls.moseSensitivity
|
private var mouseSensitivity = Minosoft.config.config.game.controls.moseSensitivity
|
||||||
|
|
||||||
@Deprecated("", ReplaceWith("connection.player"))
|
@Deprecated("", ReplaceWith("connection.player"))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user