diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/component/ShadowComponent.java b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/component/ShadowComponent.java index 2a86de5eca..a5955d86d0 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/component/ShadowComponent.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/component/ShadowComponent.java @@ -17,6 +17,7 @@ import dev.engine_room.flywheel.lib.model.QuadMesh; import dev.engine_room.flywheel.lib.model.SingleMeshModel; import dev.engine_room.flywheel.lib.visual.util.InstanceRecycler; +import dev.engine_room.flywheel.lib.util.ShadersModHelper; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.Lightmap; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -56,6 +57,7 @@ public final class ShadowComponent implements EntityComponent { private final VisualizationContext context; private final Entity entity; private final Level level; + private final boolean shaderPackShadowSuppressed; private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); private final InstanceRecycler instances = new InstanceRecycler<>(this::createInstance); @@ -68,6 +70,7 @@ public ShadowComponent(VisualizationContext context, Entity entity) { this.context = context; this.entity = entity; this.level = entity.level(); + this.shaderPackShadowSuppressed = ShadersModHelper.isShaderPackInUse(); } private ShadowInstance createInstance() { @@ -118,7 +121,7 @@ public void beginFrame(DynamicVisual.Context context) { boolean shadowsEnabled = Minecraft.getInstance().options.entityShadows() .get(); - if (shadowsEnabled && radius > 0 && !entity.isInvisible()) { + if (shadowsEnabled && !shaderPackShadowSuppressed && radius > 0 && !entity.isInvisible()) { setupInstances(context); } @@ -181,18 +184,25 @@ private void setupInstance(ChunkAccess chunk, MutableBlockPos pos, float entityX int y = pos.getY() - renderOrigin.getY() + 1; // +1 since we moved the pos down. int z = pos.getZ() - renderOrigin.getZ(); - double minX = x + shape.min(Axis.X); + double entityLocalX = entityX - renderOrigin.getX(); + double entityLocalZ = entityZ - renderOrigin.getZ(); + // Do not submit a whole block for a small-radius shadow; clipping here keeps the + // primitive and its UV domain bounded by the same radius. + double minX = Math.max(x + shape.min(Axis.X), entityLocalX - radius); double minY = y + shape.min(Axis.Y); - double minZ = z + shape.min(Axis.Z); - double maxX = x + shape.max(Axis.X); - double maxZ = z + shape.max(Axis.Z); + double minZ = Math.max(z + shape.min(Axis.Z), entityLocalZ - radius); + double maxX = Math.min(x + shape.max(Axis.X), entityLocalX + radius); + double maxZ = Math.min(z + shape.max(Axis.Z), entityLocalZ + radius); + if (minX >= maxX || minZ >= maxZ) { + return; + } var instance = instances.get(); instance.x = (float) minX; instance.y = (float) minY; instance.z = (float) minZ; - instance.entityX = entityX - renderOrigin.getX(); - instance.entityZ = entityZ - renderOrigin.getZ(); + instance.entityX = (float) entityLocalX; + instance.entityZ = (float) entityLocalZ; instance.sizeX = (float) (maxX - minX); instance.sizeZ = (float) (maxZ - minZ); instance.alpha = alpha; diff --git a/common/src/lib/resources/assets/flywheel/flywheel/instance/shadow.vert b/common/src/lib/resources/assets/flywheel/flywheel/instance/shadow.vert index 97649f6249..99d99e47b7 100644 --- a/common/src/lib/resources/assets/flywheel/flywheel/instance/shadow.vert +++ b/common/src/lib/resources/assets/flywheel/flywheel/instance/shadow.vert @@ -1,10 +1,11 @@ +// Vanilla reference: net.minecraft.client.renderer.feature.ShadowFeatureRenderer#renderTranslucent void flw_instanceVertex(in FlwInstance i) { // Stretch the quad to the shape of the block the shadow is being cast on, // then move it to the correct position. flw_vertexPos.xyz = flw_vertexPos.xyz * vec3(i.size.x, 1., i.size.y) + i.pos; // Uvs are calculated based on the distance to the entity. - flw_vertexTexCoord = (flw_vertexPos.xz - i.entityPosXZ) * 0.5 / i.radius + 0.5; + flw_vertexTexCoord = (i.entityPosXZ - flw_vertexPos.xz) * 0.5 / i.radius + 0.5; flw_vertexColor.a = i.alpha; } diff --git a/vanillin/common/src/main/java/dev/engine_room/vanillin/elements/ShadowElement.java b/vanillin/common/src/main/java/dev/engine_room/vanillin/elements/ShadowElement.java index 9bf9fafbb7..f53601a56f 100644 --- a/vanillin/common/src/main/java/dev/engine_room/vanillin/elements/ShadowElement.java +++ b/vanillin/common/src/main/java/dev/engine_room/vanillin/elements/ShadowElement.java @@ -19,6 +19,7 @@ import dev.engine_room.flywheel.lib.visual.AbstractVisual; import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual; import dev.engine_room.flywheel.lib.visual.util.InstanceRecycler; +import dev.engine_room.flywheel.lib.util.ShadersModHelper; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.Lightmap; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -55,6 +56,7 @@ public final class ShadowElement extends AbstractVisual implements SimpleDynamic private static final Model SHADOW_MODEL = new SingleMeshModel(ShadowMesh.INSTANCE, SHADOW_MATERIAL); private final Entity entity; + private final boolean shaderPackShadowSuppressed; private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); private final InstanceRecycler instances = new InstanceRecycler<>(this::createInstance); @@ -66,6 +68,7 @@ public final class ShadowElement extends AbstractVisual implements SimpleDynamic public ShadowElement(VisualizationContext ctx, Entity entity, float partialTick, Config config) { super(ctx, entity.level(), partialTick); this.entity = entity; + shaderPackShadowSuppressed = ShadersModHelper.isShaderPackInUse(); radius(config.radius); strength(config.strength); } @@ -118,7 +121,7 @@ public void beginFrame(DynamicVisual.Context context) { boolean shadowsEnabled = Minecraft.getInstance().options.entityShadows() .get(); - if (shadowsEnabled && radius > 0 && !entity.isInvisible()) { + if (shadowsEnabled && !shaderPackShadowSuppressed && radius > 0 && !entity.isInvisible()) { setupInstances(context); } @@ -181,18 +184,25 @@ private void setupInstance(ChunkAccess chunk, MutableBlockPos pos, double entity int y = pos.getY() - renderOrigin.getY() + 1; // +1 since we moved the pos down. int z = pos.getZ() - renderOrigin.getZ(); - double minX = x + shape.min(Axis.X); + double entityLocalX = entityX - renderOrigin.getX(); + double entityLocalZ = entityZ - renderOrigin.getZ(); + // Do not submit a whole block for a small-radius shadow; clipping here keeps the + // primitive and its UV domain bounded by the same radius. + double minX = Math.max(x + shape.min(Axis.X), entityLocalX - radius); double minY = y + shape.min(Axis.Y); - double minZ = z + shape.min(Axis.Z); - double maxX = x + shape.max(Axis.X); - double maxZ = z + shape.max(Axis.Z); + double minZ = Math.max(z + shape.min(Axis.Z), entityLocalZ - radius); + double maxX = Math.min(x + shape.max(Axis.X), entityLocalX + radius); + double maxZ = Math.min(z + shape.max(Axis.Z), entityLocalZ + radius); + if (minX >= maxX || minZ >= maxZ) { + return; + } var instance = instances.get(); instance.x = (float) minX; instance.y = (float) minY; instance.z = (float) minZ; - instance.entityX = (float) (entityX - renderOrigin.getX()); - instance.entityZ = (float) (entityZ - renderOrigin.getZ()); + instance.entityX = (float) entityLocalX; + instance.entityZ = (float) entityLocalZ; instance.sizeX = (float) (maxX - minX); instance.sizeZ = (float) (maxZ - minZ); instance.alpha = alpha;