Remake animations using shaders #22

Open
TopchetoEU wants to merge 2 commits from TopchetoEU/reprogramming-shaders into 1.19.2
15 changed files with 119 additions and 136 deletions
Showing only changes of commit 00a25c3681 - Show all commits

View File

@ -107,12 +107,12 @@ public final class AnimatedChunks implements ClientModInitializer, ModMenuApi {
}
public AnimatedChunks() {
var eases = new Manager<>(new Descriptor<Ease>(x -> 1, "default")
var eases = new Manager<>(new Descriptor<Ease>(() -> "t = 1;", "default")
.author("TopchetoEU")
.description("Ends the animation as soon as it has started.")
.displayName("No animation")
);
var animations = new Manager<>(new Descriptor<Animation>((a, b, c, d, e, f, g, h) -> {}, "default")
var animations = new Manager<>(new Descriptor<Animation>(() -> ";", "default")
.author("TopchetoEU")
.description("Does nothing.")
.displayName("No animation")

View File

@ -0,0 +1,26 @@
package me.topchetoeu.animatedchunks;
import java.util.Map;
public interface StatementFactory {
/**
* Returns a GLSL statement, with access to at least the following variables:
* <ul>
* <li>playerPos - vec3, the position of the player</li>
* <li>chunkPos - vec3, the position of the current chunk</li>
* <li>pos - vec3, the position of the current vertex</li>
* <li>x - the raw stage of the animation, from 0 to 1</li>
* <li>t - the eased stage of the animation, from 0 to 1</li>
* <li>tmp0 - tmp7 - temporary float variables</li>
* <li>tmp8 - tmp11 - temporary vec3 variables</li>
* <li>tmp12 - tmp15 - temporary vec4 variables</li>
* </ul>
*/
String statement();
/**
* Returns all uniforms that are used by the statement
*/
public default Map<String, Float> uniforms() {
return Map.of();
}
}

View File

@ -1,18 +1,5 @@
package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack;
import me.topchetoeu.animatedchunks.StatementFactory;
public interface Animation {
/**
* Animations using the currently set ease
* @param progress The point at which the animation currently is (a value between 0 and 1)
* @param matrices The matrix stack used for rendering
* @param chunkX The current chunk's x (in blocks) which is animated
* @param chunkY The current chunk's y (in blocks) which is animated
* @param chunkZ The current chunk's z (in blocks) which is animated
* @param playerX The player's x (in blocks)
* @param playerY The player's y (in blocks)
* @param playerZ The player's z (in blocks)
*/
void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ);
}
public interface Animation extends StatementFactory { }

View File

@ -6,9 +6,6 @@ import java.util.Hashtable;
import me.topchetoeu.animatedchunks.Manager;
import me.topchetoeu.animatedchunks.easing.Ease;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Vector3d;
import net.minecraft.util.math.BlockPos;
public final class Animator {
public static class ChunkLoc {
@ -152,33 +149,4 @@ public final class Animator {
if (!chunkToStage.containsKey(new ChunkLoc(x, y, z))) return 1f;
return chunkToStage.get(new ChunkLoc(x, y, z));
}
public void animate(MatrixStack matrices, float progress, BlockPos chunkPos, Vector3d playerPos) {
if (progress < 0) progress = 0;
if (progress > 1) progress = 1;
if (progress < 0.999) {
float _progress = EASES.getValue().ease(progress);
ANIMATIONS.getValue().animate(
_progress, matrices,
chunkPos.getX() * 16, chunkPos.getY() * 16, chunkPos.getZ() * 16,
(float)playerPos.x, (float)playerPos.y, (float)playerPos.z
);
// matrices.translate(0, 0, 16);
}
}
public void animate(MatrixStack matrices, BlockPos chunkPos, Vector3d playerPos) {
if (!isChunkLoaded(chunkPos.getX(), chunkPos.getY(), chunkPos.getZ())) {
matrices.scale(0, 0, 0);
}
else {
animate(matrices, getChunkProgress(chunkPos.getX(), chunkPos.getY(), chunkPos.getZ()), chunkPos, playerPos);
}
}
public void animate(MatrixStack matrices, BlockPos chunkPos) {
animate(matrices, chunkPos, new Vector3d(0, 0, 0));
}
public void animate(MatrixStack matrices, float progress, BlockPos chunkPos) {
animate(matrices, progress, chunkPos, new Vector3d(0, 0, 0));
}
}

View File

@ -1,6 +1,6 @@
package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack;
import java.util.Map;
public class FallAnimation implements Animation {
private float offset;
@ -12,12 +12,11 @@ public class FallAnimation implements Animation {
this.offset = offset;
}
@Override
public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) {
animate(progress, matrices);
public Map<String, Float> uniforms() {
return Map.of("animation_f", offset);
}
public void animate(float progress, MatrixStack matrices) {
matrices.translate(0, offset * (1 - progress), 0);
public String statement() {
return "pos += vec3(0, animation_f * (1 - t));";
}
public FallAnimation(float offset) {

View File

@ -1,7 +1,6 @@
package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Vec2f;
import java.util.Map;
public class FlyInAnimation implements Animation {
private float offset;
@ -13,13 +12,21 @@ public class FlyInAnimation implements Animation {
this.offset = offset;
}
@Override
public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) {
Vec2f direction = new Vec2f(playerX, playerZ).add(new Vec2f(-chunkX, -chunkZ)).normalize().multiply(-offset);
matrices.translate(direction.x * (1 - progress), 0, direction.y * (1 - progress));
public Map<String, Float> uniforms() {
return Map.of("animation_f", offset);
}
@Override
public String statement() {
return "tmp8 = normalize(chunkPos.xz - playerPos.xz) * animation_f; tmp8 *= (1 - t); pos += tmp8;";
}
// @Override
// public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) {
// Vec2f direction = new Vec2f(playerX, playerZ).add(new Vec2f(-chunkX, -chunkZ)).normalize().multiply(-offset);
// matrices.translate(direction.x * (1 - progress), 0, direction.y * (1 - progress));
// }
public FlyInAnimation() {
offset = 50;

View File

@ -1,6 +1,6 @@
package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack;
import java.util.Map;
public final class RiseAnimation implements Animation {
private float offset;
@ -12,12 +12,11 @@ public final class RiseAnimation implements Animation {
this.offset = offset;
}
@Override
public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) {
animate(progress, matrices);
public Map<String, Float> uniforms() {
return Map.of("animation_f", offset);
}
public void animate(float progress, MatrixStack matrices) {
matrices.translate(0, offset * (progress - 1), 0);
public String statement() {
return "pos += vec3(0, animation_f * (t - 1));";
}
public RiseAnimation(float offset) {

View File

@ -1,10 +1,11 @@
package me.topchetoeu.animatedchunks.animation;
import net.minecraft.client.util.math.MatrixStack;
import java.util.Map;
public class ScaleAnimation implements Animation {
public static float xOffset = 8, yOffset = 8, zOffset = 8;
private boolean scaleY = true;
private float xOffset = 8, yOffset = 8, zOffset = 8;
public boolean isScalingY() {
return scaleY;
@ -13,38 +14,31 @@ public class ScaleAnimation implements Animation {
this.scaleY = scaleY;
}
public float getXOffset() {
return xOffset;
}
public void setXOffset(float xOffset) {
this.xOffset = xOffset;
}
public float getYOffset() {
return yOffset;
}
public void setYOffset(float yOffset) {
this.yOffset = yOffset;
}
public float getZOffset() {
return zOffset;
}
public void setZOffset(float zOffset) {
this.zOffset = zOffset;
@Override
public Map<String, Float> uniforms() {
return Map.of("animation_ox", xOffset, "animation_oy", yOffset, "animation_oz", zOffset, "animation_sy", scaleY ? 1f : 0f);
}
@Override
public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) {
float scaleX = progress;
float scaleZ = progress;
matrices.translate(xOffset, yOffset, zOffset);
matrices.scale(scaleX, 1, scaleZ);
matrices.translate(-xOffset, -yOffset, -zOffset);
public String statement() {
return
"tmp8 = vec3(animation_ox, animation_oy, animation_oz);" +
"tmp9 = vec3(t);" +
"if (animation_sy < .5f) tmp9.y = 0;" +
"pos += tmp8;" +
"pos *= tmp9;" +
"pos -= tmp8;";
}
public ScaleAnimation() {
// @Override
// public void animate(float progress, MatrixStack matrices, int chunkX, int chunkY, int chunkZ, float playerX, float playerY, float playerZ) {
// float scaleX = progress;
// float scaleZ = progress;
}
// matrices.translate(xOffset, yOffset, zOffset);
// matrices.scale(scaleX, 1, scaleZ);
// matrices.translate(-xOffset, -yOffset, -zOffset);
// }
public ScaleAnimation() { }
}

View File

@ -1,34 +1,30 @@
package me.topchetoeu.animatedchunks.easing;
public interface Ease {
/**
* Converts the linear progress of an animation to an eased progress
* @param x The progress of the animation being eased
* @return The new, eased progress
*/
float ease(float x);
import me.topchetoeu.animatedchunks.StatementFactory;
public interface Ease extends StatementFactory {
/**
* Converts a function to an ease out version of itself.
* Converts a ease-in statement to an ease-out statement
* Mathematically, the function is being "rotated" 180 degrees
* @param func The function to convert
* @return The ease out version of the function
* @param func The ease statement to convert
*/
public static Ease easeOut(Ease func) {
return x -> 1 - func.ease(1 - x);
return () -> "x = 1 - x; " + func.statement() + "x = 1 - x; t = 1 - t;";
// return x -> 1 - func.ease(1 - x);
}
/**
* Converts a function to an ease in-out version of itself.
* Mathematically, the function is being split into two, where in the interval [0; 0.5], the ease-out function is being used, and in the other interval [0.5; 1], the ease-in function is being used
* @param func The function to convert
* @return The ease in-out version of the function
* Converts a ease statement to an ease in-out statement
* Mathematically, the function is being split into two, where in the interval [0; 0.5), the ease-in function is being used, and in the other interval [0.5; 1], the ease-out function is being used
* @param func The ease statement to convert
* @return The ease in-out statement
*/
public static Ease easeInOut(Ease func) {
return x -> {
float x2 = 2 * x;
return () -> "x *= 2; if (x < 1f) { " + easeOut(func) + "} else { x -= 1; " + func.statement() + " } x /= 2;";
// return x -> {
// float x2 = 2 * x;
if (x < 0.5f) return (1 - func.ease(1 - x2)) / 2;
else return (1 + func.ease(x2 - 1)) / 2;
};
// if (x < 0.5f) return (1 - func.ease(1 - x2)) / 2;
// else return (1 + func.ease(x2 - 1)) / 2;
// };
}
}

View File

@ -1,5 +1,7 @@
package me.topchetoeu.animatedchunks.easing;
import java.util.Map;
public class ElasticEase implements Ease {
private float steepness = 1;
private int periods = 3;
@ -19,11 +21,21 @@ public class ElasticEase implements Ease {
}
@Override
public float ease(float x) {
float amplitude = (float)Math.pow(2, -steepness * x) * (1 - x);
float wave = (float)Math.sin(2 * Math.PI * periods * x - Math.PI / 2);
public Map<String, Float> uniforms() {
return Map.of("ease_s", steepness, "ease_p", (float)periods);
}
return amplitude * wave + 1;
@Override
public String statement() {
return
"tmp0 = pow(2, -ease_s * x) * (1 - x);" +
"tmp1 = sin(6.28 * ease_p * x - 1.57);" +
"t = tmp0 * tmp1 + 1;";
// float amplitude = (float)Math.pow(2, -steepness * x) * (1 - x);
// float wave = (float)Math.sin(2 * Math.PI * periods * x - Math.PI / 2);
// return amplitude * wave + 1;
}
}

View File

@ -1,7 +1,7 @@
package me.topchetoeu.animatedchunks.easing;
public class LinearEase implements Ease {
public float ease(float x) {
return x;
public String statement() {
return "t = x;";
}
}

View File

@ -1,8 +1,7 @@
package me.topchetoeu.animatedchunks.easing;
public class QuadraticEase implements Ease {
@Override
public float ease(float x) {
return x * x;
public String statement() {
return "t = x * x;";
}
}

View File

@ -1,8 +1,7 @@
package me.topchetoeu.animatedchunks.easing;
public class SineEase implements Ease {
@Override
public float ease(float x) {
return (float)Math.sin(x * Math.PI / 2);
public String statement() {
return "t = sin(x * 1.57);";
}
}

View File

@ -20,7 +20,6 @@ import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Matrix4f;
import net.minecraft.util.math.Quaternion;
import net.minecraft.util.math.Vec3f;
@ -173,7 +172,7 @@ public class ChunkPreview extends DrawableHelper implements Drawable, Element, S
// x += n;
// y += n;
animator.animate(matrices, progress, new BlockPos(x * 16, 0, y * 16));
// animator.animate(matrices, progress, new BlockPos(x * 16, 0, y * 16));
// if (progress < 0) progress = 0;
// if (progress > 1) progress = 1;

View File

@ -11,8 +11,6 @@ import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.render.WorldRenderer.ChunkInfo;
import net.minecraft.client.render.chunk.ChunkBuilder.BuiltChunk;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Vector3d;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Matrix4f;
import org.spongepowered.asm.mixin.Mixin;
@ -56,7 +54,7 @@ public abstract class WorldRendererMixin {
matrices.push();
AnimatedChunks.getInstance().animator.animate(matrices, new BlockPos(chunk.getOrigin().getX(), 0, chunk.getOrigin().getZ()), new Vector3d(playerX, playerY, playerZ));
// AnimatedChunks.getInstance().animator.animate(matrices, new BlockPos(chunk.getOrigin().getX(), 0, chunk.getOrigin().getZ()), new Vector3d(playerX, playerY, playerZ));
// if (getProgressManager().isChunkLoaded(x, 0, z)) {
// float progress = getProgressManager().getChunkProgress(x, 0, z);