diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimationTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimationTest.kt index 05357bfbd..aad2d9d88 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimationTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/chunk/entities/renderer/storage/OpenCloseAnimationTest.kt @@ -24,8 +24,7 @@ import de.bixilon.minosoft.gui.rendering.skeletal.instance.SkeletalInstance import de.bixilon.minosoft.gui.rendering.skeletal.mesh.SkeletalMesh import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3Util.EMPTY import de.bixilon.minosoft.test.IT -import org.testng.Assert.assertEquals -import org.testng.Assert.assertTrue +import org.testng.Assert.* import org.testng.annotations.Test @Test(groups = ["skeletal", "block_entity_rendering"]) @@ -46,12 +45,13 @@ class OpenCloseAnimationTest { fun `correct playing and over state`() { val animation = create() - // TODO: assert not playing + assertFalse(animation.getInstance().animation.isPlaying(animation)) animation.open() - // TODO: assert playing + assertTrue(animation.getInstance().animation.isPlaying(animation)) animation.close() - // TODO: assert playing + assertTrue(animation.getInstance().animation.isPlaying(animation)) assertEquals(animation.draw(0.3f), OVER) + // assertFalse(animation.getInstance().animation.isPlaying(animation)) // animation is drawn directly, that is part of the animation manager } fun animation() { @@ -97,5 +97,8 @@ class OpenCloseAnimationTest { @JvmName("getProgress2") fun getProgress() = this.progress + + @JvmName("getInstance2") + fun getInstance() = this.instance } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/AnimationManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/AnimationManager.kt index 0cd45782b..68aaf43f8 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/AnimationManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/instance/AnimationManager.kt @@ -72,4 +72,7 @@ class AnimationManager(val instance: SkeletalInstance) { } lock.unlock() } + + fun isPlaying(animation: AbstractAnimation) = animation.name in playing + fun isPlaying(name: String) = name in playing } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/mesh/SkeletalConsumer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/mesh/SkeletalConsumer.kt index 209ea3cd9..4fda65a81 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/mesh/SkeletalConsumer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/mesh/SkeletalConsumer.kt @@ -13,10 +13,11 @@ package de.bixilon.minosoft.gui.rendering.skeletal.mesh +import de.bixilon.kotlinglm.vec3.Vec3 import de.bixilon.minosoft.gui.rendering.models.block.element.FaceVertexData import de.bixilon.minosoft.gui.rendering.system.base.texture.shader.ShaderTexture interface SkeletalConsumer { - fun addQuad(positions: FaceVertexData, uv: FaceVertexData, transform: Int, texture: ShaderTexture) + fun addQuad(positions: FaceVertexData, uv: FaceVertexData, transform: Int, normal: Vec3, texture: ShaderTexture) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/mesh/SkeletalMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/mesh/SkeletalMesh.kt index 2c3999848..c655f2250 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/mesh/SkeletalMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/mesh/SkeletalMesh.kt @@ -25,20 +25,35 @@ import de.bixilon.minosoft.gui.rendering.util.mesh.MeshStruct class SkeletalMesh(context: RenderContext, initialCacheSize: Int) : Mesh(context, SkeletalMeshStruct, initialCacheSize = initialCacheSize), SkeletalConsumer { override val order = context.system.quadOrder - private fun addVertex(position: FaceVertexData, positionOffset: Int, uv: FaceVertexData, uvOffset: Int, transform: Float, textureShaderId: Float) { + private fun addVertex(position: FaceVertexData, positionOffset: Int, uv: FaceVertexData, uvOffset: Int, transform: Float, normal: Float, textureShaderId: Float) { data.add( position[positionOffset + 0], position[positionOffset + 1], position[positionOffset + 2], uv[uvOffset + 0], uv[uvOffset + 1], - transform, textureShaderId + transform, normal, ) + data.add(textureShaderId) } - override fun addQuad(positions: FaceVertexData, uv: FaceVertexData, transform: Int, texture: ShaderTexture) { + private fun encodePart(part: Float): Int { + val unsigned = (part + 1.0f) / 2.0f // remove negative sign + return (unsigned * 15.0f).toInt() and 0x0F + } + + private fun encodeNormal(normal: Vec3): Int { + val x = encodePart(normal.x) + val y = encodePart(normal.y) + val z = encodePart(normal.z) + + return (y shl 8) or (z shl 4) or (x) + } + + override fun addQuad(positions: FaceVertexData, uv: FaceVertexData, transform: Int, normal: Vec3, texture: ShaderTexture) { val transform = transform.buffer() val textureShaderId = texture.shaderId.buffer() + val normal = encodeNormal(normal).buffer() order.iterate { position, uvIndex -> - addVertex(positions, position * Vec3.length, uv, uvIndex * Vec2.length, transform, textureShaderId) + addVertex(positions, position * Vec3.length, uv, uvIndex * Vec2.length, transform, normal, textureShaderId) } } @@ -47,6 +62,7 @@ class SkeletalMesh(context: RenderContext, initialCacheSize: Int) : Mesh(context val position: Vec3, val uv: Vec2, val transform: Int, + val normal: Int, val indexLayerAnimation: Int, ) { companion object : MeshStruct(SkeletalMeshStruct::class) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/elements/SkeletalFace.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/elements/SkeletalFace.kt index 697139418..3902ab2ab 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/elements/SkeletalFace.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/skeletal/model/elements/SkeletalFace.kt @@ -16,7 +16,6 @@ package de.bixilon.minosoft.gui.rendering.skeletal.model.elements import de.bixilon.kotlinglm.GLM import de.bixilon.kotlinglm.vec2.Vec2 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.ResourceLocation import de.bixilon.minosoft.gui.rendering.models.block.element.ModelElement.Companion.BLOCK_SIZE @@ -47,19 +46,24 @@ data class SkeletalFace( ).toArray(direction, 0) + val normal = Vec3(direction.vector) + for (rotation in context.rotations) { val origin = rotation.origin!! / BLOCK_SIZE val rad = -GLM.radians(rotation.value) val vec = Vec3(0, positions) + normal.rotateAssign(rad) + for (i in 0 until 4) { vec.ofs = i * Vec3.length - vec.rotateAssign(rad[0], Axes.X, origin, false) - vec.rotateAssign(rad[1], Axes.Y, origin, false) - vec.rotateAssign(rad[2], Axes.Z, origin, false) + vec.rotateAssign(rad, origin, false) } } - context.consumer.addQuad(positions, uvData, transform, texture.texture) + normal.normalizeAssign() + + + context.consumer.addQuad(positions, uvData, transform, normal, texture.texture) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt index a044965c7..b0c0630b0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/vec/vec3/Vec3Util.kt @@ -91,6 +91,20 @@ object Vec3Util { this += origin } + fun Vec3.rotateAssign(rad: Vec3, origin: Vec3, rescale: Boolean) { + this -= origin + rotateAssign(rad.x, Axes.X, rescale) + rotateAssign(rad.y, Axes.Y, rescale) + rotateAssign(rad.z, Axes.Z, rescale) + this += origin + } + + fun Vec3.rotateAssign(rad: Vec3) { + rotateAssign(rad.x, Axes.X, false) + rotateAssign(rad.y, Axes.Y, false) + rotateAssign(rad.z, Axes.Z, false) + } + operator fun Vec3.get(axis: Axes): Float { return when (axis) { Axes.X -> x diff --git a/src/main/resources/assets/minosoft/rendering/shader/skeletal/skeletal.vsh b/src/main/resources/assets/minosoft/rendering/shader/skeletal/skeletal.vsh index 670177aed..3aeaf867a 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/skeletal/skeletal.vsh +++ b/src/main/resources/assets/minosoft/rendering/shader/skeletal/skeletal.vsh @@ -16,7 +16,8 @@ layout (location = 0) in vec3 vinPosition; layout (location = 1) in vec2 vinUV; layout (location = 2) in float vinTransform; -layout (location = 3) in float vinIndexLayerAnimation;// texture index (0xF0000000), texture layer (0x0FFFF000), animation index (0x00000FFF) +layout (location = 3) in float vinNormal; +layout (location = 4) in float vinIndexLayerAnimation;// texture index (0xF0000000), texture layer (0x0FFFF000), animation index (0x00000FFF) #include "minosoft:animation/header_vertex" @@ -35,10 +36,39 @@ uniform uint uLight; #include "minosoft:animation/main_vertex" +float decodeNormal(uint data) { + return (data / 15.0f) * 2.0f - 1.0f; +} + +vec3 decodeNormal() { + uint combined = floatBitsToUint(vinNormal); + uint x = combined & 0x0Fu; + uint y = combined >> 8u & 0x0Fu; + uint z = combined >> 4u & 0x0Fu; + return vec3(decodeNormal(x), decodeNormal(y), decodeNormal(z)); +} + +vec3 transformNormal(vec3 normal, mat4 transform) { + // return normalize(mat3(transpose(inverse(transform))) * normal); + return mat3(transform) * normal; +} + +float getShade(vec3 normal) { + if (normal.y < -0.5f) return 0.5f; + if (normal.y > 0.5f) return 1.0f; + if (normal.x < -0.5f || normal.x > 0.5f) return 0.6f; + if (normal.z < -0.5f || normal.z > 0.5f) return 0.8f; + + return 1.0f; +} + void main() { - vec4 position = uSkeletalTransforms[floatBitsToUint(vinTransform)] * vec4(vinPosition, 1.0f); + mat4 transform = uSkeletalTransforms[floatBitsToUint(vinTransform)]; + vec4 position = transform * vec4(vinPosition, 1.0f); gl_Position = uViewProjectionMatrix * position; - finTintColor = getLight(uLight & 0xFFu); + vec3 normal = transformNormal(decodeNormal(), transform); + + finTintColor = getLight(uLight & 0xFFu) * vec4(vec3(getShade(normal)), 1.0f); finFragmentPosition = position.xyz; run_animation();