normal cull section preparer

This commit is contained in:
Bixilon 2021-11-08 13:41:47 +01:00
parent 2455359747
commit 2279af73a1
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 163 additions and 24 deletions

View File

@ -101,6 +101,7 @@ enum class Directions(
companion object : BlockPropertiesSerializer, ValuesEnum<Directions> {
const val SIZE = 6
override val VALUES = values()
override val NAME_MAP: Map<String, Directions> = KUtil.getEnumValues(VALUES)
val SIDES = arrayOf(NORTH, SOUTH, WEST, EAST)

View File

@ -24,6 +24,10 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.RendererBuilder
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.system.base.RenderSystem
import de.bixilon.minosoft.gui.rendering.system.base.phases.OpaqueDrawable
@ -43,10 +47,13 @@ class WorldRenderer(
override val renderSystem: RenderSystem = renderWindow.renderSystem
private val shader = renderSystem.createShader("minosoft:world".toResourceLocation())
private val world: World = connection.world
private val sectionPreparer = SectionPreparer(renderWindow)
private val sectionPreparer: AbstractSectionPreparer = GenericSectionPreparer(renderWindow)
private val lightMap = LightMap(connection)
private lateinit var mesh: ChunkSectionMesh
private val culledPreparer = GenericSectionPreparer(renderWindow, CullSectionPreparer(renderWindow))
private val greedyPreparer = GenericSectionPreparer(renderWindow, GreedySectionPreparer(renderWindow))
override fun init() {
val asset = Resources.getAssetVersionByVersion(connection.version)
@ -66,9 +73,24 @@ class WorldRenderer(
val random = Random(0L)
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)
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()
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -11,37 +11,38 @@
* 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.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.models.baked.block.GreedyBakedBlockModel
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition.SECTION_SIZE
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 java.util.*
class SectionPreparer(
class GreedySectionPreparer(
val renderWindow: RenderWindow,
) {
) : AbstractSectionPreparer {
private fun renderNormal(position: Vec3i, section: ChunkSection, mesh: ChunkSectionMesh, random: Random) {
// ToDo
}
fun prepare(section: ChunkSection): ChunkSectionMesh {
val startTime = System.nanoTime()
override fun prepare(section: ChunkSection): ChunkSectionMesh {
val mesh = ChunkSectionMesh(renderWindow)
val random = Random(0L)
var currentBlock: BlockState?
var compareBlock: BlockState?
var start: Vec3i
var end: Vec3i
for (direction in Directions.VALUES) {
// Sweep over each axis (X, Y and Z)
@ -80,8 +81,8 @@ class SectionPreparer(
n++
continue
}
val 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
currentBlock = if (position[axis] >= 0) section.blocks[ChunkSection.getIndex(position[0], position[1], position[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,
// i.e. both aren't empty and both aren't blocks
@ -150,14 +151,14 @@ class SectionPreparer(
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])]!!
(block.model as GreedyBakedBlockModel).greedyRender(start, end, direction, mesh, 0xFF)
currentBlock = section.blocks[ChunkSection.getIndex(position[0], position[1], position[2])]!!
(currentBlock.model as GreedyBakedBlockModel).greedyRender(start, end, direction, mesh, 0xFF)
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
}
}

View File

@ -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) {
val rescale = element.rotation?.rescale ?: false

View File

@ -279,7 +279,7 @@ object VecUtil {
val Vec3d.empty: Boolean
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()
hash = hash * hash * 42317861L + hash * 11L
return hash shr 16