From 70c9986accdd949d3835d715cdeea47e0f6b1b4c Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 26 May 2021 12:34:30 +0200 Subject: [PATCH] particle texture (sprite) animations --- .../gui/rendering/particle/ParticleMesh.kt | 7 +++- .../rendering/particle/ParticleRenderer.kt | 36 ++++++++++++----- .../minosoft/rendering/shader/chunk/chunk.vsh | 4 +- .../rendering/shader/particle/particle.fsh | 26 +++++++++--- .../rendering/shader/particle/particle.gsh | 30 +++++++++----- .../rendering/shader/particle/particle.vsh | 40 ++++++++++++++++--- 6 files changed, 107 insertions(+), 36 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleMesh.kt index 7e5b31b00..9a7d83cb3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleMesh.kt @@ -39,6 +39,7 @@ class ParticleMesh : Mesh() { texture.uvEnd.x, texture.uvEnd.y, Float.fromBits(textureLayer), + Float.fromBits(texture.properties.animation?.animationId ?: -1), scale, Float.fromBits(tintColor.rgba), )) @@ -58,15 +59,17 @@ class ParticleMesh : Mesh() { glEnableVertexAttribArray(index++) glVertexAttribPointer(index, 1, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.SIZE_BYTES, (7 * Float.SIZE_BYTES).toLong()) glEnableVertexAttribArray(index++) + glVertexAttribPointer(index, 1, GL_FLOAT, false, FLOATS_PER_VERTEX * Float.SIZE_BYTES, (8 * Float.SIZE_BYTES).toLong()) + glEnableVertexAttribArray(index++) super.unbind() } override fun draw() { glBindVertexArray(vao) - glDrawArrays(GL_POINTS, 0, 1) + glDrawArrays(GL_POINTS, 0, primitiveCount) } companion object { - private val FLOATS_PER_VERTEX = 8 + private val FLOATS_PER_VERTEX = 9 } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt index ade702e09..64a1381e8 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/particle/ParticleRenderer.kt @@ -21,25 +21,25 @@ import de.bixilon.minosoft.gui.rendering.RendererBuilder import de.bixilon.minosoft.gui.rendering.modding.events.CameraMatrixChangeEvent import de.bixilon.minosoft.gui.rendering.shader.Shader import de.bixilon.minosoft.gui.rendering.textures.Texture +import de.bixilon.minosoft.gui.rendering.textures.TextureArray import de.bixilon.minosoft.modding.event.CallbackEventInvoker import de.bixilon.minosoft.protocol.network.connection.PlayConnection import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import de.bixilon.minosoft.util.MMath import glm_.vec3.Vec3 +import java.util.concurrent.ThreadLocalRandom class ParticleRenderer( private val connection: PlayConnection, val renderWindow: RenderWindow, ) : Renderer { - private val particleShader = Shader( - resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"), - ) + private lateinit var particleShader: Shader private var particleMesh = ParticleMesh() private val texture = Texture(DUMMY_PARTICLE_RESOURCE_LOCATION) override fun init() { - particleShader.load() @@ -56,25 +56,39 @@ class ParticleRenderer( } override fun postInit() { + particleShader = Shader( + resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "particle"), + defines = mapOf("ANIMATED_TEXTURE_COUNT" to MMath.clamp(renderWindow.textures.animator.animatedTextures.size, 1, TextureArray.MAX_ANIMATED_TEXTURE)), + ) + particleShader.load() renderWindow.textures.use(particleShader, "textureArray") + renderWindow.textures.animator.use(particleShader, "AnimatedDataBuffer") } + var last = 0L override fun draw() { particleShader.use() - particleMesh.unload() + val time = System.currentTimeMillis() + if (time - last >= ProtocolDefinition.TICK_TIME * 2000) { + particleMesh.unload() - particleMesh = ParticleMesh() - - // thanks: https://gamedev.stackexchange.com/questions/113147/rotate-billboard-towards-camera - val position = Vec3(0, 6, 0) + particleMesh = ParticleMesh() - particleMesh.addVertex(position, 1.0f, texture, ChatColors.RED) + val random = ThreadLocalRandom.current() + fun randomFlot(min: Float, max: Float): Float { + return min + random.nextFloat() * (max - min) + } + for (i in 0 until 123456) { + particleMesh.addVertex(Vec3(randomFlot(0.0f, 200.0f), randomFlot(6.0f, 200.0f), randomFlot(0.0f, 200.0f)), randomFlot(0.05f, 0.2f), texture, ChatColors.getRandomColor()) + } - particleMesh.load() + particleMesh.load() + last = time + } particleMesh.draw() } diff --git a/src/main/resources/assets/minosoft/rendering/shader/chunk/chunk.vsh b/src/main/resources/assets/minosoft/rendering/shader/chunk/chunk.vsh index 575ee0f57..61d85318c 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/chunk/chunk.vsh +++ b/src/main/resources/assets/minosoft/rendering/shader/chunk/chunk.vsh @@ -33,7 +33,7 @@ uniform mat4 viewProjectionMatrix; layout(std140) uniform AnimatedDataBuffer { - uvec4 globalAnimationData[ANIMATED_TEXTURE_COUNT]; + uvec4 uAnimationData[ANIMATED_TEXTURE_COUNT]; }; #include "minosoft:color" @@ -52,7 +52,7 @@ void main() { return; } - uvec4 data = globalAnimationData[animationIndex]; + uvec4 data = uAnimationData[animationIndex]; uint firstTexture = data.x; uint secondTexture = data.y; uint interpolation = data.z; diff --git a/src/main/resources/assets/minosoft/rendering/shader/particle/particle.fsh b/src/main/resources/assets/minosoft/rendering/shader/particle/particle.fsh index de655ba1c..012cc3909 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/particle/particle.fsh +++ b/src/main/resources/assets/minosoft/rendering/shader/particle/particle.fsh @@ -13,20 +13,34 @@ #version 330 core -out vec4 outColor; +out vec4 foutColor; -flat in uint finTextureIndex; -in vec3 finTextureCoordinates; +flat in uint finTextureIndex1; +in vec3 finTextureCoordinates1; +flat in uint finTextureIndex2; +in vec3 finTextureCoordinates2; +flat in float finInterpolation; in vec4 finTintColor; #include "minosoft:texture" void main() { - vec4 texelColor = getTexture(finTextureIndex, finTextureCoordinates); - if (texelColor.a == 0.0f) { + vec4 texelColor1 = getTexture(finTextureIndex1, finTextureCoordinates1); + if (texelColor1.a == 0.0f) { discard; } - outColor = texelColor * finTintColor; + if (finInterpolation == 0.0f) { + foutColor = texelColor1 * finTintColor; + return; + } + + vec4 texelColor2 = getTexture(finTextureIndex2, finTextureCoordinates2); + + if (texelColor2.a == 0.0f) { + discard; + } + + foutColor = mix(texelColor1, texelColor2, finInterpolation) * finTintColor; } diff --git a/src/main/resources/assets/minosoft/rendering/shader/particle/particle.gsh b/src/main/resources/assets/minosoft/rendering/shader/particle/particle.gsh index b3e70c14f..3a6986d89 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/particle/particle.gsh +++ b/src/main/resources/assets/minosoft/rendering/shader/particle/particle.gsh @@ -24,8 +24,11 @@ uniform vec3 uCameraUp; in Vertex { - uint textureIndex; - uint textureLayer; + uint textureIndex1; + uint textureLayer1; + uint textureIndex2; + uint textureLayer2; + float interpolation; vec2 maxUVCoordinates; float scale; @@ -33,8 +36,11 @@ in Vertex } ginVertex[]; -flat out uint finTextureIndex; -out vec3 finTextureCoordinates; +flat out uint finTextureIndex1; +out vec3 finTextureCoordinates1; +flat out uint finTextureIndex2; +out vec3 finTextureCoordinates2; +flat out float finInterpolation; out vec4 finTintColor; @@ -43,24 +49,30 @@ void main() vec3 pointPosition = gl_in[0].gl_Position.xyz; - finTextureIndex = ginVertex[0].textureIndex; + finTextureIndex1 = ginVertex[0].textureIndex1; + finTextureIndex2 = ginVertex[0].textureIndex2; + finInterpolation = ginVertex[0].interpolation; finTintColor = ginVertex[0].tintColor; gl_Position = uViewProjectionMatrix * vec4(pointPosition - (uCameraRight - uCameraUp) * ginVertex[0].scale, 1.0); - finTextureCoordinates = vec3(0.0f, ginVertex[0].maxUVCoordinates.y, ginVertex[0].textureLayer); + finTextureCoordinates1 = vec3(0.0f, 0.0f, ginVertex[0].textureLayer1); + finTextureCoordinates2 = vec3(0.0f, 0.0f, ginVertex[0].textureLayer2); EmitVertex(); gl_Position = uViewProjectionMatrix * vec4(pointPosition - (uCameraRight + uCameraUp) * ginVertex[0].scale, 1.0); - finTextureCoordinates = vec3(0.0f, 0.0f, ginVertex[0].textureLayer); + finTextureCoordinates1 = vec3(0.0f, ginVertex[0].maxUVCoordinates.y, ginVertex[0].textureLayer1); + finTextureCoordinates2 = vec3(0.0f, ginVertex[0].maxUVCoordinates.y, ginVertex[0].textureLayer2); EmitVertex(); gl_Position = uViewProjectionMatrix * vec4(pointPosition + (uCameraRight + uCameraUp) * ginVertex[0].scale, 1.0); - finTextureCoordinates = vec3(ginVertex[0].maxUVCoordinates, ginVertex[0].textureLayer); + finTextureCoordinates1 = vec3(ginVertex[0].maxUVCoordinates.x, 0.0f, ginVertex[0].textureLayer1); + finTextureCoordinates2 = vec3(ginVertex[0].maxUVCoordinates.x, 0.0f, ginVertex[0].textureLayer2); EmitVertex(); gl_Position = uViewProjectionMatrix * vec4(pointPosition + (uCameraRight - uCameraUp) * ginVertex[0].scale, 1.0); - finTextureCoordinates = vec3(ginVertex[0].maxUVCoordinates.x, 0.0f, ginVertex[0].textureLayer); + finTextureCoordinates1 = vec3(ginVertex[0].maxUVCoordinates.x, ginVertex[0].maxUVCoordinates.y, ginVertex[0].textureLayer1); + finTextureCoordinates2 = vec3(ginVertex[0].maxUVCoordinates.x, ginVertex[0].maxUVCoordinates.y, ginVertex[0].textureLayer2); EmitVertex(); diff --git a/src/main/resources/assets/minosoft/rendering/shader/particle/particle.vsh b/src/main/resources/assets/minosoft/rendering/shader/particle/particle.vsh index 49c7a5e57..6b6091875 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/particle/particle.vsh +++ b/src/main/resources/assets/minosoft/rendering/shader/particle/particle.vsh @@ -16,15 +16,24 @@ layout (location = 0) in vec3 vinPosition; layout (location = 1) in vec2 vinMaxUVCoordinates; layout (location = 2) in uint vinTextureLayer; +layout (location = 3) in int vinAnimationIndex; -layout (location = 3) in float vinScale; -layout (location = 4) in uint vinTintColor; +layout (location = 4) in float vinScale; +layout (location = 5) in uint vinTintColor; +layout(std140) uniform AnimatedDataBuffer +{ + uvec4 uAnimationData[ANIMATED_TEXTURE_COUNT]; +}; + out Vertex { - uint textureIndex; - uint textureLayer; + uint textureIndex1; + uint textureLayer1; + uint textureIndex2; + uint textureLayer2; + float interpolation; vec2 maxUVCoordinates; float scale; @@ -36,10 +45,29 @@ out Vertex void main() { gl_Position = vec4(vinPosition, 1.0f); - ginVertex.textureIndex = vinTextureLayer >> 24u; - ginVertex.textureLayer = vinTextureLayer & 0xFFFFFFu; ginVertex.maxUVCoordinates = vinMaxUVCoordinates; ginVertex.scale = vinScale; ginVertex.tintColor = getRGBAColor(vinTintColor); + + if (vinAnimationIndex == -1) { + ginVertex.textureIndex1 = vinTextureLayer >> 24u; + ginVertex.textureLayer1 = vinTextureLayer & 0xFFFFFFu; + + ginVertex.interpolation = 0.0f; + return; + } + + uvec4 data = uAnimationData[vinAnimationIndex]; + uint texture1 = data.x; + uint texture2 = data.y; + uint interpolation = data.z; + + ginVertex.textureIndex1 = texture1 >> 24u; + ginVertex.textureLayer1 = texture1 & 0xFFFFFFu; + + ginVertex.textureIndex2 = texture2 >> 24u; + ginVertex.textureLayer2 = texture2 & 0xFFFFFFu; + + ginVertex.interpolation = interpolation / 100.0f; }