rework some fluid models and rendering

This commit is contained in:
Bixilon 2023-09-14 23:22:50 +02:00
parent 67512e93e6
commit 5231b68e4a
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
11 changed files with 88 additions and 60 deletions

View File

@ -222,7 +222,7 @@ testing {
options {
val options = this as TestNGOptions
options.preserveOrder = true
options.excludeGroups("chunk", "input", "font", "command", "registry", "biome", "version", "fluid", "world", "raycasting", "pixlyzer", "item", "block", "physics", "light", "packet", "container", "item_stack", "signature", "private_key", "interaction", "item_digging", "world_renderer", "rendering")
options.excludeGroups("chunk", "input", "font", "command", "registry", "biome", "version", "fluid", "world", "raycasting", "pixlyzer", "item", "block", "physics", "light", "packet", "container", "item_stack", "signature", "private_key", "interaction", "item_digging", "chunk_renderer", "rendering")
}
}
}

View File

@ -22,7 +22,7 @@ import de.bixilon.minosoft.gui.rendering.RenderTestUtil.frame
import org.testng.Assert
import org.testng.annotations.Test
@Test(groups = ["world_renderer"], dependsOnGroups = ["rendering", "block"])
@Test(groups = ["chunk_renderer"], dependsOnGroups = ["rendering", "block"])
class ChunkRendererTest {
private fun create(): ChunkRenderer {

View File

@ -0,0 +1,42 @@
/*
* Minosoft
* Copyright (C) 2020-2023 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.chunk.mesher
import de.bixilon.kotlinglm.vec3.Vec3i
import de.bixilon.kutil.cast.CastUtil.unsafeNull
import de.bixilon.minosoft.data.registries.fluid.fluids.LavaFluid
import de.bixilon.minosoft.data.registries.fluid.fluids.WaterFluid
import de.bixilon.minosoft.gui.rendering.chunk.mesh.ChunkMesh
import org.testng.annotations.Test
@Test(groups = ["mesher"], dependsOnGroups = ["rendering", "block"], enabled = false)
class FluidSectionMesherTest {
private var water: WaterFluid = unsafeNull()
private var lava: LavaFluid = unsafeNull()
@Test(priority = -1)
fun load() {
}
private fun mesh(data: Map<Vec3i, Any>): ChunkMesh {
TODO()
}
fun `simple water without surrounding blocks`() {
val mesh = mesh(mapOf(Vec3i(2, 2, 2) to water))
TODO()
}
}

View File

@ -26,6 +26,7 @@ import de.bixilon.minosoft.data.world.World
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.RenderingStates
import de.bixilon.minosoft.gui.rendering.chunk.mesh.VisibleMeshes
import de.bixilon.minosoft.gui.rendering.chunk.mesher.ChunkMesher
import de.bixilon.minosoft.gui.rendering.chunk.queue.CulledQueue
import de.bixilon.minosoft.gui.rendering.chunk.queue.QueuePosition
import de.bixilon.minosoft.gui.rendering.chunk.queue.loading.MeshLoadingQueue

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.chunk
package de.bixilon.minosoft.gui.rendering.chunk.mesher
import de.bixilon.kutil.concurrent.pool.runnable.InterruptableRunnable
import de.bixilon.minosoft.gui.rendering.chunk.ChunkRenderer
import de.bixilon.minosoft.gui.rendering.chunk.WorldQueueItem
import de.bixilon.minosoft.gui.rendering.chunk.mesh.ChunkMesh
import de.bixilon.minosoft.gui.rendering.chunk.mesher.FluidSectionMesher
import de.bixilon.minosoft.gui.rendering.chunk.mesher.SolidSectionMesher
import de.bixilon.minosoft.gui.rendering.chunk.queue.meshing.tasks.MeshPrepareTask
import de.bixilon.minosoft.gui.rendering.chunk.util.ChunkRendererUtil.smallMesh
import de.bixilon.minosoft.util.chunk.ChunkUtil

View File

@ -35,6 +35,7 @@ import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.chunk.mesh.ChunkMesh
import de.bixilon.minosoft.gui.rendering.chunk.mesh.SingleChunkMesh
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull.FaceCulling
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull.side.FaceProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.getMesh
import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus
@ -44,7 +45,6 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.chunkPosition
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.inChunkPosition
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
import de.bixilon.minosoft.util.KUtil.isTrue
import java.util.*
import kotlin.math.atan2
class FluidSectionMesher(
@ -53,13 +53,20 @@ class FluidSectionMesher(
private val water = context.connection.registries.fluid[WaterFluid]
private val tints = context.tints
private fun BlockState.getFluid(): Fluid? {
val block = block
return when {
block is FluidHolder -> block.fluid
water != null && isWaterlogged() -> water
else -> null
}
}
// ToDo: Should this be combined with the solid renderer (but we'd need to render faces twice, because of cullface)
fun mesh(chunkPosition: Vec2i, sectionHeight: Int, chunk: Chunk, section: ChunkSection, neighbourChunks: Array<Chunk>, neighbours: Array<ChunkSection?>, mesh: ChunkMesh) {
val blocks = section.blocks
val random = Random(0L)
var blockState: BlockState
var position: Vec3i
var rendered = false
var tint: Int
@ -73,17 +80,11 @@ class FluidSectionMesher(
for (y in blocks.minPosition.y..blocks.maxPosition.y) {
for (z in blocks.minPosition.z..blocks.maxPosition.z) {
for (x in blocks.minPosition.x..blocks.maxPosition.x) {
blockState = blocks[x, y, z] ?: continue
val block = blockState.block
val fluid = when {
block is FluidHolder -> block.fluid
water != null && blockState.isWaterlogged() -> water
else -> continue
}
val state = blocks[x, y, z] ?: continue
val fluid = state.getFluid() ?: continue
val model = fluid.model ?: continue
val stillTexture = model.still ?: continue
val flowingTexture = model.flowing ?: continue
val height = fluid.getHeight(blockState)
val height = fluid.getHeight(state)
position = Vec3i(offsetX + x, offsetY + y, offsetZ + z)
tint = tints.getFluidTint(chunk, fluid, height, position.x, position.y, position.z) ?: Colors.WHITE
@ -97,7 +98,7 @@ class FluidSectionMesher(
return true
}
return FaceCulling.canCull(blockState, model.properties, direction, neighbour)
return FaceCulling.canCull(state, FaceProperties(Vec2.EMPTY, Vec2(1.0f), model.transparency), direction, neighbour)
}
val topBlock = if (y == ProtocolDefinition.SECTION_MAX_Y) {
@ -129,7 +130,7 @@ class FluidSectionMesher(
val offsetPosition = Vec3(position - cameraOffset)
if (!skip[Directions.O_UP]) {
val velocity = fluid.getVelocity(blockState, position, chunk)
val velocity = fluid.getVelocity(state, position, chunk)
val still = velocity.x == 0.0 && velocity.z == 0.0
val texture: Texture
val minUV = Vec2.EMPTY
@ -145,9 +146,9 @@ class FluidSectionMesher(
if (still) {
texture = stillTexture
texture = model.still
} else {
texture = flowingTexture
texture = model.flowing
maxUV.x = 0.5f
val atan = atan2(velocity.x, velocity.z).toFloat()
@ -232,9 +233,9 @@ class FluidSectionMesher(
TEXTURE_2,
)
val meshToUse = flowingTexture.transparency.getMesh(mesh)
val meshToUse = model.flowing.transparency.getMesh(mesh)
val fluidLight = chunk.light[x, offsetY + y, z]
addFluidVertices(meshToUse, positions, texturePositions, flowingTexture, tint, fluidLight)
addFluidVertices(meshToUse, positions, texturePositions, model.flowing, tint, fluidLight)
rendered = true
}
@ -273,21 +274,21 @@ class FluidSectionMesher(
return 1.0f
}
val blockState = chunk[inChunkPosition]
if (blockState == null) {
val state = chunk[inChunkPosition]
if (state == null) {
count++
continue
}
if (!fluid.matches(blockState)) {
if (!fluid.matches(state)) {
// TODO: this was !blockState.material.solid
if (blockState.block !is CollidableBlock || blockState.block.getCollisionShape(EmptyCollisionContext, blockPosition, blockState, null) == AbstractVoxelShape.EMPTY) {
if (state.block !is CollidableBlock || state.block.getCollisionShape(EmptyCollisionContext, blockPosition, state, null) == AbstractVoxelShape.EMPTY) {
count++
}
continue
}
val height = fluid.getHeight(blockState)
val height = fluid.getHeight(state)
if (height >= 0.8f) {
totalHeight += height * 10.0f
@ -307,13 +308,5 @@ class FluidSectionMesher(
private val TEXTURE_1 = Vec2(0.0f, 0.5f)
private val TEXTURE_2 = Vec2(0.5f, 0.5f)
/*
private val FLUID_FACE_PROPERTY = FaceProperties(
Vec2.EMPTY,
Vec2(1.0f, 1.0f),
TextureTransparencies.OPAQUE,
)
*/
}
}

View File

@ -51,9 +51,8 @@ data class SingleBlockStateApply(
for (index in 0 until VERTEX_DATA_COMPONENTS) {
val offset = index * 3
val y = this[offset + 1]
val z = this[offset + 2]
this[offset + 1] = z
this[offset + 1] = this[offset + 2]
this[offset + 2] = -y + 1.0f
}
}
@ -78,9 +77,8 @@ data class SingleBlockStateApply(
for (index in 0 until VERTEX_DATA_COMPONENTS) {
val offset = index * 3
val x = this[offset + 0]
val z = this[offset + 2]
this[offset + 0] = -z + 1.0f // translates to origin and back; same as -(z-0.5f) + 0.5f
this[offset + 0] = -this[offset + 2] + 1.0f // translates to origin and back; same as -(z-0.5f) + 0.5f
this[offset + 2] = x
}
}

View File

@ -14,15 +14,15 @@
package de.bixilon.minosoft.gui.rendering.models.fluid
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull.side.FaceProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
import de.bixilon.minosoft.gui.rendering.tint.TintProvider
interface FluidModel {
val tint: TintProvider? get() = null
val still: Texture?
val flowing: Texture?
val properties: FaceProperties
val still: Texture
val flowing: Texture
val transparency: TextureTransparencies
fun load(context: RenderContext)
}

View File

@ -13,20 +13,18 @@
package de.bixilon.minosoft.gui.rendering.models.fluid.fluids
import de.bixilon.kotlinglm.vec2.Vec2
import de.bixilon.kutil.cast.CastUtil.unsafeNull
import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull.side.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.fluid.FluidModel
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY
class LavaFluidModel : FluidModel {
override var still: Texture? = null
override var flowing: Texture? = null
override var properties = FaceProperties(Vec2.EMPTY, Vec2(1.0f), TextureTransparencies.OPAQUE) // TODO: determinate by texture
override var still: Texture = unsafeNull()
override var flowing: Texture = unsafeNull()
override val transparency = TextureTransparencies.OPAQUE// TODO: from texture
override fun load(context: RenderContext) {
still = context.textures.staticTextures.createTexture(STILL)

View File

@ -13,24 +13,22 @@
package de.bixilon.minosoft.gui.rendering.models.fluid.fluids
import de.bixilon.kotlinglm.vec2.Vec2
import de.bixilon.kutil.cast.CastUtil.unsafeNull
import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft
import de.bixilon.minosoft.gui.rendering.RenderContext
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull.side.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.fluid.FluidModel
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
import de.bixilon.minosoft.gui.rendering.tint.TintProvider
import de.bixilon.minosoft.gui.rendering.tint.WaterTintProvider
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2Util.EMPTY
class WaterFluidModel : FluidModel {
override val tint: TintProvider = WaterTintProvider
override var still: Texture? = null
override var flowing: Texture? = null
override var properties = FaceProperties(Vec2.EMPTY, Vec2(1.0f), TextureTransparencies.TRANSLUCENT) // TODO: determinate by texture
override var still: Texture = unsafeNull()
override var flowing: Texture = unsafeNull()
override val transparency = TextureTransparencies.TRANSLUCENT// TODO: from texture
override fun load(context: RenderContext) {
still = context.textures.staticTextures.createTexture(STILL)

View File

@ -33,9 +33,7 @@ class FluidModelLoader(private val loader: ModelLoader) {
}
private fun load(fluid: Fluid) {
if (fluid.model != null) {
return
}
if (fluid.model != null) return
val model = fluid.createModel() ?: return
fluid.model = model
model.load(context)