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 java.util.Map;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.lwjgl.opengl.GL32;
import com.jozufozu.flywheel.api.backend.Engine; import com.jozufozu.flywheel.api.backend.Engine;
import com.jozufozu.flywheel.api.instance.Instance; 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.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.core.BlockPos;
public class InstancingCrumble { public class InstancedCrumbling {
@NotNull @NotNull
public static Map<ShaderState, Int2ObjectMap<Map<BlockPos, List<Runnable>>>> doCrumblingSort(List<Engine.CrumblingBlock> instances) { public static Map<ShaderState, Int2ObjectMap<List<Runnable>>> doCrumblingSort(List<Engine.CrumblingBlock> instances) {
Map<ShaderState, Int2ObjectMap<Map<BlockPos, List<Runnable>>>> out = new HashMap<>(); Map<ShaderState, Int2ObjectMap<List<Runnable>>> out = new HashMap<>();
for (Engine.CrumblingBlock triple : instances) { for (Engine.CrumblingBlock triple : instances) {
int progress = triple.progress(); int progress = triple.progress();
@ -36,8 +34,6 @@ public class InstancingCrumble {
continue; continue;
} }
BlockPos position = triple.pos();
for (Instance instance : triple.instances()) { for (Instance instance : triple.instances()) {
// Filter out instances that weren't created by this engine. // Filter out instances that weren't created by this engine.
// If all is well, we probably shouldn't take the `continue` // If all is well, we probably shouldn't take the `continue`
@ -55,8 +51,7 @@ public class InstancingCrumble {
for (DrawCall draw : draws) { for (DrawCall draw : draws) {
out.computeIfAbsent(draw.shaderState, $ -> new Int2ObjectArrayMap<>()) out.computeIfAbsent(draw.shaderState, $ -> new Int2ObjectArrayMap<>())
.computeIfAbsent(progress, $ -> new HashMap<>()) .computeIfAbsent(progress, $ -> new ArrayList<>())
.computeIfAbsent(position, $ -> new ArrayList<>())
.add(() -> draw.renderOne(impl)); .add(() -> draw.renderOne(impl));
} }
} }
@ -64,7 +59,7 @@ public class InstancingCrumble {
return out; 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. // Sort draw calls into buckets, so we don't have to do as many shader binds.
var byShaderState = doCrumblingSort(crumblingBlocks); var byShaderState = doCrumblingSort(crumblingBlocks);
@ -88,16 +83,14 @@ public class InstancingCrumble {
.get(shader.vertexType(), shader.instanceType(), Contexts.CRUMBLING); .get(shader.vertexType(), shader.instanceType(), Contexts.CRUMBLING);
UniformBuffer.syncAndBind(program); UniformBuffer.syncAndBind(program);
int crumblingBlockPosUniform = program.getUniformLocation("_flw_crumblingBlockPos");
InstancingEngine.uploadMaterialIDUniform(program, material); InstancingEngine.uploadMaterialIDUniform(program, material);
int renderTex = getDiffuseTexture(material); int renderTex = getDiffuseTexture(material);
for (Int2ObjectMap.Entry<Map<BlockPos, List<Runnable>>> progressEntry : byProgress.int2ObjectEntrySet()) { for (Int2ObjectMap.Entry<List<Runnable>> progressEntry : byProgress.int2ObjectEntrySet()) {
var byPos = progressEntry.getValue(); var drawCalls = progressEntry.getValue();
if (byPos.isEmpty()) { if (drawCalls.isEmpty()) {
continue; continue;
} }
@ -109,12 +102,7 @@ public class InstancingCrumble {
GlTextureUnit.T1.makeActive(); GlTextureUnit.T1.makeActive();
RenderSystem.bindTexture(renderTex); RenderSystem.bindTexture(renderTex);
for (var blockPosEntry : byPos.entrySet()) { drawCalls.forEach(Runnable::run);
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);
}
} }
} }
} }

View file

@ -76,7 +76,7 @@ public class InstancingEngine extends AbstractEngine {
// Need to wait for flush before we can inspect instancer state. // Need to wait for flush before we can inspect instancer state.
executor.syncUntil(flushFlag::isRaised); executor.syncUntil(flushFlag::isRaised);
InstancingCrumble.render(crumblingBlocks, this.renderOrigin); InstancedCrumbling.render(crumblingBlocks);
} }
@Override @Override

View file

@ -7,39 +7,17 @@ layout (depth_greater) out float gl_FragDepth;
#endif #endif
#endif #endif
uniform vec3 _flw_crumblingBlockPos;
uniform sampler2D flw_diffuseTex; uniform sampler2D flw_diffuseTex;
uniform sampler2D flw_crumblingTex; uniform sampler2D flw_crumblingTex;
in vec2 _flw_crumblingFlip; in vec2 _flw_crumblingTexCoord;
out vec4 fragColor; out vec4 fragColor;
vec4 flw_crumblingSampleColor; 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() { void flw_initFragment() {
vec2 crumblingTexCoord = flattenedPos(flw_vertexPos.xyz, flw_vertexNormal); flw_crumblingSampleColor = texture(flw_crumblingTex, _flw_crumblingTexCoord);
flw_crumblingSampleColor = texture(flw_crumblingTex, crumblingTexCoord);
flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord); flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord);
// Let the other components modify the diffuse color as they normally would. // 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:api/vertex.glsl"
#include "flywheel:util/fog.glsl" #include "flywheel:util/fog.glsl"
out vec2 _flw_crumblingFlip; out vec2 _flw_crumblingTexCoord;
const int DOWN = 0; const int DOWN = 0;
const int UP = 1; const int UP = 1;
@ -10,20 +10,13 @@ const int SOUTH = 3;
const int WEST = 4; const int WEST = 4;
const int EAST = 5; 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 // based on net.minecraftforge.client.ForgeHooksClient.getNearestStable
int getNearestFacing(vec3 normal) { int getNearestFacing(vec3 normal) {
float maxAlignment = -2; float maxAlignment = -2;
int face = 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( vec3 alignment = vec3(
dot(normal, vec3(1., 0., 0.)), dot(normal, vec3(1., 0., 0.)),
dot(normal, vec3(0., 1., 0.)), dot(normal, vec3(0., 1., 0.)),
@ -46,44 +39,39 @@ int getNearestFacing(vec3 normal) {
maxAlignment = alignment.z; maxAlignment = alignment.z;
face = SOUTH; face = SOUTH;
} }
if (alignment.x > maxAlignment) { if (-alignment.x > maxAlignment) {
maxAlignment = -alignment.x; maxAlignment = -alignment.x;
face = WEST; face = WEST;
} }
if (alignment.x > maxAlignment) {
maxAlignment = alignment.x;
face = EAST;
}
return face; return face;
} }
vec2 calculateFlip(vec3 normal) { vec2 getCrumblingTexCoord() {
int face = getNearestFacing(normal); switch (getNearestFacing(flw_vertexNormal)) {
return FLIPS_BY_FACE[face]; 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. // default to north
vec2 calculateFlipBranchless(vec3 normal) { return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
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.);
} }
void flw_initVertex() { void flw_initVertex() {
// Calculate the flips in model space so that the crumbling effect doesn't have discontinuities. // no-op
_flw_crumblingFlip = calculateFlipBranchless(flw_vertexNormal);
} }
void flw_contextVertex() { void flw_contextVertex() {
_flw_crumblingTexCoord = getCrumblingTexCoord();
flw_distance = fog_distance(flw_vertexPos.xyz, flywheel.cameraPos.xyz, flywheel.fogShape); flw_distance = fog_distance(flw_vertexPos.xyz, flywheel.cameraPos.xyz, flywheel.fogShape);
gl_Position = flywheel.viewProjection * flw_vertexPos; gl_Position = flywheel.viewProjection * flw_vertexPos;
flw_vertexNormal = normalize(flw_vertexNormal); flw_vertexNormal = normalize(flw_vertexNormal);