wip element rotation

This commit is contained in:
Moritz Zwerger 2023-08-01 03:14:53 +02:00
parent 17f7c96a2b
commit e858e6a1d9
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
7 changed files with 87 additions and 31 deletions

View File

@ -25,6 +25,7 @@ import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import org.testng.Assert
import kotlin.math.abs
object BakedModelTestUtil {
private val texture = Minosoft::class.java.getResourceAsStream("/assets/minosoft/textures/debug.png")!!.readAllBytes()
@ -56,9 +57,18 @@ object BakedModelTestUtil {
if (faces.size != 1) throw IllegalArgumentException("Model has more/less than once face: ${faces.size}!")
val face = faces.first()
vertices?.let { Assert.assertEquals(face.positions, it, "Vertices mismatch") }
vertices?.let { assertMatches(face.positions, it, "Vertices mismatch") }
uv?.let { if (!face.uv.contentEquals(it)) throw AssertionError("UV mismatch, expected [${uv[0]}|${uv[1]}], but got [${face.uv[0]}|${face.uv[1]}]") } // printing the first element is fine, it is always clockwise
shade?.let { Assert.assertEquals(face.shade, it, "Shade mismatch") }
texture?.toResourceLocation()?.texture()?.let { Assert.assertEquals(face.texture, it, "Texture mismatch") }
}
private fun assertMatches(actual: FloatArray, expected: FloatArray, message: String) {
if (actual.size != expected.size) throw AssertionError("Size mismatch!")
for (i in actual.indices) {
val delta = abs(actual[i] - expected[i])
if (delta > 0.01f) throw AssertionError("$message: Delta is too high at index $i: ${actual[i]}, expected ${expected[i]}")
}
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.models.baked.rotation
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.identified.Namespaces.minecraft
import de.bixilon.minosoft.gui.rendering.models.ModelTestUtil.bake
import de.bixilon.minosoft.gui.rendering.models.ModelTestUtil.rbgy
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModelTestUtil.assertFace
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModelTestUtil.createFaces
import de.bixilon.minosoft.gui.rendering.models.baked.BakedModelTestUtil.createTextureManager
import de.bixilon.minosoft.gui.rendering.models.block.BlockModel
import de.bixilon.minosoft.gui.rendering.models.block.element.ElementRotation
import de.bixilon.minosoft.gui.rendering.models.block.element.ModelElement
import de.bixilon.minosoft.gui.rendering.models.block.state.apply.SingleBlockStateApply
import de.bixilon.minosoft.gui.rendering.textures.TextureUtil.texture
import org.testng.annotations.Test
@Test(groups = ["models"])
class ElementRotationTest {
private fun block(rotation: ElementRotation): SingleBlockStateApply {
val from = Vec3(0.0f)
val to = Vec3(1.0f)
return SingleBlockStateApply(BlockModel(elements = listOf(ModelElement(from, to, faces = createFaces(), rotation = rotation)), textures = mapOf("test" to minecraft("block/test").texture())))
}
fun `rotate block around origin 45 degree on the y axis`() {
val model = block(ElementRotation(axis = Axes.Y, angle = 45.0f))
val baked = model.bake(createTextureManager("block/test"))!!
baked.assertFace(Directions.UP, floatArrayOf(-0.2f, 1.0f, 0.5f, 0.5f, 1.0f, -0.2f, 1.2f, 1.0f, 0.5f, 0.5f, 1.0f, 1.2f), rbgy, 1.0f)
}
fun `rotate block around origin -45 degree on the y axis`() {
val model = block(ElementRotation(axis = Axes.Y, angle = -45.0f))
val baked = model.bake(createTextureManager("block/test"))!!
baked.assertFace(Directions.UP, floatArrayOf(0.5f, 1.0f, -0.2f, 1.2f, 1.0f, 0.5f, 0.5f, 1.0f, 1.2f, -0.2f, 1.0f, 0.5f), rbgy, 1.0f)
}
// TODO: a,z axis
}

View File

@ -14,20 +14,16 @@
package de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull
import de.bixilon.kotlinglm.vec2.Vec2
import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kutil.exception.Broken
import de.bixilon.minosoft.data.direction.Directions
import de.bixilon.minosoft.data.registries.blocks.settings.BlockSettings
import de.bixilon.minosoft.data.registries.blocks.state.BlockState
import de.bixilon.minosoft.data.registries.blocks.types.Block
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakedFace
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.BakedModel
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull.side.FaceProperties
import de.bixilon.minosoft.gui.rendering.models.block.state.baked.cull.side.SideProperties
import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparencies
import de.bixilon.minosoft.gui.rendering.system.base.texture.texture.memory.MemoryTexture
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import org.testng.Assert.assertFalse
import org.testng.Assert.assertTrue
import org.testng.annotations.Test
@ -35,8 +31,8 @@ import org.testng.annotations.Test
@Test(groups = ["models", "culling"])
class FaceCullingTest {
private fun createFace(transparency: TextureTransparencies = TextureTransparencies.OPAQUE, properties: FaceProperties? = FaceProperties(Vec2(0), Vec2(1), transparency)): BakedFace {
return BakedFace(floatArrayOf(), floatArrayOf(), 1.0f, -1, null, MemoryTexture(Vec2i.EMPTY), properties)
private fun createFace(transparency: TextureTransparencies = TextureTransparencies.OPAQUE, properties: FaceProperties? = FaceProperties(Vec2(0), Vec2(1), transparency)): FaceProperties? {
return properties
}
private fun createBlock(transparency: TextureTransparencies = TextureTransparencies.OPAQUE, properties: SideProperties? = SideProperties(arrayOf(FaceProperties(Vec2(0), Vec2(1), transparency)), transparency), type: Int = 0): BlockState {
@ -228,7 +224,7 @@ class FaceCullingTest {
val block = object : Block(minosoft("dummy"), BlockSettings()), CustomBlockCulling {
override val hardness get() = Broken()
override fun shouldCull(state: BlockState, face: BakedFace, directions: Directions, neighbour: BlockState): Boolean {
override fun shouldCull(state: BlockState, properties: FaceProperties, directions: Directions, neighbour: BlockState): Boolean {
throw AssertionError("shouldCall invoked!")
}
}
@ -244,7 +240,7 @@ class FaceCullingTest {
private fun forceNoCull() = object : Block(minosoft("dummy"), BlockSettings()), CustomBlockCulling {
override val hardness get() = Broken()
override fun shouldCull(state: BlockState, face: BakedFace, directions: Directions, neighbour: BlockState): Boolean {
override fun shouldCull(state: BlockState, properties: FaceProperties, directions: Directions, neighbour: BlockState): Boolean {
return false
}
}

View File

@ -13,23 +13,30 @@
package de.bixilon.minosoft.gui.rendering.models.block.element
import de.bixilon.kotlinglm.func.rad
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.kutil.json.JsonObject
import de.bixilon.kutil.primitive.BooleanUtil.toBoolean
import de.bixilon.kutil.primitive.FloatUtil.toFloat
import de.bixilon.minosoft.data.Axes
import de.bixilon.minosoft.data.entities.EntityRotation.Companion.CIRCLE_DEGREE
import de.bixilon.minosoft.gui.rendering.models.block.element.ModelElement.Companion.BLOCK_SIZE
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.rotateAssign
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.toVec3
data class ElementRotation(
val origin: Vec3,
val origin: Vec3 = ORIGIN,
val axis: Axes,
val angle: Float,
val rescale: Boolean = false,
) {
fun apply(positions: FloatArray) {
// TODO("Can not rotate yet!")
val angle = -angle.rad
Vec3(0, positions).rotateAssign(angle, axis, origin, rescale)
Vec3(3, positions).rotateAssign(angle, axis, origin, rescale)
Vec3(6, positions).rotateAssign(angle, axis, origin, rescale)
Vec3(9, positions).rotateAssign(angle, axis, origin, rescale)
}
@ -37,7 +44,7 @@ data class ElementRotation(
private val ORIGIN = Vec3(0.5f)
fun deserialize(data: JsonObject): ElementRotation? {
val angle = data["angle"]?.toFloat() ?: return null
val angle = data["angle"]?.toFloat()?.mod(CIRCLE_DEGREE.toFloat()) ?: return null
if (angle == 0.0f) return null
val rescale = data["rescale"]?.toBoolean() ?: false

View File

@ -47,7 +47,7 @@ class BakedModel(
val direction = Directions.VALUES[directionIndex].inverted
for (face in faces) {
if (FaceCulling.canCull(state, face, direction, neighbour)) {
if (FaceCulling.canCull(state, face.properties, direction, neighbour)) {
continue
}
face.render(offset, mesh, light, tints)

View File

@ -22,10 +22,6 @@ import de.bixilon.minosoft.gui.rendering.system.base.texture.TextureTransparenci
object FaceCulling {
inline fun canCull(state: BlockState, face: BakedFace, direction: Directions, neighbour: BlockState?): Boolean {
return canCull(state, face.properties, direction, neighbour)
}
fun canCull(state: BlockState, properties: FaceProperties?, direction: Directions, neighbour: BlockState?): Boolean {
if (neighbour == null) return false
if (properties == null) return false

View File

@ -61,7 +61,7 @@ object Vec3Util {
fun rotate(x: Float, y: Float, sin: Float, cos: Float, rescale: Boolean): Vec2 {
val result = Vec2(x * cos - y * sin, x * sin + y * cos)
if (rescale) {
return result / cos
result /= cos
}
return result
}
@ -78,19 +78,6 @@ object Vec3Util {
}
}
fun Vec3.rotateAssign(rotation: Vec2, centerBlock: Boolean = false) {
if (centerBlock) {
this -= 0.5f
}
rotateAssign(-rotation.x, Axes.X)
rotateAssign(rotation.y, Axes.Y)
if (centerBlock) {
this += 0.5f
}
}
fun Vec3.rotateAssign(angle: Float, axis: Axes, origin: Vec3, rescale: Boolean) {
this -= origin
rotateAssign(angle, axis, rescale)