skeletal: shade lighting

This adds (and transforms as needed) a normal into the shader. Maybe interpolation will be done in the future
This commit is contained in:
Moritz Zwerger 2023-10-22 16:18:21 +02:00
parent 3eac315d62
commit e4a5cb597b
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
7 changed files with 89 additions and 18 deletions

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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

View File

@ -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();