mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-12 17:07:55 -04:00
normal cull section preparer
This commit is contained in:
parent
2455359747
commit
2279af73a1
@ -101,6 +101,7 @@ enum class Directions(
|
|||||||
|
|
||||||
|
|
||||||
companion object : BlockPropertiesSerializer, ValuesEnum<Directions> {
|
companion object : BlockPropertiesSerializer, ValuesEnum<Directions> {
|
||||||
|
const val SIZE = 6
|
||||||
override val VALUES = values()
|
override val VALUES = values()
|
||||||
override val NAME_MAP: Map<String, Directions> = KUtil.getEnumValues(VALUES)
|
override val NAME_MAP: Map<String, Directions> = KUtil.getEnumValues(VALUES)
|
||||||
val SIDES = arrayOf(NORTH, SOUTH, WEST, EAST)
|
val SIDES = arrayOf(NORTH, SOUTH, WEST, EAST)
|
||||||
|
@ -24,6 +24,10 @@ 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.ChunkSectionMesh
|
||||||
|
import de.bixilon.minosoft.gui.rendering.block.preparer.AbstractSectionPreparer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.block.preparer.CullSectionPreparer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.block.preparer.GenericSectionPreparer
|
||||||
|
import de.bixilon.minosoft.gui.rendering.block.preparer.GreedySectionPreparer
|
||||||
import de.bixilon.minosoft.gui.rendering.models.ModelLoader
|
import de.bixilon.minosoft.gui.rendering.models.ModelLoader
|
||||||
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.phases.OpaqueDrawable
|
import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable
|
||||||
@ -43,10 +47,13 @@ class WorldRenderer(
|
|||||||
override val renderSystem: RenderSystem = renderWindow.renderSystem
|
override val renderSystem: RenderSystem = renderWindow.renderSystem
|
||||||
private val shader = renderSystem.createShader("minosoft:world".toResourceLocation())
|
private val shader = renderSystem.createShader("minosoft:world".toResourceLocation())
|
||||||
private val world: World = connection.world
|
private val world: World = connection.world
|
||||||
private val sectionPreparer = SectionPreparer(renderWindow)
|
private val sectionPreparer: AbstractSectionPreparer = GenericSectionPreparer(renderWindow)
|
||||||
private val lightMap = LightMap(connection)
|
private val lightMap = LightMap(connection)
|
||||||
private lateinit var mesh: ChunkSectionMesh
|
private lateinit var mesh: ChunkSectionMesh
|
||||||
|
|
||||||
|
private val culledPreparer = GenericSectionPreparer(renderWindow, CullSectionPreparer(renderWindow))
|
||||||
|
private val greedyPreparer = GenericSectionPreparer(renderWindow, GreedySectionPreparer(renderWindow))
|
||||||
|
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
val asset = Resources.getAssetVersionByVersion(connection.version)
|
val asset = Resources.getAssetVersionByVersion(connection.version)
|
||||||
@ -66,9 +73,24 @@ class WorldRenderer(
|
|||||||
|
|
||||||
val random = Random(0L)
|
val random = Random(0L)
|
||||||
val blockState = connection.registries.blockRegistry["diamond_block"]?.defaultState
|
val blockState = connection.registries.blockRegistry["diamond_block"]?.defaultState
|
||||||
val chunk = ChunkSection(Array(4096) { if (random.nextBoolean()) blockState else null })
|
val section = ChunkSection(Array(4096) { if (random.nextBoolean()) blockState else null })
|
||||||
|
|
||||||
|
mesh = sectionPreparer.prepare(section)
|
||||||
|
/*
|
||||||
for (i in 0 until 1000)
|
for (i in 0 until 1000)
|
||||||
mesh = sectionPreparer.prepare(chunk)
|
mesh = sectionPreparer.prepare(section)
|
||||||
|
|
||||||
|
Log.log(LogMessageType.OTHER, LogLevels.WARN){"Culling now..."}
|
||||||
|
|
||||||
|
val culledMesh = culledPreparer.prepare(section)
|
||||||
|
for (i in 0 until 1000){
|
||||||
|
culledPreparer.prepare(section)
|
||||||
|
}
|
||||||
|
val greedyMesh = greedyPreparer.prepare(section)
|
||||||
|
|
||||||
|
Log.log(LogMessageType.OTHER,LogLevels.INFO){"Culling has ${culledMesh.data.size / ChunkSectionMesh.SectionArrayMeshStruct.FLOATS_PER_VERTEX}, greedy meshed has ${greedyMesh.data.size / ChunkSectionMesh.SectionArrayMeshStruct.FLOATS_PER_VERTEX}."}
|
||||||
|
|
||||||
|
*/
|
||||||
mesh.load()
|
mesh.load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering.block.preparer
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.world.ChunkSection
|
||||||
|
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
||||||
|
|
||||||
|
interface AbstractSectionPreparer {
|
||||||
|
|
||||||
|
fun prepare(section: ChunkSection): ChunkSectionMesh
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package de.bixilon.minosoft.gui.rendering.block.preparer
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.direction.Directions
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||||
|
import de.bixilon.minosoft.data.world.ChunkSection
|
||||||
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
|
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
||||||
|
import de.bixilon.minosoft.gui.rendering.util.VecUtil
|
||||||
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
|
import glm_.vec3.Vec3i
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class CullSectionPreparer(
|
||||||
|
val renderWindow: RenderWindow,
|
||||||
|
) : AbstractSectionPreparer {
|
||||||
|
|
||||||
|
override fun prepare(section: ChunkSection): ChunkSectionMesh {
|
||||||
|
val mesh = ChunkSectionMesh(renderWindow)
|
||||||
|
val random = Random(0L)
|
||||||
|
|
||||||
|
var block: BlockState?
|
||||||
|
val neighbours: Array<BlockState?> = arrayOfNulls(Directions.SIZE)
|
||||||
|
|
||||||
|
for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) {
|
||||||
|
for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) {
|
||||||
|
for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) {
|
||||||
|
block = section.blocks[ChunkSection.getIndex(x, y, z)]
|
||||||
|
|
||||||
|
// ToDo: Chunk borders
|
||||||
|
neighbours[Directions.DOWN.ordinal] = if (y == 0) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
section.blocks[ChunkSection.getIndex(x, y - 1, z)]
|
||||||
|
}
|
||||||
|
neighbours[Directions.UP.ordinal] = if (y == ProtocolDefinition.SECTION_MAX_Y) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
section.blocks[ChunkSection.getIndex(x, y + 1, z)]
|
||||||
|
}
|
||||||
|
neighbours[Directions.NORTH.ordinal] = if (z == 0) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
section.blocks[ChunkSection.getIndex(x, y, z - 1)]
|
||||||
|
}
|
||||||
|
neighbours[Directions.SOUTH.ordinal] = if (z == ProtocolDefinition.SECTION_MAX_Z) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
section.blocks[ChunkSection.getIndex(x, y, z + 1)]
|
||||||
|
}
|
||||||
|
neighbours[Directions.WEST.ordinal] = if (x == 0) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
section.blocks[ChunkSection.getIndex(x - 1, y, z)]
|
||||||
|
}
|
||||||
|
neighbours[Directions.EAST.ordinal] = if (x == ProtocolDefinition.SECTION_MAX_X) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
section.blocks[ChunkSection.getIndex(x + 1, y, z)]
|
||||||
|
}
|
||||||
|
|
||||||
|
random.setSeed(VecUtil.generatePositionHash(x, y, z))
|
||||||
|
block?.model?.singleRender(Vec3i(x, y, z), mesh, random, neighbours, 0xFF, intArrayOf(0xF, 0xF, 0xF, 0xF))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return mesh
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 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.block.preparer
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.world.ChunkSection
|
||||||
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
|
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
||||||
|
import de.bixilon.minosoft.util.logging.Log
|
||||||
|
import de.bixilon.minosoft.util.logging.LogLevels
|
||||||
|
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||||
|
|
||||||
|
|
||||||
|
class GenericSectionPreparer(
|
||||||
|
val renderWindow: RenderWindow,
|
||||||
|
private val preparer: AbstractSectionPreparer = GreedySectionPreparer(renderWindow),
|
||||||
|
) : AbstractSectionPreparer {
|
||||||
|
|
||||||
|
override fun prepare(section: ChunkSection): ChunkSectionMesh {
|
||||||
|
val startTime = System.nanoTime()
|
||||||
|
|
||||||
|
val mesh = preparer.prepare(section)
|
||||||
|
|
||||||
|
val time = System.nanoTime()
|
||||||
|
val delta = time - startTime
|
||||||
|
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Preparing took ${delta}ns, ${delta / 1000}µs, ${delta / 1000000}ms" }
|
||||||
|
|
||||||
|
return mesh
|
||||||
|
}
|
||||||
|
}
|
@ -11,37 +11,38 @@
|
|||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.bixilon.minosoft.gui.rendering.block
|
package de.bixilon.minosoft.gui.rendering.block.preparer
|
||||||
|
|
||||||
import de.bixilon.minosoft.data.direction.Directions
|
import de.bixilon.minosoft.data.direction.Directions
|
||||||
|
import de.bixilon.minosoft.data.registries.blocks.BlockState
|
||||||
import de.bixilon.minosoft.data.world.ChunkSection
|
import de.bixilon.minosoft.data.world.ChunkSection
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
|
||||||
import de.bixilon.minosoft.gui.rendering.models.baked.block.GreedyBakedBlockModel
|
import de.bixilon.minosoft.gui.rendering.models.baked.block.GreedyBakedBlockModel
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.SECTION_SIZE
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.SECTION_SIZE
|
||||||
import de.bixilon.minosoft.util.KUtil.decide
|
import de.bixilon.minosoft.util.KUtil.decide
|
||||||
import de.bixilon.minosoft.util.logging.Log
|
|
||||||
import de.bixilon.minosoft.util.logging.LogLevels
|
|
||||||
import de.bixilon.minosoft.util.logging.LogMessageType
|
|
||||||
import glm_.vec3.Vec3i
|
import glm_.vec3.Vec3i
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class SectionPreparer(
|
class GreedySectionPreparer(
|
||||||
val renderWindow: RenderWindow,
|
val renderWindow: RenderWindow,
|
||||||
) {
|
) : AbstractSectionPreparer {
|
||||||
|
|
||||||
private fun renderNormal(position: Vec3i, section: ChunkSection, mesh: ChunkSectionMesh, random: Random) {
|
private fun renderNormal(position: Vec3i, section: ChunkSection, mesh: ChunkSectionMesh, random: Random) {
|
||||||
// ToDo
|
// ToDo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun prepare(section: ChunkSection): ChunkSectionMesh {
|
override fun prepare(section: ChunkSection): ChunkSectionMesh {
|
||||||
val startTime = System.nanoTime()
|
|
||||||
val mesh = ChunkSectionMesh(renderWindow)
|
val mesh = ChunkSectionMesh(renderWindow)
|
||||||
|
|
||||||
val random = Random(0L)
|
val random = Random(0L)
|
||||||
|
|
||||||
|
var currentBlock: BlockState?
|
||||||
|
var compareBlock: BlockState?
|
||||||
|
var start: Vec3i
|
||||||
|
var end: Vec3i
|
||||||
|
|
||||||
for (direction in Directions.VALUES) {
|
for (direction in Directions.VALUES) {
|
||||||
// Sweep over each axis (X, Y and Z)
|
// Sweep over each axis (X, Y and Z)
|
||||||
@ -80,8 +81,8 @@ class SectionPreparer(
|
|||||||
n++
|
n++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val currentBlock = if (position[axis] >= 0) section.blocks[ChunkSection.getIndex(position[0], position[1], position[2])] else null
|
currentBlock = if (position[axis] >= 0) section.blocks[ChunkSection.getIndex(position[0], position[1], position[2])] else null
|
||||||
val compareBlock = if (position[axis] < SECTION_SIZE - 1) section.blocks[ChunkSection.getIndex(position[0] + checkOffset[0], position[1] + checkOffset[1], position[2] + checkOffset[2])] else null
|
compareBlock = if (position[axis] < SECTION_SIZE - 1) section.blocks[ChunkSection.getIndex(position[0] + checkOffset[0], position[1] + checkOffset[1], position[2] + checkOffset[2])] else null
|
||||||
|
|
||||||
// The mask is set to true if there is a visible face between two blocks,
|
// The mask is set to true if there is a visible face between two blocks,
|
||||||
// i.e. both aren't empty and both aren't blocks
|
// i.e. both aren't empty and both aren't blocks
|
||||||
@ -150,14 +151,14 @@ class SectionPreparer(
|
|||||||
position[axis] -= offsetCheck
|
position[axis] -= offsetCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
val start = Vec3i(position[0], position[1], position[2])
|
start = Vec3i(position[0], position[1], position[2])
|
||||||
|
|
||||||
|
|
||||||
val end = Vec3i(position[0] + du[0] + dv[0], position[1] + du[1] + dv[1], position[2] + du[2] + dv[2])
|
end = Vec3i(position[0] + du[0] + dv[0], position[1] + du[1] + dv[1], position[2] + du[2] + dv[2])
|
||||||
|
|
||||||
|
|
||||||
val block = section.blocks[ChunkSection.getIndex(position[0], position[1], position[2])]!!
|
currentBlock = section.blocks[ChunkSection.getIndex(position[0], position[1], position[2])]!!
|
||||||
(block.model as GreedyBakedBlockModel).greedyRender(start, end, direction, mesh, 0xFF)
|
(currentBlock.model as GreedyBakedBlockModel).greedyRender(start, end, direction, mesh, 0xFF)
|
||||||
|
|
||||||
|
|
||||||
if (!backFace) {
|
if (!backFace) {
|
||||||
@ -188,11 +189,6 @@ class SectionPreparer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val time = System.nanoTime()
|
|
||||||
val delta = time - startTime
|
|
||||||
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Preparing took ${delta}ns, ${delta / 1000}µs, ${delta / 1000000}ms" }
|
|
||||||
|
|
||||||
return mesh
|
return mesh
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -68,7 +68,7 @@ data class UnbakedBlockStateModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val faces: Array<MutableList<BakedFace>> = Array(Directions.VALUES.size) { mutableListOf() }
|
val faces: Array<MutableList<BakedFace>> = Array(Directions.SIZE) { mutableListOf() }
|
||||||
|
|
||||||
for (element in model.elements) {
|
for (element in model.elements) {
|
||||||
val rescale = element.rotation?.rescale ?: false
|
val rescale = element.rotation?.rescale ?: false
|
||||||
|
@ -279,7 +279,7 @@ object VecUtil {
|
|||||||
val Vec3d.empty: Boolean
|
val Vec3d.empty: Boolean
|
||||||
get() = this.length() < 0.001
|
get() = this.length() < 0.001
|
||||||
|
|
||||||
private fun generatePositionHash(x: Int, y: Int, z: Int): Long {
|
fun generatePositionHash(x: Int, y: Int, z: Int): Long {
|
||||||
var hash = (x * 3129871L) xor z.toLong() * 116129781L xor y.toLong()
|
var hash = (x * 3129871L) xor z.toLong() * 116129781L xor y.toLong()
|
||||||
hash = hash * hash * 42317861L + hash * 11L
|
hash = hash * hash * 42317861L + hash * 11L
|
||||||
return hash shr 16
|
return hash shr 16
|
||||||
|
Loading…
x
Reference in New Issue
Block a user