mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 01:48:04 -04:00
rendering: improve frustum culling code, cull chunks at y axis
This commit is contained in:
parent
a695a7e027
commit
7bd34f85fa
@ -47,7 +47,7 @@ object KeyBindingsNames {
|
||||
|
||||
val TOGGLE_DEBUG_SCREEN = ResourceLocation("minosoft:toggle_debug_screen")
|
||||
val DEBUG_CLEAR_CHUNK_CACHE = ResourceLocation("minosoft:debug_clear_chunk_cache")
|
||||
val DEBUG_POLYGEN = ResourceLocation("minosoft:debug_polygen")
|
||||
val DEBUG_POLYGON = ResourceLocation("minosoft:debug_polygon")
|
||||
val DEBUG_MOUSE_CATCH = ResourceLocation("minosoft:debug_mouse_catch")
|
||||
|
||||
val WHEN_IN_GAME = ResourceLocation("minosoft:in_game")
|
||||
@ -124,7 +124,7 @@ object KeyBindingsNames {
|
||||
),
|
||||
mutableSetOf(mutableSetOf(WHEN_IN_GAME))
|
||||
),
|
||||
DEBUG_POLYGEN to KeyBinding(
|
||||
DEBUG_POLYGON to KeyBinding(
|
||||
mutableMapOf(
|
||||
KeyAction.MODIFIER to mutableSetOf(KeyCodes.KEY_F4),
|
||||
KeyAction.PRESS to mutableSetOf(KeyCodes.KEY_P)
|
||||
|
@ -39,7 +39,7 @@ import kotlin.math.sin
|
||||
class Camera(
|
||||
val connection: Connection,
|
||||
var fov: Float,
|
||||
private val renderWindow: RenderWindow,
|
||||
val renderWindow: RenderWindow,
|
||||
) {
|
||||
private var mouseSensitivity = Minosoft.getConfig().config.game.camera.moseSensitivity
|
||||
private var movementSpeed = 7
|
||||
@ -73,8 +73,12 @@ class Camera(
|
||||
var inChunkSectionPosition: InChunkSectionPosition = InChunkSectionPosition(0, 0, 0)
|
||||
private set
|
||||
|
||||
private var screenHeight = 0
|
||||
private var screenWidth = 0
|
||||
val frustum: Frustum = Frustum(this)
|
||||
|
||||
var screenHeight = 0
|
||||
private set
|
||||
var screenWidth = 0
|
||||
private set
|
||||
private val shaders: MutableSet<Shader> = mutableSetOf()
|
||||
|
||||
private var keyForwardDown = false
|
||||
@ -214,7 +218,10 @@ class Camera(
|
||||
// recalculate sky color for current biome
|
||||
val blockPosition = Position(cameraPosition).toBlockPosition()
|
||||
renderWindow.setSkyColor(connection.player.world.getChunk(blockPosition.getChunkPosition())?.biomeAccessor?.getBiome(blockPosition, connection.player.world.dimension?.supports3DBiomes ?: false)?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR)
|
||||
connection.renderer.renderWindow.worldRenderer.recalculateFrustum(Frustum(this))
|
||||
|
||||
frustum.recalculate()
|
||||
renderWindow.worldRenderer.recalculateVisibleChunks()
|
||||
|
||||
connection.player.world.dimension?.hasSkyLight?.let {
|
||||
if (it) {
|
||||
renderWindow.setSkyColor(currentBiome?.skyColor ?: RenderConstants.DEFAULT_SKY_COLOR)
|
||||
|
@ -43,7 +43,7 @@ object RenderConstants {
|
||||
|
||||
const val TEXT_LINE_PADDING = 0
|
||||
|
||||
const val CHUNK_SECTIONS_PER_MESH = 8
|
||||
const val CHUNK_SECTIONS_PER_MESH = 4
|
||||
|
||||
const val MAXIMUM_CALLS_PER_FRAME = 10
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ class RenderWindow(
|
||||
// Make the OpenGL context current
|
||||
glfwMakeContextCurrent(windowId)
|
||||
// Enable v-sync
|
||||
glfwSwapInterval(0)
|
||||
glfwSwapInterval(1)
|
||||
|
||||
|
||||
// Make the window visible
|
||||
@ -309,14 +309,14 @@ class RenderWindow(
|
||||
}
|
||||
|
||||
private fun registerGlobalKeyCombinations() {
|
||||
registerKeyCallback(KeyBindingsNames.DEBUG_POLYGEN) { _: KeyCodes, _: KeyAction ->
|
||||
registerKeyCallback(KeyBindingsNames.DEBUG_POLYGON) { _: KeyCodes, _: KeyAction ->
|
||||
polygonEnabled = !polygonEnabled
|
||||
glPolygonMode(GL_FRONT_AND_BACK, if (polygonEnabled) {
|
||||
GL_LINE
|
||||
} else {
|
||||
GL_FILL
|
||||
})
|
||||
sendDebugMessage("Toggled polygen mode!")
|
||||
sendDebugMessage("Toggled polygon mode!")
|
||||
}
|
||||
registerKeyCallback(KeyBindingsNames.DEBUG_MOUSE_CATCH) { _: KeyCodes, _: KeyAction ->
|
||||
mouseCatch = !mouseCatch
|
||||
|
@ -3,7 +3,6 @@ package de.bixilon.minosoft.gui.rendering.chunk
|
||||
import de.bixilon.minosoft.data.world.ChunkPosition
|
||||
import de.bixilon.minosoft.gui.rendering.Camera
|
||||
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||
import de.bixilon.minosoft.protocol.network.Connection
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import glm_.glm
|
||||
import glm_.vec3.Vec3
|
||||
@ -13,7 +12,15 @@ class Frustum(private val camera: Camera) {
|
||||
camera.cameraFront.normalize(),
|
||||
)
|
||||
|
||||
|
||||
init {
|
||||
recalculate()
|
||||
}
|
||||
|
||||
fun recalculate() {
|
||||
normals.clear()
|
||||
normals.add(camera.cameraFront.normalize())
|
||||
|
||||
calculateSideNormals()
|
||||
calculateVerticalNormals()
|
||||
}
|
||||
@ -28,7 +35,7 @@ class Frustum(private val camera: Camera) {
|
||||
}
|
||||
|
||||
private fun calculateVerticalNormals() {
|
||||
val aspect = camera.connection.renderer.renderWindow.screenHeight.toFloat() / camera.connection.renderer.renderWindow.screenWidth.toFloat()
|
||||
val aspect = camera.screenHeight.toFloat() / camera.screenWidth.toFloat()
|
||||
val angle = glm.radians(camera.fov * aspect - 90f)
|
||||
val sin = glm.sin(angle)
|
||||
val cos = glm.cos(angle)
|
||||
@ -63,12 +70,10 @@ class Frustum(private val camera: Camera) {
|
||||
return true
|
||||
}
|
||||
|
||||
fun containsChunk(chunkPosition: ChunkPosition, connection: Connection): Boolean {
|
||||
val dimension = connection.player.world.dimension!!
|
||||
val from = Vec3(chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X, dimension.minY, chunkPosition.z * ProtocolDefinition.SECTION_WIDTH_Z)
|
||||
val to = from + Vec3(ProtocolDefinition.SECTION_WIDTH_X, dimension.logicalHeight, ProtocolDefinition.SECTION_WIDTH_Z)
|
||||
val frustum = Frustum(connection.renderer.renderWindow.camera)
|
||||
return frustum.containsRegion(from, to)
|
||||
fun containsChunk(chunkPosition: ChunkPosition, lowestBlockHeight: Int, highestBlockHeight: Int): Boolean {
|
||||
val from = Vec3(chunkPosition.x * ProtocolDefinition.SECTION_WIDTH_X, lowestBlockHeight, chunkPosition.z * ProtocolDefinition.SECTION_WIDTH_Z)
|
||||
val to = from + Vec3(ProtocolDefinition.SECTION_WIDTH_X, highestBlockHeight, ProtocolDefinition.SECTION_WIDTH_Z)
|
||||
return containsRegion(from, to)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ import org.lwjgl.opengl.GL20.glEnableVertexAttribArray
|
||||
import org.lwjgl.opengl.GL20.glVertexAttribPointer
|
||||
|
||||
class SectionArrayMesh : Mesh() {
|
||||
var lowestBlockHeight = 0
|
||||
var highestBlockHeight = 0
|
||||
|
||||
fun addVertex(position: Vec3, textureCoordinates: Vec2, texture: Texture, tintColor: RGBColor?, lightLevel: Int = 14) {
|
||||
data.add(position.x)
|
||||
|
@ -39,7 +39,6 @@ class WorldRenderer(
|
||||
lateinit var chunkShader: Shader
|
||||
val allChunkSections = ConcurrentHashMap<ChunkPosition, ConcurrentHashMap<Int, SectionArrayMesh>>()
|
||||
val visibleChunks = ConcurrentHashMap<ChunkPosition, ConcurrentHashMap<Int, SectionArrayMesh>>()
|
||||
private lateinit var frustum: Frustum
|
||||
private var currentTick = 0 // for animation usage
|
||||
private var lastTickIncrementTime = 0L
|
||||
val queuedChunks: MutableSet<ChunkPosition> = mutableSetOf()
|
||||
@ -220,13 +219,33 @@ class WorldRenderer(
|
||||
Minosoft.THREAD_POOL.execute {
|
||||
val mesh = prepareSections(chunkPosition, sections)
|
||||
|
||||
var sectionMap = allChunkSections[chunkPosition]
|
||||
if (sectionMap == null) {
|
||||
sectionMap = ConcurrentHashMap()
|
||||
allChunkSections[chunkPosition] = sectionMap
|
||||
var lowestBlockHeight = 0
|
||||
var highestBlockHeight = 0
|
||||
for ((sectionHeight, _) in sections) {
|
||||
if (sectionHeight < lowestBlockHeight) {
|
||||
lowestBlockHeight = sectionHeight
|
||||
}
|
||||
if (sectionHeight > highestBlockHeight) {
|
||||
highestBlockHeight = sectionHeight
|
||||
}
|
||||
}
|
||||
val index = getSectionIndex(lowestBlockHeight)
|
||||
|
||||
lowestBlockHeight *= ProtocolDefinition.SECTION_HEIGHT_Y
|
||||
highestBlockHeight = highestBlockHeight * ProtocolDefinition.SECTION_HEIGHT_Y + ProtocolDefinition.SECTION_MAX_Y
|
||||
|
||||
mesh.lowestBlockHeight = lowestBlockHeight
|
||||
mesh.highestBlockHeight = highestBlockHeight
|
||||
|
||||
|
||||
val sectionMap = allChunkSections[chunkPosition] ?: let {
|
||||
val map: ConcurrentHashMap<Int, SectionArrayMesh> = ConcurrentHashMap()
|
||||
allChunkSections[chunkPosition] = map
|
||||
map
|
||||
}
|
||||
|
||||
if (frustum.containsChunk(chunkPosition, connection)) {
|
||||
|
||||
if (renderWindow.camera.frustum.containsChunk(chunkPosition, lowestBlockHeight, highestBlockHeight)) {
|
||||
visibleChunks[chunkPosition] = sectionMap
|
||||
}
|
||||
|
||||
@ -302,12 +321,17 @@ class WorldRenderer(
|
||||
prepareWorld(connection.player.world)
|
||||
}
|
||||
|
||||
fun recalculateFrustum(frustum: Frustum) {
|
||||
fun recalculateVisibleChunks() {
|
||||
visibleChunks.clear()
|
||||
this.frustum = frustum
|
||||
for ((chunkLocation, sectionMap) in allChunkSections.entries) {
|
||||
if (frustum.containsChunk(chunkLocation, connection)) {
|
||||
visibleChunks[chunkLocation] = sectionMap
|
||||
for ((chunkLocation, indexMap) in allChunkSections) {
|
||||
val visibleIndexMap: ConcurrentHashMap<Int, SectionArrayMesh> = ConcurrentHashMap()
|
||||
for ((index, mesh) in indexMap) {
|
||||
if (renderWindow.camera.frustum.containsChunk(chunkLocation, mesh.lowestBlockHeight, mesh.highestBlockHeight)) {
|
||||
visibleIndexMap[index] = mesh
|
||||
}
|
||||
}
|
||||
if (visibleIndexMap.isNotEmpty()) {
|
||||
visibleChunks[chunkLocation] = visibleIndexMap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user