multiple entity render layers

This commit is contained in:
Moritz Zwerger 2023-11-08 14:55:34 +01:00
parent 0a2a92cdfe
commit 15b0d653d7
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 65 additions and 24 deletions

View File

@ -18,16 +18,15 @@ import de.bixilon.kutil.latch.AbstractLatch
import de.bixilon.kutil.observer.DataObserver.Companion.observe import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.kutil.time.TimeUtil.millis
import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.entities.feature.EntityRenderFeature
import de.bixilon.minosoft.gui.rendering.entities.feature.register.EntityRenderFeatures import de.bixilon.minosoft.gui.rendering.entities.feature.register.EntityRenderFeatures
import de.bixilon.minosoft.gui.rendering.entities.visibility.EntityLayer
import de.bixilon.minosoft.gui.rendering.entities.visibility.VisibilityManager import de.bixilon.minosoft.gui.rendering.entities.visibility.VisibilityManager
import de.bixilon.minosoft.gui.rendering.renderer.renderer.AsyncRenderer import de.bixilon.minosoft.gui.rendering.renderer.renderer.AsyncRenderer
import de.bixilon.minosoft.gui.rendering.renderer.renderer.RendererBuilder import de.bixilon.minosoft.gui.rendering.renderer.renderer.RendererBuilder
import de.bixilon.minosoft.gui.rendering.renderer.renderer.world.LayerSettings import de.bixilon.minosoft.gui.rendering.renderer.renderer.world.LayerSettings
import de.bixilon.minosoft.gui.rendering.renderer.renderer.world.WorldRenderer import de.bixilon.minosoft.gui.rendering.renderer.renderer.world.WorldRenderer
import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.layer.RenderLayer
import de.bixilon.minosoft.gui.rendering.system.base.layer.TranslucentLayer
import de.bixilon.minosoft.gui.rendering.system.base.settings.RenderSettings
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
class EntitiesRenderer( class EntitiesRenderer(
@ -47,7 +46,8 @@ class EntitiesRenderer(
private var reset = false private var reset = false
override fun registerLayers() { override fun registerLayers() {
layers.register(EntityLayer, null, this::draw) { visibility.size <= 0 } layers.register(EntityLayer.OpaqueEntityLayer, null, { visibility.opaque.draw() }) { visibility.opaque.size <= 0 }
layers.register(EntityLayer.TranslucentEntityLayer, null, { visibility.translucent.draw() }) { visibility.opaque.size <= 0 }
} }
override fun prePrepareDraw() { override fun prePrepareDraw() {
@ -83,18 +83,12 @@ class EntitiesRenderer(
features.postInit() features.postInit()
} }
private fun draw() { private fun ArrayList<EntityRenderFeature>.draw() {
for (feature in visibility) { for (feature in this) {
feature.draw() feature.draw()
} }
} }
object EntityLayer : RenderLayer {
override val settings = RenderSettings(faceCulling = false)
override val priority: Int get() = TranslucentLayer.priority - 1
}
companion object : RendererBuilder<EntitiesRenderer> { companion object : RendererBuilder<EntitiesRenderer> {
override fun build(connection: PlayConnection, context: RenderContext): EntitiesRenderer { override fun build(connection: PlayConnection, context: RenderContext): EntitiesRenderer {

View File

@ -14,6 +14,8 @@
package de.bixilon.minosoft.gui.rendering.entities.feature package de.bixilon.minosoft.gui.rendering.entities.feature
import de.bixilon.minosoft.gui.rendering.entities.renderer.EntityRenderer import de.bixilon.minosoft.gui.rendering.entities.renderer.EntityRenderer
import de.bixilon.minosoft.gui.rendering.entities.visibility.EntityLayer
import de.bixilon.minosoft.gui.rendering.entities.visibility.VisibilityManager
abstract class EntityRenderFeature(val renderer: EntityRenderer<*>) : Comparable<EntityRenderFeature> { abstract class EntityRenderFeature(val renderer: EntityRenderer<*>) : Comparable<EntityRenderFeature> {
open var enabled = true open var enabled = true
@ -21,6 +23,8 @@ abstract class EntityRenderFeature(val renderer: EntityRenderer<*>) : Comparable
open val priority: Int get() = 0 open val priority: Int get() = 0
val sort = this::class.java.hashCode() val sort = this::class.java.hashCode()
open val layer: EntityLayer get() = EntityLayer.OpaqueEntityLayer
open fun updateVisibility(occluded: Boolean) { open fun updateVisibility(occluded: Boolean) {
this.visible = !occluded this.visible = !occluded
} }
@ -32,7 +36,9 @@ abstract class EntityRenderFeature(val renderer: EntityRenderer<*>) : Comparable
abstract fun draw() abstract fun draw()
open fun compareByDistance(other: EntityRenderFeature): Int { open fun compareByDistance(other: EntityRenderFeature): Int {
return renderer.distance.compareTo(other.renderer.distance) val compared = renderer.distance.compareTo(other.renderer.distance)
if (layer === EntityLayer.TranslucentEntityLayer) return -compared // translucent is sorted the exact other way
return compared
} }
override fun compareTo(other: EntityRenderFeature): Int { override fun compareTo(other: EntityRenderFeature): Int {
@ -43,4 +49,8 @@ abstract class EntityRenderFeature(val renderer: EntityRenderer<*>) : Comparable
return compareByDistance(other) return compareByDistance(other)
} }
open fun collect(visibility: VisibilityManager) {
visibility[layer] += this
}
} }

View File

@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.entities.feature.EntityRenderFeature import de.bixilon.minosoft.gui.rendering.entities.feature.EntityRenderFeature
import de.bixilon.minosoft.gui.rendering.entities.renderer.EntityRenderer import de.bixilon.minosoft.gui.rendering.entities.renderer.EntityRenderer
import de.bixilon.minosoft.gui.rendering.entities.visibility.EntityLayer
import de.bixilon.minosoft.gui.rendering.font.renderer.component.ChatComponentRenderer import de.bixilon.minosoft.gui.rendering.font.renderer.component.ChatComponentRenderer
import de.bixilon.minosoft.gui.rendering.font.renderer.element.CharSpacing import de.bixilon.minosoft.gui.rendering.font.renderer.element.CharSpacing
import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderInfo import de.bixilon.minosoft.gui.rendering.font.renderer.element.TextRenderInfo
@ -57,6 +58,8 @@ open class BillboardTextFeature(
unload() // TODO: just update matrix unload() // TODO: just update matrix
} }
override val layer get() = EntityLayer.TranslucentEntityLayer
override fun update(millis: Long, delta: Float) { override fun update(millis: Long, delta: Float) {
if (!super.enabled) return unload() if (!super.enabled) return unload()
if (!isInRenderDistance()) return unload() if (!isInRenderDistance()) return unload()
@ -122,10 +125,6 @@ open class BillboardTextFeature(
renderer.renderer.queue += { mesh.unload() } renderer.renderer.queue += { mesh.unload() }
} }
override fun compareByDistance(other: EntityRenderFeature): Int {
return -super.compareByDistance(other)
}
companion object { companion object {
val PROPERTIES = TextRenderProperties(allowNewLine = false, shadow = false, charSpacing = CharSpacing(top = 1.0f, bottom = 1.0f)) val PROPERTIES = TextRenderProperties(allowNewLine = false, shadow = false, charSpacing = CharSpacing(top = 1.0f, bottom = 1.0f))
val MAX_SIZE = Vec2(300.0f, PROPERTIES.lineHeight) val MAX_SIZE = Vec2(300.0f, PROPERTIES.lineHeight)

View File

@ -0,0 +1,32 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.entities.visibility
import de.bixilon.minosoft.gui.rendering.system.base.layer.OpaqueLayer
import de.bixilon.minosoft.gui.rendering.system.base.layer.RenderLayer
import de.bixilon.minosoft.gui.rendering.system.base.layer.TranslucentLayer
import de.bixilon.minosoft.gui.rendering.system.base.settings.RenderSettings
interface EntityLayer : RenderLayer {
object OpaqueEntityLayer : EntityLayer {
override val settings = RenderSettings(faceCulling = false)
override val priority: Int get() = OpaqueLayer.priority + 1 // entities are mostly more expensive to render, let the gpu clip all fragments first
}
object TranslucentEntityLayer : EntityLayer {
override val settings = RenderSettings(faceCulling = false)
override val priority: Int get() = TranslucentLayer.priority - 1 // otherwise not visible through water, etc
}
}

View File

@ -21,13 +21,14 @@ import de.bixilon.minosoft.gui.rendering.events.VisibilityGraphChangeEvent
import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
class VisibilityManager(val renderer: EntitiesRenderer) : Iterable<EntityRenderFeature> { class VisibilityManager(val renderer: EntitiesRenderer) {
private var update = false private var update = false
var size: Int = 0 var size: Int = 0
private set private set
private val count = AtomicInteger() private val count = AtomicInteger()
private val visible: ArrayList<EntityRenderFeature> = ArrayList(1000) val opaque: ArrayList<EntityRenderFeature> = ArrayList(1000)
val translucent: ArrayList<EntityRenderFeature> = ArrayList(1000)
private val lock = SimpleLock() private val lock = SimpleLock()
private val graph = renderer.context.camera.visibilityGraph private val graph = renderer.context.camera.visibilityGraph
private val frustum = renderer.context.camera.matrixHandler.frustum private val frustum = renderer.context.camera.matrixHandler.frustum
@ -37,7 +38,8 @@ class VisibilityManager(val renderer: EntitiesRenderer) : Iterable<EntityRenderF
} }
fun reset() { fun reset() {
this.visible.clear() opaque.clear()
translucent.clear()
count.set(0) count.set(0)
} }
@ -59,18 +61,22 @@ class VisibilityManager(val renderer: EntitiesRenderer) : Iterable<EntityRenderF
lock.lock() lock.lock()
for (feature in renderer.features) { for (feature in renderer.features) {
if (!feature.enabled || !feature.visible) continue if (!feature.enabled || !feature.visible) continue
this.visible += feature feature.collect(this)
} }
lock.unlock() lock.unlock()
} }
fun finish() { fun finish() {
this.visible.sort() // TODO: Optimize it (pre create array, just work with array?) // TODO: Optimize it (pre create array, just work with array?)
this.opaque.sort()
this.translucent.sort()
this.update = false this.update = false
size = count.get() size = count.get()
} }
override fun iterator(): Iterator<EntityRenderFeature> { operator fun get(layer: EntityLayer) = when (layer) {
return this.visible.iterator() EntityLayer.OpaqueEntityLayer -> opaque
EntityLayer.TranslucentEntityLayer -> translucent
else -> throw IllegalStateException("Unknown entity layer: $layer")
} }
} }