diff --git a/Robust.Client/GameObjects/Components/Renderable/SpriteComponent.cs b/Robust.Client/GameObjects/Components/Renderable/SpriteComponent.cs
index d1dbd6587c6..51380a85d1d 100644
--- a/Robust.Client/GameObjects/Components/Renderable/SpriteComponent.cs
+++ b/Robust.Client/GameObjects/Components/Renderable/SpriteComponent.cs
@@ -214,6 +214,14 @@ public ShaderInstance? PostShader
set;
}
+ ///
+ /// Fraction of every normal sprite layer cropped from its bottom edge before rendering.
+ /// This is applied before layer and post shaders, allowing effects such as water immersion
+ /// without consuming the sprite's single post-shader slot.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float BottomClipFraction { get; set; }
+
///
/// Whether to pass the screen texture to the .
///
diff --git a/Robust.Client/GameObjects/EntitySystems/SpriteSystem.Render.cs b/Robust.Client/GameObjects/EntitySystems/SpriteSystem.Render.cs
index e630ad93248..05845c5e785 100644
--- a/Robust.Client/GameObjects/EntitySystems/SpriteSystem.Render.cs
+++ b/Robust.Client/GameObjects/EntitySystems/SpriteSystem.Render.cs
@@ -1,3 +1,4 @@
+using System;
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Clyde;
@@ -146,6 +147,20 @@ private void RenderLayer(Layer layer, DrawingHandleWorld drawingHandle, ref Matr
var layerColor = layer.Owner.Comp.color * layer.Color;
var textureSize = texture.Size / (float) EyeManager.PixelsPerMeter;
var quad = Box2.FromDimensions(textureSize / -2, textureSize);
+ UIBox2? subRegion = null;
+
+ var bottomClip = Math.Clamp(layer.Owner.Comp.BottomClipFraction, 0f, 0.999f);
+ if (bottomClip > 0f)
+ {
+ // Crop the texture as well as its quad so the visible portion keeps its original scale.
+ // Texture sub-regions use a top-left origin while world quads use a bottom-left origin.
+ quad.Bottom = MathHelper.Lerp(quad.Bottom, quad.Top, bottomClip);
+ subRegion = new UIBox2(
+ 0f,
+ 0f,
+ texture.Width,
+ texture.Height * (1f - bottomClip));
+ }
if (layer.UnShaded)
{
@@ -158,7 +173,7 @@ private void RenderLayer(Layer layer, DrawingHandleWorld drawingHandle, ref Matr
layerColor = new(new Vector4(-1) - layerColor.RGBA);
}
- drawingHandle.DrawTextureRectRegion(texture, quad, layerColor);
+ drawingHandle.DrawTextureRectRegion(texture, quad, layerColor, subRegion);
if (layer.Shader != null)
drawingHandle.UseShader(null);