face culling

This commit is contained in:
Bixilon 2021-11-10 16:47:52 +01:00
parent 486da0eda1
commit b811a95059
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
10 changed files with 100 additions and 24 deletions

View File

@ -18,6 +18,8 @@ import de.bixilon.minosoft.data.assets.Resources
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.direction.FakeDirection
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.properties.BlockProperties
import de.bixilon.minosoft.data.registries.blocks.properties.MultipartDirectionParser
import de.bixilon.minosoft.data.world.ChunkSection
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.gui.rendering.RenderWindow
@ -72,14 +74,14 @@ class WorldRenderer(
val random = Random(0L)
val blockState1 = connection.registries.blockRegistry["end_portal_frame"]?.defaultState
val blockState2 = connection.registries.blockRegistry["oak_fence"]!!.defaultState//.withProperties(BlockProperties.FACING to Directions.SOUTH)
val blockState1 = connection.registries.blockRegistry["grass_block"]?.defaultState
val blockState2 = connection.registries.blockRegistry["oak_fence"]!!.defaultState.withProperties(BlockProperties.MULTIPART_SOUTH to MultipartDirectionParser.SIDE, BlockProperties.MULTIPART_NORTH to MultipartDirectionParser.SIDE, BlockProperties.MULTIPART_EAST to MultipartDirectionParser.SIDE, BlockProperties.MULTIPART_WEST to MultipartDirectionParser.SIDE)
val section = ChunkSection(Array(4096) {
if (it < 256) return@Array blockState2 else return@Array null
when (random.nextInt(3)) {
1 -> blockState2
1 -> blockState1
2 -> blockState2
else -> blockState2
else -> null
}
})
//val section = ChunkSection(Array(4096) { if (it < 1) blockState else null })

View File

@ -59,7 +59,7 @@ class CullSectionPreparer(
}
random.setSeed(VecUtil.generatePositionHash(x, y, z))
block?.model?.singleRender(Vec3i(x, y, z), mesh, random, neighbours, 0xFF, intArrayOf(0xF, 0xF, 0xF, 0xF))
block?.model?.singleRender(Vec3i(x, y, z), mesh, random, neighbours, 0xFF, floatArrayOf(1.0f, 1.0f, 1.0f, 1.0f))
}
}
}

View File

@ -0,0 +1,18 @@
package de.bixilon.minosoft.gui.rendering.models
object CullUtil {
fun Array<FaceSize>.canCull(size: FaceSize): Boolean {
for (faceSize in this) {
if (
faceSize.start.x <= size.start.x
&& faceSize.start.y <= size.start.y
&& faceSize.end.x >= size.end.x
&& faceSize.end.y >= size.end.y
) {
return true
}
}
return false
}
}

View File

@ -17,19 +17,25 @@ import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
import de.bixilon.minosoft.gui.rendering.models.FaceSize
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
import glm_.vec3.Vec3i
import java.util.*
class MultipartBakedModel(
val models: Array<BakedBlockModel>,
val sizes: Array<Array<FaceSize>>,
) : BakedBlockModel {
override fun getSize(random: Random, direction: Directions): Array<FaceSize> {
return sizes[direction.ordinal]
}
override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int {
return 0xFF
}
override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: IntArray) {
override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: FloatArray) {
for (model in models) {
model.singleRender(position, mesh, random, neighbours, light, ambientLight)
}

View File

@ -17,6 +17,7 @@ import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
import de.bixilon.minosoft.gui.rendering.models.FaceSize
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
import glm_.vec3.Vec3i
import java.util.*
@ -36,6 +37,10 @@ class WeightedBakedModel(
this.totalWeight = totalWeight
}
override fun getSize(random: Random, direction: Directions): Array<FaceSize> {
return getModel(random).getSize(random, direction)
}
private fun getModel(random: Random): BakedBlockModel {
val totalWeight = abs(random.nextLong() % totalWeight)
@ -55,7 +60,7 @@ class WeightedBakedModel(
return getModel(random).getLight(position, random, side, lightAccessor)
}
override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: IntArray) {
override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: FloatArray) {
getModel(random).singleRender(position, mesh, random, neighbours, light, ambientLight)
}

View File

@ -17,14 +17,17 @@ import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
import de.bixilon.minosoft.gui.rendering.models.FaceSize
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel
import glm_.vec3.Vec3i
import java.util.*
interface BakedBlockModel : BakedModel {
fun getSize(random: Random, direction: Directions): Array<FaceSize>
// ToDo: Tint
fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: IntArray)
fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: FloatArray)
// ToDo: Get ambient light
fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int

View File

@ -17,25 +17,38 @@ import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
import de.bixilon.minosoft.gui.rendering.models.CullUtil.canCull
import de.bixilon.minosoft.gui.rendering.models.FaceSize
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
import glm_.vec3.Vec3i
import java.util.*
class BakedBlockStateModel(
val faces: Array<Array<BakedFace>>,
val sizes: Array<Array<FaceSize>>,
) : BakedBlockModel, GreedyBakedBlockModel { // ToDo: Greedy meshable
override val canGreedyMesh: Boolean = true
override val greedyMeshableFaces: BooleanArray = booleanArrayOf(true, false, true, true, true, true)
override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: IntArray) {
override fun getSize(random: Random, direction: Directions): Array<FaceSize> {
return sizes[direction.ordinal]
}
override fun singleRender(position: Vec3i, mesh: ChunkSectionMesh, random: Random, neighbours: Array<BlockState?>, light: Int, ambientLight: FloatArray) {
val floatPosition = position.toVec3()
for ((index, direction) in faces.withIndex()) {
val neighbour = neighbours[index]
for ((index, faces) in faces.withIndex()) {
val direction = Directions.VALUES[index]
val neighbour = neighbours[index]?.model
var neighbourSize: Array<FaceSize>? = null
if (neighbour != null) {
// continue
random.setSeed(0L) // ToDo
neighbourSize = neighbour.getSize(random, direction.inverted)
}
for (face in direction) {
face.singleRender(floatPosition, mesh, neighbour, light, ambientLight)
for (face in faces) {
if (face.touching && neighbourSize != null && neighbourSize.isNotEmpty() && neighbourSize.canCull(face.faceSize)) {
continue
}
face.singleRender(floatPosition, mesh, light, ambientLight)
}
}
}

View File

@ -15,7 +15,6 @@ package de.bixilon.minosoft.gui.rendering.models.baked.block
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
import de.bixilon.minosoft.gui.rendering.models.FaceSize
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
@ -32,8 +31,9 @@ class BakedFace(
val tintIndex: Int,
val cullFace: Directions?,
val texture: AbstractTexture,
val touching: Boolean,
) {
fun singleRender(position: Vec3, mesh: ChunkSectionMesh, neighbour: BlockState?, light: Int, ambientLight: IntArray) {
fun singleRender(position: Vec3, mesh: ChunkSectionMesh, light: Int, ambientLight: FloatArray) {
// ToDo: Ambient light
for ((index, textureIndex) in Mesh.QUAD_DRAW_ODER) {
mesh.addVertex(positions[index] + position, uv[textureIndex], texture, null, light)

View File

@ -17,6 +17,7 @@ import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.models.FaceSize
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockStateModel
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedFace
@ -28,6 +29,7 @@ import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.get
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.rad
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.toVec2iN
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.get
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotateAssign
import de.bixilon.minosoft.util.KUtil.toBoolean
import de.bixilon.minosoft.util.KUtil.toInt
@ -82,6 +84,7 @@ data class UnbakedBlockStateModel(
val faces: Array<MutableList<BakedFace>> = Array(Directions.SIZE) { mutableListOf() }
val sizes: Array<MutableList<FaceSize>> = Array(Directions.SIZE) { mutableListOf() }
for (element in model.elements) {
val rescale = element.rotation?.rescale ?: false
@ -126,15 +129,20 @@ data class UnbakedBlockStateModel(
}
}
val size = face.direction.getSize(element.from, element.to)
val touching = (if (face.direction.negative) element.from[face.direction.axis] else element.to[face.direction.axis] - 1.0f) == 0.0f
if (touching) {
sizes[direction.ordinal] += size
}
faces[direction.ordinal] += BakedFace(
faceSize = face.direction.getSize(element.from, element.to),
faceSize = size,
positions = positions,
uv = texturePositions,
shade = element.shade,
tintIndex = face.tintIndex,
cullFace = face.cullFace,
texture = texture,
touching = touching,
)
}
}
@ -142,10 +150,15 @@ data class UnbakedBlockStateModel(
val finalFaces: Array<Array<BakedFace>?> = arrayOfNulls(faces.size)
for ((index, faceArray) in faces.withIndex()) {
finalFaces[index] = faceArray.toTypedArray()
finalFaces[index] = faceArray.reversed().toTypedArray()
}
val finalSizes: Array<Array<FaceSize>?> = arrayOfNulls(faces.size)
for ((index, sizeArray) in sizes.withIndex()) {
finalSizes[index] = sizeArray.toTypedArray()
}
val baked = BakedBlockStateModel(finalFaces.unsafeCast())
val baked = BakedBlockStateModel(finalFaces.unsafeCast(), finalSizes.unsafeCast())
this.baked = baked
return baked
}

View File

@ -1,11 +1,14 @@
package de.bixilon.minosoft.gui.rendering.models.unbaked.block
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.models.FaceSize
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel
import de.bixilon.minosoft.gui.rendering.models.baked.MultipartBakedModel
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel
import de.bixilon.minosoft.util.KUtil.unsafeCast
import java.util.*
class UnbakedMultipartModel(
val models: Set<UnbakedBlockStateModel>,
@ -13,12 +16,25 @@ class UnbakedMultipartModel(
override fun bake(renderWindow: RenderWindow): BakedModel {
val baked: Array<BakedBlockModel?> = arrayOfNulls(this.models.size)
val sizes: Array<MutableList<FaceSize>> = Array(Directions.SIZE) { mutableListOf() }
var index = 0
for (model in this.models) {
baked[index++] = model.bake(renderWindow)
for ((index, model) in this.models.withIndex()) {
val bakedModel = model.bake(renderWindow)
for (direction in Directions.VALUES) {
sizes[direction.ordinal] += bakedModel.getSize(RANDOM, direction) // There is no random here!
}
baked[index] = bakedModel
}
val finalFaces: Array<Array<FaceSize>?> = arrayOfNulls(Directions.SIZE)
for (index in 0 until Directions.SIZE) {
finalFaces[index] = sizes[index].toTypedArray()
}
return MultipartBakedModel(baked.unsafeCast())
return MultipartBakedModel(baked.unsafeCast(), finalFaces.unsafeCast())
}
private companion object {
private val RANDOM = Random(0L)
}
}