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.Directions
import de.bixilon.minosoft.data.direction.FakeDirection import de.bixilon.minosoft.data.direction.FakeDirection
import de.bixilon.minosoft.data.registries.ResourceLocation 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.ChunkSection
import de.bixilon.minosoft.data.world.World import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.RenderWindow
@ -72,14 +74,14 @@ class WorldRenderer(
val random = Random(0L) val random = Random(0L)
val blockState1 = connection.registries.blockRegistry["end_portal_frame"]?.defaultState val blockState1 = connection.registries.blockRegistry["grass_block"]?.defaultState
val blockState2 = connection.registries.blockRegistry["oak_fence"]!!.defaultState//.withProperties(BlockProperties.FACING to Directions.SOUTH) 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) { val section = ChunkSection(Array(4096) {
if (it < 256) return@Array blockState2 else return@Array null if (it < 256) return@Array blockState2 else return@Array null
when (random.nextInt(3)) { when (random.nextInt(3)) {
1 -> blockState2 1 -> blockState1
2 -> blockState2 2 -> blockState2
else -> blockState2 else -> null
} }
}) })
//val section = ChunkSection(Array(4096) { if (it < 1) blockState 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)) 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.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.data.world.light.LightAccessor
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.FaceSize
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
import java.util.* import java.util.*
class MultipartBakedModel( class MultipartBakedModel(
val models: Array<BakedBlockModel>, val models: Array<BakedBlockModel>,
val sizes: Array<Array<FaceSize>>,
) : BakedBlockModel { ) : 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 { override fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int {
return 0xFF 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) { for (model in models) {
model.singleRender(position, mesh, random, neighbours, light, ambientLight) 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.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.data.world.light.LightAccessor
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.FaceSize
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
import java.util.* import java.util.*
@ -36,6 +37,10 @@ class WeightedBakedModel(
this.totalWeight = totalWeight this.totalWeight = totalWeight
} }
override fun getSize(random: Random, direction: Directions): Array<FaceSize> {
return getModel(random).getSize(random, direction)
}
private fun getModel(random: Random): BakedBlockModel { private fun getModel(random: Random): BakedBlockModel {
val totalWeight = abs(random.nextLong() % totalWeight) val totalWeight = abs(random.nextLong() % totalWeight)
@ -55,7 +60,7 @@ class WeightedBakedModel(
return getModel(random).getLight(position, random, side, lightAccessor) 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) 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.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.data.world.light.LightAccessor
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.FaceSize
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
import java.util.* import java.util.*
interface BakedBlockModel : BakedModel { interface BakedBlockModel : BakedModel {
fun getSize(random: Random, direction: Directions): Array<FaceSize>
// ToDo: Tint // 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 // ToDo: Get ambient light
fun getLight(position: Vec3i, random: Random, side: Directions, lightAccessor: LightAccessor): Int 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.registries.blocks.BlockState
import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.data.world.light.LightAccessor
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.CullUtil.canCull
import de.bixilon.minosoft.gui.rendering.models.FaceSize
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3 import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.toVec3
import glm_.vec3.Vec3i import glm_.vec3.Vec3i
import java.util.* import java.util.*
class BakedBlockStateModel( class BakedBlockStateModel(
val faces: Array<Array<BakedFace>>, val faces: Array<Array<BakedFace>>,
val sizes: Array<Array<FaceSize>>,
) : BakedBlockModel, GreedyBakedBlockModel { // ToDo: Greedy meshable ) : BakedBlockModel, GreedyBakedBlockModel { // ToDo: Greedy meshable
override val canGreedyMesh: Boolean = true override val canGreedyMesh: Boolean = true
override val greedyMeshableFaces: BooleanArray = booleanArrayOf(true, false, true, true, true, 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() val floatPosition = position.toVec3()
for ((index, direction) in faces.withIndex()) { for ((index, faces) in faces.withIndex()) {
val neighbour = neighbours[index] val direction = Directions.VALUES[index]
val neighbour = neighbours[index]?.model
var neighbourSize: Array<FaceSize>? = null
if (neighbour != null) { if (neighbour != null) {
// continue random.setSeed(0L) // ToDo
neighbourSize = neighbour.getSize(random, direction.inverted)
} }
for (face in direction) { for (face in faces) {
face.singleRender(floatPosition, mesh, neighbour, light, ambientLight) 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.Axes
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.gui.rendering.block.mesh.ChunkSectionMesh import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMesh
import de.bixilon.minosoft.gui.rendering.models.FaceSize import de.bixilon.minosoft.gui.rendering.models.FaceSize
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
@ -32,8 +31,9 @@ class BakedFace(
val tintIndex: Int, val tintIndex: Int,
val cullFace: Directions?, val cullFace: Directions?,
val texture: AbstractTexture, 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 // ToDo: Ambient light
for ((index, textureIndex) in Mesh.QUAD_DRAW_ODER) { for ((index, textureIndex) in Mesh.QUAD_DRAW_ODER) {
mesh.addVertex(positions[index] + position, uv[textureIndex], texture, null, light) 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.direction.Directions
import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.gui.rendering.RenderWindow 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.BakedBlockModel
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockStateModel import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockStateModel
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedFace 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.get
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.rad 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.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.gui.rendering.util.vec.vec3.Vec3Util.rotateAssign
import de.bixilon.minosoft.util.KUtil.toBoolean import de.bixilon.minosoft.util.KUtil.toBoolean
import de.bixilon.minosoft.util.KUtil.toInt import de.bixilon.minosoft.util.KUtil.toInt
@ -82,6 +84,7 @@ data class UnbakedBlockStateModel(
val faces: Array<MutableList<BakedFace>> = Array(Directions.SIZE) { mutableListOf() } val faces: Array<MutableList<BakedFace>> = Array(Directions.SIZE) { mutableListOf() }
val sizes: Array<MutableList<FaceSize>> = 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
@ -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( faces[direction.ordinal] += BakedFace(
faceSize = face.direction.getSize(element.from, element.to), faceSize = size,
positions = positions, positions = positions,
uv = texturePositions, uv = texturePositions,
shade = element.shade, shade = element.shade,
tintIndex = face.tintIndex, tintIndex = face.tintIndex,
cullFace = face.cullFace, cullFace = face.cullFace,
texture = texture, texture = texture,
touching = touching,
) )
} }
} }
@ -142,10 +150,15 @@ data class UnbakedBlockStateModel(
val finalFaces: Array<Array<BakedFace>?> = arrayOfNulls(faces.size) val finalFaces: Array<Array<BakedFace>?> = arrayOfNulls(faces.size)
for ((index, faceArray) in faces.withIndex()) { 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 this.baked = baked
return baked return baked
} }

View File

@ -1,11 +1,14 @@
package de.bixilon.minosoft.gui.rendering.models.unbaked.block 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.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.BakedModel
import de.bixilon.minosoft.gui.rendering.models.baked.MultipartBakedModel 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.baked.block.BakedBlockModel
import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel
import de.bixilon.minosoft.util.KUtil.unsafeCast import de.bixilon.minosoft.util.KUtil.unsafeCast
import java.util.*
class UnbakedMultipartModel( class UnbakedMultipartModel(
val models: Set<UnbakedBlockStateModel>, val models: Set<UnbakedBlockStateModel>,
@ -13,12 +16,25 @@ class UnbakedMultipartModel(
override fun bake(renderWindow: RenderWindow): BakedModel { override fun bake(renderWindow: RenderWindow): BakedModel {
val baked: Array<BakedBlockModel?> = arrayOfNulls(this.models.size) val baked: Array<BakedBlockModel?> = arrayOfNulls(this.models.size)
val sizes: Array<MutableList<FaceSize>> = Array(Directions.SIZE) { mutableListOf() }
var index = 0 for ((index, model) in this.models.withIndex()) {
for (model in this.models) { val bakedModel = model.bake(renderWindow)
baked[index++] = 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)
} }
} }