test every quad of side for face culling

This workarounds unoptimized face properties and fixes culling between grass blocks
This commit is contained in:
Moritz Zwerger 2023-09-01 18:49:49 +02:00
parent 4ab3fc08a7
commit 1c4e5e9eae
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
2 changed files with 33 additions and 31 deletions

View File

@ -58,168 +58,144 @@ class FaceCullingTest {
assertFalse(FaceCulling.canCull(createState(), face, Directions.DOWN, null))
}
@Test
fun selfNotTouching() {
val face = createFace(properties = null)
val neighbour = createBlock()
assertFalse(FaceCulling.canCull(createState(), face, Directions.DOWN, neighbour))
}
@Test
fun neighbourNotTouching() {
val face = createFace()
val neighbour = createBlock(properties = null)
assertFalse(FaceCulling.canCull(createState(), face, Directions.DOWN, neighbour))
}
@Test
fun fullNeighbour() {
val face = createFace()
val neighbour = createBlock()
assertTrue(FaceCulling.canCull(createState(), face, Directions.DOWN, neighbour))
}
@Test
fun sizeMatch() {
val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE))
val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE)))
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun greaterNeighbour() {
val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE))
val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.6f), TextureTransparencies.OPAQUE)))
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun smallerNeighbour() {
val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE))
val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.4f), TextureTransparencies.OPAQUE)))
assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun noSize() {
val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE))
val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE)))
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun shiftedNeighbour1() {
val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.4f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE))
val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.4f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE)))
assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun shiftedNeighbour2() {
val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.4f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE))
val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.4f), Vec2(1.0f, 0.6f), TextureTransparencies.OPAQUE)))
assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun shiftedNeighbour3() {
val face = createFace(properties = FaceProperties(Vec2(0.1f, 0.8f), Vec2(0.9f, 0.9f), TextureTransparencies.OPAQUE))
val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.5f), Vec2(0.95f, 0.95f), TextureTransparencies.OPAQUE)))
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun multipleNeighbourFaces() {
val face = createFace(properties = FaceProperties(Vec2(0.1f, 0.3f), Vec2(0.9f, 0.9f), TextureTransparencies.OPAQUE))
val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.2f), Vec2(0.95f, 0.4f), TextureTransparencies.OPAQUE), FaceProperties(Vec2(0.1f, 0.4f), Vec2(0.95f, 0.6f), TextureTransparencies.OPAQUE), FaceProperties(Vec2(0.1f, 0.6f), Vec2(0.95f, 0.95f), TextureTransparencies.OPAQUE)))
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun `transparent side on opaque neighbour`() {
val face = createFace(transparency = TextureTransparencies.TRANSPARENT)
val neighbour = createBlock(transparency = TextureTransparencies.OPAQUE)
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun `translucent side on opaque neighbour`() {
val face = createFace(transparency = TextureTransparencies.TRANSLUCENT)
val neighbour = createBlock(transparency = TextureTransparencies.OPAQUE)
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun `opaque side on transparent neighbour`() {
val face = createFace(transparency = TextureTransparencies.OPAQUE)
val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT)
assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun `opaque side on translucent neighbour`() {
val face = createFace(transparency = TextureTransparencies.OPAQUE)
val neighbour = createBlock(transparency = TextureTransparencies.TRANSLUCENT)
assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun `same block, both sides transparent`() {
val face = createFace(transparency = TextureTransparencies.TRANSPARENT)
val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT)
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun `same block, both sides translucent`() {
val face = createFace(transparency = TextureTransparencies.TRANSLUCENT)
val neighbour = createBlock(transparency = TextureTransparencies.TRANSLUCENT)
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
@Test
fun `different block, both sides transparent`() {
val face = createFace(transparency = TextureTransparencies.TRANSPARENT)
val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT)
assertFalse(FaceCulling.canCull(createState(1), face, Directions.EAST, neighbour))
}
@Test
fun `different block, both sides translucent`() {
val face = createFace(transparency = TextureTransparencies.TRANSLUCENT)
val neighbour = createBlock(transparency = TextureTransparencies.TRANSLUCENT)
assertFalse(FaceCulling.canCull(createState(1), face, Directions.EAST, neighbour))
}
@Test
fun `same block, transparent sides, force no cull`() {
val face = createFace(transparency = TextureTransparencies.TRANSPARENT)
val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT)
assertFalse(FaceCulling.canCull(createBlock(forceNoCull()), face, Directions.EAST, neighbour))
}
@Test
fun `same block, translucent sides, force no cull`() {
val face = createFace(transparency = TextureTransparencies.TRANSLUCENT)
val neighbour = createBlock(transparency = TextureTransparencies.TRANSLUCENT)
assertFalse(FaceCulling.canCull(createBlock(forceNoCull()), face, Directions.EAST, neighbour))
}
@Test
fun `opaque side on transparent block`() {
val face = createFace(transparency = TextureTransparencies.OPAQUE)
val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT)
assertFalse(FaceCulling.canCull(createBlock(), face, Directions.EAST, neighbour))
}
@Test
fun `transparent side on opaque block`() {
val face = createFace(transparency = TextureTransparencies.TRANSPARENT)
val neighbour = createBlock(transparency = TextureTransparencies.OPAQUE)
assertTrue(FaceCulling.canCull(createBlock(), face, Directions.EAST, neighbour))
}
@Test
fun `opaque but no invoked custom cull`() {
val block = object : Block(minosoft("dummy"), BlockSettings()), CustomBlockCulling {
override val hardness get() = Broken()
@ -233,8 +209,16 @@ class FaceCullingTest {
assertTrue(FaceCulling.canCull(createBlock(block), face, Directions.EAST, neighbour))
}
private fun side(vararg properties: FaceProperties): SideProperties {
return SideProperties(arrayOf(*properties), properties.first().transparency)
fun `opaque but neighbour opaque and transparent`() { // grass block + overlay
val face = createFace(TextureTransparencies.OPAQUE, properties = FaceProperties(Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f), TextureTransparencies.OPAQUE))
val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f), TextureTransparencies.OPAQUE), FaceProperties(Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f), TextureTransparencies.TRANSPARENT), transparency = null))
assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour))
}
private fun side(vararg properties: FaceProperties, transparency: TextureTransparencies? = properties.first().transparency): SideProperties {
return SideProperties(arrayOf(*properties), transparency)
}
private fun forceNoCull() = object : Block(minosoft("dummy"), BlockSettings()), CustomBlockCulling {

View File

@ -36,12 +36,21 @@ object FaceCulling {
// impossible to see that face
return true
}
if (neighbourProperties.transparency == null) {
for (property in neighbourProperties.faces) {
if (property.transparency != TextureTransparencies.OPAQUE) continue
if (!properties.isCoveredBy(property)) continue
return true
}
}
if (state.block is CustomBlockCulling) {
return state.block.shouldCull(state, properties, direction, neighbour)
}
if (neighbourProperties.transparency == null) return false // can not determinate it
if (neighbourProperties.transparency == null) {
return false
}
if (state.block != neighbour.block) return false
if (neighbourProperties.transparency == properties.transparency) return true
@ -59,17 +68,26 @@ object FaceCulling {
var area = 0.0f
for (quad in this.faces) {
val width = minOf(target.end.x, quad.end.x) - maxOf(quad.start.x, target.start.x)
val height = minOf(target.end.y, quad.end.y) - maxOf(quad.start.y, target.start.y)
area += width * height
area += quad.getSideArea(target)
}
return area
}
private fun FaceProperties.getSideArea(target: FaceProperties): Float {
val width = minOf(target.end.x, end.x) - maxOf(start.x, target.start.x)
val height = minOf(target.end.y, end.y) - maxOf(start.y, target.start.y)
return width * height
}
fun FaceProperties.isCoveredBy(properties: SideProperties): Boolean {
val area = properties.getSideArea(this)
return surface <= area
}
fun FaceProperties.isCoveredBy(properties: FaceProperties): Boolean {
val area = properties.getSideArea(this)
return surface <= area
}
}