The boring way

- Just use vanilla's implementation for crumbling.
This commit is contained in:
Jozufozu 2023-11-27 12:42:41 -08:00
parent f3f02963a7
commit 21d7c26ad1
4 changed files with 34 additions and 80 deletions

View file

@ -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<ShaderState, Int2ObjectMap<Map<BlockPos, List<Runnable>>>> doCrumblingSort(List<Engine.CrumblingBlock> instances) {
Map<ShaderState, Int2ObjectMap<Map<BlockPos, List<Runnable>>>> out = new HashMap<>();
public static Map<ShaderState, Int2ObjectMap<List<Runnable>>> doCrumblingSort(List<Engine.CrumblingBlock> instances) {
Map<ShaderState, Int2ObjectMap<List<Runnable>>> 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<Engine.CrumblingBlock> crumblingBlocks, BlockPos renderOrigin) {
public static void render(List<Engine.CrumblingBlock> 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<Map<BlockPos, List<Runnable>>> progressEntry : byProgress.int2ObjectEntrySet()) {
var byPos = progressEntry.getValue();
for (Int2ObjectMap.Entry<List<Runnable>> 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);
}
}
}

View file

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

View file

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

View file

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