diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingCrumble.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java similarity index 73% rename from src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingCrumble.java rename to src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java index f8232eeab..738ef53a9 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingCrumble.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java @@ -6,7 +6,6 @@ import java.util.List; import java.util.Map; import org.jetbrains.annotations.NotNull; -import org.lwjgl.opengl.GL32; import com.jozufozu.flywheel.api.backend.Engine; import com.jozufozu.flywheel.api.instance.Instance; @@ -22,12 +21,11 @@ import com.mojang.blaze3d.systems.RenderSystem; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.core.BlockPos; -public class InstancingCrumble { +public class InstancedCrumbling { @NotNull - public static Map>>> doCrumblingSort(List instances) { - Map>>> out = new HashMap<>(); + public static Map>> doCrumblingSort(List instances) { + Map>> out = new HashMap<>(); for (Engine.CrumblingBlock triple : instances) { int progress = triple.progress(); @@ -36,8 +34,6 @@ public class InstancingCrumble { continue; } - BlockPos position = triple.pos(); - for (Instance instance : triple.instances()) { // Filter out instances that weren't created by this engine. // If all is well, we probably shouldn't take the `continue` @@ -55,8 +51,7 @@ public class InstancingCrumble { for (DrawCall draw : draws) { out.computeIfAbsent(draw.shaderState, $ -> new Int2ObjectArrayMap<>()) - .computeIfAbsent(progress, $ -> new HashMap<>()) - .computeIfAbsent(position, $ -> new ArrayList<>()) + .computeIfAbsent(progress, $ -> new ArrayList<>()) .add(() -> draw.renderOne(impl)); } } @@ -64,7 +59,7 @@ public class InstancingCrumble { return out; } - public static void render(List crumblingBlocks, BlockPos renderOrigin) { + public static void render(List crumblingBlocks) { // Sort draw calls into buckets, so we don't have to do as many shader binds. var byShaderState = doCrumblingSort(crumblingBlocks); @@ -88,16 +83,14 @@ public class InstancingCrumble { .get(shader.vertexType(), shader.instanceType(), Contexts.CRUMBLING); UniformBuffer.syncAndBind(program); - int crumblingBlockPosUniform = program.getUniformLocation("_flw_crumblingBlockPos"); - InstancingEngine.uploadMaterialIDUniform(program, material); int renderTex = getDiffuseTexture(material); - for (Int2ObjectMap.Entry>> progressEntry : byProgress.int2ObjectEntrySet()) { - var byPos = progressEntry.getValue(); + for (Int2ObjectMap.Entry> progressEntry : byProgress.int2ObjectEntrySet()) { + var drawCalls = progressEntry.getValue(); - if (byPos.isEmpty()) { + if (drawCalls.isEmpty()) { continue; } @@ -109,12 +102,7 @@ public class InstancingCrumble { GlTextureUnit.T1.makeActive(); RenderSystem.bindTexture(renderTex); - for (var blockPosEntry : byPos.entrySet()) { - var center = blockPosEntry.getKey().getCenter(); - GL32.glUniform3f(crumblingBlockPosUniform, (float) center.x - renderOrigin.getX(), (float) center.y - renderOrigin.getY(), (float) center.z - renderOrigin.getZ()); - - blockPosEntry.getValue().forEach(Runnable::run); - } + drawCalls.forEach(Runnable::run); } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java index 4ea11713a..2fc88f4bb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java @@ -76,7 +76,7 @@ public class InstancingEngine extends AbstractEngine { // Need to wait for flush before we can inspect instancer state. executor.syncUntil(flushFlag::isRaised); - InstancingCrumble.render(crumblingBlocks, this.renderOrigin); + InstancedCrumbling.render(crumblingBlocks); } @Override diff --git a/src/main/resources/assets/flywheel/flywheel/context/crumbling.frag b/src/main/resources/assets/flywheel/flywheel/context/crumbling.frag index 74c61a775..a85abf204 100644 --- a/src/main/resources/assets/flywheel/flywheel/context/crumbling.frag +++ b/src/main/resources/assets/flywheel/flywheel/context/crumbling.frag @@ -7,39 +7,17 @@ layout (depth_greater) out float gl_FragDepth; #endif #endif -uniform vec3 _flw_crumblingBlockPos; - uniform sampler2D flw_diffuseTex; uniform sampler2D flw_crumblingTex; -in vec2 _flw_crumblingFlip; +in vec2 _flw_crumblingTexCoord; out vec4 fragColor; vec4 flw_crumblingSampleColor; -vec2 flattenedPos(vec3 pos, vec3 normal) { - pos = pos - _flw_crumblingBlockPos; - - // https://community.khronos.org/t/52861 - vec3 Q1 = dFdx(pos); - vec3 Q2 = dFdy(pos); - vec2 st1 = dFdx(flw_vertexTexCoord); - vec2 st2 = dFdy(flw_vertexTexCoord); - - vec3 T = normalize(Q1*st2.t - Q2*st1.t); - vec3 B = normalize(-Q1*st2.s + Q2*st1.s); - - mat3 tbn = mat3(T, B, normal); - - // transpose is the same as inverse for orthonormal matrices - return ((transpose(tbn) * pos).xy + vec2(0.5)) * _flw_crumblingFlip; -} - void flw_initFragment() { - vec2 crumblingTexCoord = flattenedPos(flw_vertexPos.xyz, flw_vertexNormal); - - flw_crumblingSampleColor = texture(flw_crumblingTex, crumblingTexCoord); + flw_crumblingSampleColor = texture(flw_crumblingTex, _flw_crumblingTexCoord); flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord); // Let the other components modify the diffuse color as they normally would. diff --git a/src/main/resources/assets/flywheel/flywheel/context/crumbling.vert b/src/main/resources/assets/flywheel/flywheel/context/crumbling.vert index ab588f97a..2767c2b1a 100644 --- a/src/main/resources/assets/flywheel/flywheel/context/crumbling.vert +++ b/src/main/resources/assets/flywheel/flywheel/context/crumbling.vert @@ -1,7 +1,7 @@ #include "flywheel:api/vertex.glsl" #include "flywheel:util/fog.glsl" -out vec2 _flw_crumblingFlip; +out vec2 _flw_crumblingTexCoord; const int DOWN = 0; const int UP = 1; @@ -10,20 +10,13 @@ const int SOUTH = 3; const int WEST = 4; const int EAST = 5; -const vec2 FLIPS_BY_FACE[6] = vec2[]( - vec2(1., -1.), - vec2(-1., -1.), - vec2(-1., -1.), - vec2(-1., -1.), - vec2(1., -1.), - vec2(1., -1.) -); - // based on net.minecraftforge.client.ForgeHooksClient.getNearestStable int getNearestFacing(vec3 normal) { float maxAlignment = -2; int face = 2; + // Calculate the alignment of the normal vector with each axis. + // Note that `-dot(normal, axis) == dot(normal, -axis)`. vec3 alignment = vec3( dot(normal, vec3(1., 0., 0.)), dot(normal, vec3(0., 1., 0.)), @@ -46,44 +39,39 @@ int getNearestFacing(vec3 normal) { maxAlignment = alignment.z; face = SOUTH; } - if (alignment.x > maxAlignment) { + if (-alignment.x > maxAlignment) { maxAlignment = -alignment.x; face = WEST; } + if (alignment.x > maxAlignment) { + maxAlignment = alignment.x; + face = EAST; + } return face; } -vec2 calculateFlip(vec3 normal) { - int face = getNearestFacing(normal); - return FLIPS_BY_FACE[face]; -} +vec2 getCrumblingTexCoord() { + switch (getNearestFacing(flw_vertexNormal)) { + case DOWN: return vec2(flw_vertexPos.x, -flw_vertexPos.z); + case UP: return vec2(flw_vertexPos.x, flw_vertexPos.z); + case NORTH: return vec2(-flw_vertexPos.x, -flw_vertexPos.y); + case SOUTH: return vec2(flw_vertexPos.x, -flw_vertexPos.y); + case WEST: return vec2(-flw_vertexPos.z, -flw_vertexPos.y); + case EAST: return vec2(flw_vertexPos.z, -flw_vertexPos.y); + } -// This is disgusting so if an issue comes up just throw this away and fix the branching version above. -vec2 calculateFlipBranchless(vec3 normal) { - vec3 alignment = vec3( - dot(normal, vec3(1., 0., 0.)), - dot(normal, vec3(0., 1., 0.)), - dot(normal, vec3(0., 0., 1.)) - ); - - vec3 absAlignment = abs(alignment); - - // x is the max alignment that would cause U to be -1. - // y is the max alignment that would cause U to be 1. - vec2 maxNegativeMaxPositive = max(vec2(absAlignment.z, alignment.y), vec2(-alignment.y, absAlignment.x)); - - bool flipU = maxNegativeMaxPositive.x > maxNegativeMaxPositive.y; - - return vec2(mix(1., -1., flipU), -1.); + // default to north + return vec2(-flw_vertexPos.x, -flw_vertexPos.y); } void flw_initVertex() { - // Calculate the flips in model space so that the crumbling effect doesn't have discontinuities. - _flw_crumblingFlip = calculateFlipBranchless(flw_vertexNormal); + // no-op } void flw_contextVertex() { + _flw_crumblingTexCoord = getCrumblingTexCoord(); + flw_distance = fog_distance(flw_vertexPos.xyz, flywheel.cameraPos.xyz, flywheel.fogShape); gl_Position = flywheel.viewProjection * flw_vertexPos; flw_vertexNormal = normalize(flw_vertexNormal);