fluid culling

This commit is contained in:
Bixilon 2021-11-24 16:51:43 +01:00
parent f2247e7fa3
commit b907ae65e7
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
14 changed files with 69 additions and 40 deletions

View File

@ -16,7 +16,6 @@ import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.registries.Registries
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3dUtil.EMPTY
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
@ -28,9 +27,6 @@ abstract class FlowableFluid(
registries: Registries,
data: Map<String, Any>,
) : Fluid(resourceLocation, registries, data) {
abstract val flowingTextureName: ResourceLocation
var flowingTexture: AbstractTexture? = null
abstract fun getVelocityMultiplier(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i): Double

View File

@ -40,7 +40,9 @@ open class Fluid(
) : RegistryItem() {
open val tintProvider: TintProvider? = null
open val stillTextureName: ResourceLocation? = null
open val flowingTextureName: ResourceLocation? = null
var stillTexture: AbstractTexture? = null
var flowingTexture: AbstractTexture? = null
val dripParticle: ParticleType? = null
val bucketItem: Item? = null

View File

@ -1,10 +1,11 @@
package de.bixilon.minosoft.gui.rendering.models
import de.bixilon.minosoft.gui.rendering.models.properties.AbstractFaceProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
object CullUtil {
fun Array<FaceProperties>.canCull(properties: FaceProperties, blockCull: Boolean): Boolean {
fun Array<AbstractFaceProperties>.canCull(properties: AbstractFaceProperties, blockCull: Boolean): Boolean {
// ToDo: Sometimes faces get drawn between stairs (we need to swap xy with yx in special cases)
val sizeStartX = properties.sizeStart.x
val sizeStartY = properties.sizeStart.y

View File

@ -15,8 +15,8 @@ package de.bixilon.minosoft.gui.rendering.models.baked
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.gui.rendering.models.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
import de.bixilon.minosoft.gui.rendering.models.properties.AbstractFaceProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
import glm_.vec3.Vec3i
@ -24,11 +24,11 @@ import java.util.*
class MultipartBakedModel(
val models: Array<BakedBlockModel>,
val sizes: Array<Array<FaceProperties>>,
val sizes: Array<Array<AbstractFaceProperties>>,
val particleTexture: AbstractTexture?,
) : BakedBlockModel {
override fun getTouchingFaceProperties(random: Random, direction: Directions): Array<FaceProperties> {
override fun getTouchingFaceProperties(random: Random, direction: Directions): Array<AbstractFaceProperties> {
return sizes[direction.ordinal]
}

View File

@ -15,8 +15,8 @@ package de.bixilon.minosoft.gui.rendering.models.baked
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.gui.rendering.models.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.baked.block.BakedBlockModel
import de.bixilon.minosoft.gui.rendering.models.properties.AbstractFaceProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.util.VecUtil
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
@ -38,7 +38,7 @@ class WeightedBakedModel(
this.totalWeight = totalWeight
}
override fun getTouchingFaceProperties(random: Random, direction: Directions): Array<FaceProperties> {
override fun getTouchingFaceProperties(random: Random, direction: Directions): Array<AbstractFaceProperties> {
return getModel(random).getTouchingFaceProperties(random, direction)
}

View File

@ -15,8 +15,8 @@ package de.bixilon.minosoft.gui.rendering.models.baked.block
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.gui.rendering.models.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModel
import de.bixilon.minosoft.gui.rendering.models.properties.AbstractFaceProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.world.mesh.WorldMesh
import glm_.vec3.Vec3i
@ -24,7 +24,7 @@ import java.util.*
interface BakedBlockModel : BakedModel {
fun getTouchingFaceProperties(random: Random, direction: Directions): Array<FaceProperties>
fun getTouchingFaceProperties(random: Random, direction: Directions): Array<AbstractFaceProperties>
fun singleRender(position: Vec3i, mesh: WorldMesh, random: Random, blockState: BlockState, neighbours: Array<BlockState?>, light: ByteArray, ambientLight: FloatArray, tints: IntArray?): Boolean

View File

@ -16,7 +16,7 @@ package de.bixilon.minosoft.gui.rendering.models.baked.block
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.gui.rendering.models.CullUtil.canCull
import de.bixilon.minosoft.gui.rendering.models.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.properties.AbstractFaceProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.util.VecUtil
import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset
@ -28,11 +28,11 @@ import java.util.*
class BakedBlockStateModel(
private val faces: Array<Array<BakedFace>>,
private val touchingFaceProperties: Array<Array<FaceProperties>>,
private val touchingFaceProperties: Array<Array<AbstractFaceProperties>>,
private val particleTexture: AbstractTexture?,
) : BakedBlockModel {
override fun getTouchingFaceProperties(random: Random, direction: Directions): Array<FaceProperties> {
override fun getTouchingFaceProperties(random: Random, direction: Directions): Array<AbstractFaceProperties> {
return touchingFaceProperties[direction.ordinal]
}
@ -49,7 +49,7 @@ class BakedBlockStateModel(
val direction = Directions.VALUES[index]
val neighbour = neighbours[index]
val neighboursModel = neighbour?.blockModel
var neighbourProperties: Array<FaceProperties>? = null
var neighbourProperties: Array<AbstractFaceProperties>? = null
if (neighboursModel != null) {
random.setSeed(VecUtil.generatePositionHash(position.x + direction.vector.x, position.y + direction.vector.y, position.z + direction.vector.z))
neighbourProperties = neighboursModel.getTouchingFaceProperties(random, direction.inverted)

View File

@ -16,7 +16,7 @@ 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.text.RGBColor
import de.bixilon.minosoft.gui.rendering.models.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.properties.AbstractFaceProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh
@ -37,7 +37,7 @@ class BakedFace(
val cullFace: Directions?,
val texture: AbstractTexture,
val touching: Boolean,
) : FaceProperties {
) : AbstractFaceProperties {
override val transparency: TextureTransparencies
get() = texture.transparency // ToDo

View File

@ -11,12 +11,12 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.models
package de.bixilon.minosoft.gui.rendering.models.properties
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
import glm_.vec2.Vec2
interface FaceProperties {
interface AbstractFaceProperties {
val sizeStart: Vec2
val sizeEnd: Vec2
val transparency: TextureTransparencies

View File

@ -0,0 +1,10 @@
package de.bixilon.minosoft.gui.rendering.models.properties
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
import glm_.vec2.Vec2
data class FaceProperties(
override val sizeStart: Vec2,
override val sizeEnd: Vec2,
override val transparency: TextureTransparencies,
) : AbstractFaceProperties

View File

@ -17,10 +17,10 @@ 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.FaceProperties
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
import de.bixilon.minosoft.gui.rendering.models.properties.AbstractFaceProperties
import de.bixilon.minosoft.gui.rendering.models.unbaked.GenericUnbakedModel
import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedBlockModel
import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel
@ -86,7 +86,7 @@ data class UnbakedBlockStateModel(
val faces: Array<MutableList<BakedFace>> = Array(Directions.SIZE) { mutableListOf() }
val touchingFaceProperties: Array<MutableList<FaceProperties>> = Array(Directions.SIZE) { mutableListOf() }
val touchingFaceProperties: Array<MutableList<AbstractFaceProperties>> = Array(Directions.SIZE) { mutableListOf() }
for (element in model.elements) {
for (face in element.faces) {
@ -169,7 +169,7 @@ data class UnbakedBlockStateModel(
finalFaces[index] = faceArray.toTypedArray()
}
val finalTouchingProperties: Array<Array<FaceProperties>?> = arrayOfNulls(faces.size)
val finalTouchingProperties: Array<Array<AbstractFaceProperties>?> = arrayOfNulls(faces.size)
for ((index, sizeArray) in touchingFaceProperties.withIndex()) {
finalTouchingProperties[index] = sizeArray.toTypedArray()
}

View File

@ -2,10 +2,10 @@ 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.FaceProperties
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.properties.AbstractFaceProperties
import de.bixilon.minosoft.gui.rendering.models.unbaked.UnbakedModel
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY
@ -19,7 +19,7 @@ class UnbakedMultipartModel(
override fun bake(renderWindow: RenderWindow): BakedModel {
val baked: Array<BakedBlockModel?> = arrayOfNulls(this.models.size)
val sizes: Array<MutableList<FaceProperties>> = Array(Directions.SIZE) { mutableListOf() }
val sizes: Array<MutableList<AbstractFaceProperties>> = Array(Directions.SIZE) { mutableListOf() }
var particleTexture: AbstractTexture? = null
for ((index, model) in this.models.withIndex()) {
@ -35,7 +35,7 @@ class UnbakedMultipartModel(
}
baked[index] = bakedModel
}
val finalFaces: Array<Array<FaceProperties>?> = arrayOfNulls(Directions.SIZE)
val finalFaces: Array<Array<AbstractFaceProperties>?> = arrayOfNulls(Directions.SIZE)
for (index in 0 until Directions.SIZE) {
finalFaces[index] = sizes[index].toTypedArray()
}

View File

@ -136,7 +136,7 @@ class WorldRenderer(
connection.registries.fluidRegistry.forEachItem {
if (it is FlowableFluid) {
it.flowingTexture = renderWindow.textureManager.staticTextures.createTexture(it.flowingTextureName.texture())
it.flowingTexture = renderWindow.textureManager.staticTextures.createTexture(it.flowingTextureName!!.texture())
}
it.stillTexture = it.stillTextureName?.let { texture -> renderWindow.textureManager.staticTextures.createTexture(texture.texture()) }
}

View File

@ -12,8 +12,12 @@ import de.bixilon.minosoft.data.world.Chunk
import de.bixilon.minosoft.data.world.ChunkSection
import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.models.CullUtil.canCull
import de.bixilon.minosoft.gui.rendering.models.properties.FaceProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.AbstractTexture
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh
import de.bixilon.minosoft.gui.rendering.util.VecUtil
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotate
@ -29,6 +33,7 @@ import glm_.vec2.Vec2
import glm_.vec2.Vec2i
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
import java.util.*
import kotlin.math.atan2
class FluidCullSectionPreparer(
@ -70,15 +75,18 @@ class FluidCullSectionPreparer(
block is FluidFillable -> block.fluid
else -> continue
}
val stillTexture = fluid.stillTexture ?: continue
val flowingTexture = fluid.flowingTexture ?: continue
position = Vec3i(offsetX + x, offsetY + y, offsetZ + z)
tints = tintManager.getAverageTint(chunk, neighbourChunks, blockState, fluid, position.x, position.y, position.z)
val skipTop = fluid.matches(chunk.get(x, offsetY + y + 1, z))
val skipBottom = !shouldRenderSide(position, Directions.DOWN)
val skipNorth = !shouldRenderSide(position, Directions.NORTH)
val skipSouth = !shouldRenderSide(position, Directions.SOUTH)
val skipWest = !shouldRenderSide(position, Directions.WEST)
val skipEast = !shouldRenderSide(position, Directions.EAST)
// ToDo
val skipBottom = !shouldRenderSide(position, Directions.DOWN, fluid, flowingTexture) /* ToDo */
val skipNorth = !shouldRenderSide(position, Directions.NORTH, fluid, flowingTexture)
val skipSouth = !shouldRenderSide(position, Directions.SOUTH, fluid, flowingTexture)
val skipWest = !shouldRenderSide(position, Directions.WEST, fluid, flowingTexture)
val skipEast = !shouldRenderSide(position, Directions.EAST, fluid, flowingTexture)
if (skipTop && skipBottom && skipNorth && skipSouth && skipWest && skipEast) {
continue
@ -189,6 +197,7 @@ class FluidCullSectionPreparer(
v2 = cornerHeights[2]
}
}
// ToDo: Prevent face fighting with transparent neighbours
val positions = arrayOf(
Vec3(position.x + faceX, position.y + v1, position.z + faceZ),
@ -203,11 +212,9 @@ class FluidCullSectionPreparer(
Vec2(0.0f, v1 / 2),
)
val texture = (fluid as FlowableFluid).flowingTexture!!
val meshToUse = texture.transparency.getMesh(mesh)
val meshToUse = flowingTexture.transparency.getMesh(mesh)
for ((positionIndex, textureIndex) in meshToUse.order) {
meshToUse.addVertex(positions[positionIndex].array, texturePositions[textureIndex], texture, tints?.get(0) ?: 0xFFFFFF, 0xFF)
meshToUse.addVertex(positions[positionIndex].array, texturePositions[textureIndex], flowingTexture, tints?.get(0) ?: 0xFFFFFF, chunk.getLight(position))
}
rendered = true
}
@ -229,12 +236,25 @@ class FluidCullSectionPreparer(
return mesh
}
private fun isSideCovered(position: Vec3i, direction: Directions, height: Float): Boolean {
return world[position + direction] != null
private fun isSideCovered(position: Vec3i, direction: Directions, texture: AbstractTexture, height: Float): Boolean {
val faceProperties = FaceProperties(
Vec2.EMPTY,
Vec2(1.0f, height),
TextureTransparencies.OPAQUE,
)
val neighbourPosition = position + direction
val neighbour = world[neighbourPosition] ?: return false
val model = neighbour.blockModel ?: return false
val random = Random(VecUtil.generatePositionHash(neighbourPosition.x, neighbourPosition.y, neighbourPosition.z))
val size = model.getTouchingFaceProperties(random, direction.inverted)
return size.canCull(faceProperties, false)
}
private fun shouldRenderSide(position: Vec3i, direction: Directions, height: Float = 1.0f): Boolean {
return !isSideCovered(position, direction, height) /* && fluid.matches(other) */
private fun shouldRenderSide(position: Vec3i, direction: Directions, fluid: Fluid, texture: AbstractTexture, height: Float = 1.0f): Boolean {
if (fluid.matches(world[position + direction])) {
return false
}
return !isSideCovered(position, direction, texture, height)
}
private fun getCornerHeight(position: Vec3i, fluid: Fluid): Float {