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