From 9064292155dd698c6cc83f2e333929fc3f29ce51 Mon Sep 17 00:00:00 2001 From: tylersfoot Date: Sat, 26 Oct 2024 23:08:43 -0400 Subject: [PATCH 1/2] Adding new shaders --- .../Shaders/Glitch/GlitchContainer.cs | 11 +++ .../Graphics/Shaders/Glitch/GlitchDrawNode.cs | 82 +++++++++++++++++++ .../Shaders/HueShift/HueShiftContainer.cs | 11 +++ .../Shaders/HueShift/HueShiftDrawNode.cs | 77 +++++++++++++++++ .../Shaders/Pixelate/PixelateContainer.cs | 11 +++ .../Shaders/Pixelate/PixelateDrawNode.cs | 77 +++++++++++++++++ .../Graphics/Shaders/ShaderContainer.cs | 19 +++-- .../Map/Structures/Events/ShaderEvent.cs | 8 +- .../Edit/Tabs/Design/DesignContainer.cs | 6 ++ .../Edit/Tabs/Design/DesignShaderHandler.cs | 2 + .../Tabs/Design/Points/Entries/ShaderEntry.cs | 72 ++++++++++++++-- .../Screens/Gameplay/GameplayScreen.cs | 6 ++ .../Screens/Gameplay/ShaderEventHandler.cs | 13 +++ fluXis.Resources/Shaders/sh_Glitch.fs | 31 +++++++ fluXis.Resources/Shaders/sh_HueShift.fs | 48 +++++++++++ fluXis.Resources/Shaders/sh_Pixelate.fs | 19 +++++ fluXis.Resources/fluXis.Resources.csproj | 2 + 17 files changed, 482 insertions(+), 13 deletions(-) create mode 100644 fluXis.Game/Graphics/Shaders/Glitch/GlitchContainer.cs create mode 100644 fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs create mode 100644 fluXis.Game/Graphics/Shaders/HueShift/HueShiftContainer.cs create mode 100644 fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs create mode 100644 fluXis.Game/Graphics/Shaders/Pixelate/PixelateContainer.cs create mode 100644 fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs create mode 100644 fluXis.Resources/Shaders/sh_Glitch.fs create mode 100644 fluXis.Resources/Shaders/sh_HueShift.fs create mode 100644 fluXis.Resources/Shaders/sh_Pixelate.fs diff --git a/fluXis.Game/Graphics/Shaders/Glitch/GlitchContainer.cs b/fluXis.Game/Graphics/Shaders/Glitch/GlitchContainer.cs new file mode 100644 index 00000000..38c4dfa2 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/Glitch/GlitchContainer.cs @@ -0,0 +1,11 @@ +using fluXis.Game.Map.Structures.Events; +using osu.Framework.Graphics; + +namespace fluXis.Game.Graphics.Shaders.Glitch; + +public partial class GlitchContainer : ShaderContainer +{ + protected override string FragmentShader => "Glitch"; + public override ShaderType Type => ShaderType.Glitch; + protected override DrawNode CreateShaderDrawNode() => new GlitchContainerDrawNode(this, SharedData); +} diff --git a/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs b/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs new file mode 100644 index 00000000..2dd7c94c --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs @@ -0,0 +1,82 @@ +using System.Runtime.InteropServices; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Shaders.Types; +using osuTK.Graphics; + +namespace fluXis.Game.Graphics.Shaders.Glitch; + +public partial class GlitchContainer +{ + private class GlitchContainerDrawNode : ShaderDrawNode + { + private float strength; + private float strength2; // block size + private IUniformBuffer glitchParametersBuffer; + + public GlitchContainerDrawNode(GlitchContainer source, BufferedDrawNodeSharedData sharedData) + : base(source, sharedData) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + strength = Source.Strength / 10f; + strength2 = Source.Strength2; + } + + protected override void PopulateContents(IRenderer renderer) + { + base.PopulateContents(renderer); + + if (strength > 0) + drawFrameBuffer(renderer); + } + + private void drawFrameBuffer(IRenderer renderer) + { + glitchParametersBuffer ??= renderer.CreateUniformBuffer(); + + IFrameBuffer current = SharedData.CurrentEffectBuffer; + IFrameBuffer target = SharedData.GetNextEffectBuffer(); + + renderer.SetBlend(BlendingParameters.None); + + using (BindFrameBuffer(target)) + { + glitchParametersBuffer.Data = glitchParametersBuffer.Data with + { + TexSize = current.Size, + Strength = strength, + BlockSize = strength2, + Time = (float)Source.Time.Current % 10000 + }; + + Shader.BindUniformBlock("m_GlitchParameters", glitchParametersBuffer); + Shader.Bind(); + renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); + Shader.Unbind(); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + glitchParametersBuffer?.Dispose(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct GlitchParameters + { + public UniformVector2 TexSize; + public UniformFloat Strength; + public UniformFloat BlockSize; + public UniformFloat Time; + private readonly UniformPadding12 pad1; + } + } +} diff --git a/fluXis.Game/Graphics/Shaders/HueShift/HueShiftContainer.cs b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftContainer.cs new file mode 100644 index 00000000..99d04762 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftContainer.cs @@ -0,0 +1,11 @@ +using fluXis.Game.Map.Structures.Events; +using osu.Framework.Graphics; + +namespace fluXis.Game.Graphics.Shaders.HueShift; + +public partial class HueShiftContainer : ShaderContainer +{ + protected override string FragmentShader => "HueShift"; + public override ShaderType Type => ShaderType.HueShift; + protected override DrawNode CreateShaderDrawNode() => new HueShiftContainerDrawNode(this, SharedData); +} diff --git a/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs new file mode 100644 index 00000000..bde916e0 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs @@ -0,0 +1,77 @@ +using System.Runtime.InteropServices; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Shaders.Types; +using osuTK.Graphics; + +namespace fluXis.Game.Graphics.Shaders.HueShift; + +public partial class HueShiftContainer +{ + private class HueShiftContainerDrawNode : ShaderDrawNode + { + private float strength; + private IUniformBuffer hueShiftParametersBuffer; + + public HueShiftContainerDrawNode(HueShiftContainer source, BufferedDrawNodeSharedData sharedData) + : base(source, sharedData) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + strength = Source.Strength; + } + + protected override void PopulateContents(IRenderer renderer) + { + base.PopulateContents(renderer); + + if (strength > 0) + drawFrameBuffer(renderer, strength); + } + + private void drawFrameBuffer(IRenderer renderer, float strength) + { + hueShiftParametersBuffer ??= renderer.CreateUniformBuffer(); + + IFrameBuffer current = SharedData.CurrentEffectBuffer; + IFrameBuffer target = SharedData.GetNextEffectBuffer(); + + renderer.SetBlend(BlendingParameters.None); + + using (BindFrameBuffer(target)) + { + hueShiftParametersBuffer.Data = hueShiftParametersBuffer.Data with + { + TexSize = current.Size, + Strength = strength + }; + + Shader.BindUniformBlock("m_HueShiftParameters", hueShiftParametersBuffer); + Shader.Bind(); + renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); + Shader.Unbind(); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + hueShiftParametersBuffer?.Dispose(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct HueShiftParameters + { + public UniformVector2 TexSize; + public UniformFloat Strength; + private readonly UniformPadding8 pad1; + private readonly UniformPadding12 pad2; + } + } +} diff --git a/fluXis.Game/Graphics/Shaders/Pixelate/PixelateContainer.cs b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateContainer.cs new file mode 100644 index 00000000..3656a3b8 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateContainer.cs @@ -0,0 +1,11 @@ +using fluXis.Game.Map.Structures.Events; +using osu.Framework.Graphics; + +namespace fluXis.Game.Graphics.Shaders.Pixelate; + +public partial class PixelateContainer : ShaderContainer +{ + protected override string FragmentShader => "Pixelate"; + public override ShaderType Type => ShaderType.Pixelate; + protected override DrawNode CreateShaderDrawNode() => new PixelateContainerDrawNode(this, SharedData); +} diff --git a/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs new file mode 100644 index 00000000..ffa7d9d1 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs @@ -0,0 +1,77 @@ +using System.Runtime.InteropServices; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Shaders.Types; +using osuTK.Graphics; + +namespace fluXis.Game.Graphics.Shaders.Pixelate; + +public partial class PixelateContainer +{ + private class PixelateContainerDrawNode : ShaderDrawNode + { + private float strength; + private IUniformBuffer pixelateParametersBuffer; + + public PixelateContainerDrawNode(PixelateContainer source, BufferedDrawNodeSharedData sharedData) + : base(source, sharedData) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + strength = Source.Strength; + } + + protected override void PopulateContents(IRenderer renderer) + { + base.PopulateContents(renderer); + + if (strength > 0) + drawFrameBuffer(renderer, strength); + } + + private void drawFrameBuffer(IRenderer renderer, float strength) + { + pixelateParametersBuffer ??= renderer.CreateUniformBuffer(); + + IFrameBuffer current = SharedData.CurrentEffectBuffer; + IFrameBuffer target = SharedData.GetNextEffectBuffer(); + + renderer.SetBlend(BlendingParameters.None); + + using (BindFrameBuffer(target)) + { + pixelateParametersBuffer.Data = pixelateParametersBuffer.Data with + { + TexSize = current.Size, + Strength = strength + }; + + Shader.BindUniformBlock("m_PixelateParameters", pixelateParametersBuffer); + Shader.Bind(); + renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); + Shader.Unbind(); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + pixelateParametersBuffer?.Dispose(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct PixelateParameters + { + public UniformVector2 TexSize; + public UniformFloat Strength; + private readonly UniformPadding8 pad1; + private readonly UniformPadding12 pad2; + } + } +} diff --git a/fluXis.Game/Graphics/Shaders/ShaderContainer.cs b/fluXis.Game/Graphics/Shaders/ShaderContainer.cs index 8d9781ef..df0ed9bd 100644 --- a/fluXis.Game/Graphics/Shaders/ShaderContainer.cs +++ b/fluXis.Game/Graphics/Shaders/ShaderContainer.cs @@ -19,12 +19,8 @@ public abstract partial class ShaderContainer : Container, IBufferedDrawable protected abstract DrawNode CreateShaderDrawNode(); private float strength; + private float strength2; - /// - /// The strength of the mosaic effect. From 0 to 1. - ///
- /// 0 means its full resolution, 1 means its 1x1 pixel. - ///
public float Strength { get => strength; @@ -38,6 +34,19 @@ public float Strength } } + public float Strength2 + { + get => strength2; + set + { + if (value == strength2) + return; + + strength2 = value; + Invalidate(Invalidation.DrawNode); + } + } + public bool DrawOriginal { get; set; } public ColourInfo EffectColour { get; set; } = Color4.White; public BlendingParameters EffectBlending { get; set; } = BlendingParameters.Inherit; diff --git a/fluXis.Game/Map/Structures/Events/ShaderEvent.cs b/fluXis.Game/Map/Structures/Events/ShaderEvent.cs index 3b8cecca..4aa1c07c 100644 --- a/fluXis.Game/Map/Structures/Events/ShaderEvent.cs +++ b/fluXis.Game/Map/Structures/Events/ShaderEvent.cs @@ -50,6 +50,9 @@ public class ShaderParameters { [JsonProperty("strength")] public float Strength { get; set; } + + [JsonProperty("strength2")] + public float Strength2 { get; set; } } } @@ -62,5 +65,8 @@ public enum ShaderType Mosaic, Noise, Vignette, - Retro + Retro, + HueShift, + Pixelate, + Glitch } diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs b/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs index 068470bb..936cf33e 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs @@ -4,12 +4,15 @@ using fluXis.Game.Graphics.Shaders; using fluXis.Game.Graphics.Shaders.Bloom; using fluXis.Game.Graphics.Shaders.Chromatic; +using fluXis.Game.Graphics.Shaders.Glitch; using fluXis.Game.Graphics.Shaders.Greyscale; using fluXis.Game.Graphics.Shaders.Invert; using fluXis.Game.Graphics.Shaders.Mosaic; using fluXis.Game.Graphics.Shaders.Noise; using fluXis.Game.Graphics.Shaders.Retro; using fluXis.Game.Graphics.Shaders.Vignette; +using fluXis.Game.Graphics.Shaders.HueShift; +using fluXis.Game.Graphics.Shaders.Pixelate; using fluXis.Game.Graphics.Sprites; using fluXis.Game.Map.Structures.Events; using fluXis.Game.Screens.Edit.Tabs.Design.Effects; @@ -108,6 +111,9 @@ private ShaderStackContainer createShaderStack() ShaderType.Noise => new NoiseContainer(), ShaderType.Vignette => new VignetteContainer(), ShaderType.Retro => new RetroContainer(), + ShaderType.HueShift => new HueShiftContainer(), + ShaderType.Pixelate => new PixelateContainer(), + ShaderType.Glitch => new GlitchContainer(), _ => null }; diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs b/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs index 0484dba5..8b2d1f4a 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs @@ -43,6 +43,7 @@ private void handleGroup(ShaderType type, IEnumerable events) if (current == null) { container.Strength = 0; + container.Strength2 = 0; return; } @@ -52,6 +53,7 @@ private void handleGroup(ShaderType type, IEnumerable events) if (progress >= 1) { container.Strength = end; + container.Strength2 = end; return; } diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs b/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs index e8462d7d..36bbf21c 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs @@ -31,6 +31,8 @@ private float maxStrength } } + private float maxStrength2 => 1f; + private float step { get @@ -57,11 +59,13 @@ public override ITimedObject CreateClone() UseStartParams = shader.UseStartParams, StartParameters = new ShaderEvent.ShaderParameters { - Strength = shader.StartParameters.Strength + Strength = shader.StartParameters.Strength, + Strength2 = shader.StartParameters.Strength2, }, EndParameters = new ShaderEvent.ShaderParameters { - Strength = shader.EndParameters.Strength + Strength = shader.EndParameters.Strength, + Strength2 = shader.EndParameters.Strength2 } }; } @@ -99,7 +103,7 @@ protected override IEnumerable CreateSettings() } }; - return base.CreateSettings().Concat(new Drawable[] + var settings = new List { new PointSettingsLength(Map, shader, BeatLength), new PointSettingsDropdown @@ -114,7 +118,19 @@ protected override IEnumerable CreateSettings() Map.Update(shader); } }, - startValToggle, + + new PointSettingsToggle + { + Text = "Use Start Value", + TooltipText = "Enables whether start values should be used.", + Bindable = new Bindable(shader.UseStartParams), + OnStateChanged = enabled => + { + shader.UseStartParams = enabled; + Map.Update(shader); + } + }, + new PointSettingsSlider { Enabled = startValToggle.Bindable, @@ -130,6 +146,7 @@ protected override IEnumerable CreateSettings() Map.Update(shader); } }, + new PointSettingsSlider { Text = "End Strength", @@ -143,8 +160,49 @@ protected override IEnumerable CreateSettings() shader.EndParameters.Strength = value; Map.Update(shader); } - }, - new PointSettingsEasing(Map, shader) - }); + } + }; + + // edge cases for shaders with extra parameters + if (shader.Type == ShaderType.Glitch) + { + settings.AddRange(new Drawable[] + { + new PointSettingsSlider + { + Enabled = startValToggle.Bindable, + Text = "Start Block Size", + TooltipText = "The size of the glitch blocks.", + CurrentValue = shader.StartParameters.Strength2, + Min = 0, + Max = maxStrength2, + Step = step, + OnValueChanged = value => + { + shader.StartParameters.Strength2 = value; + Map.Update(shader); + } + }, + + new PointSettingsSlider + { + Text = "End Block Size", + TooltipText = "The size of the glitch blocks.", + CurrentValue = shader.EndParameters.Strength2, + Min = 0, + Max = maxStrength2, + Step = step, + OnValueChanged = value => + { + shader.EndParameters.Strength2 = value; + Map.Update(shader); + } + } + }); + } + + settings.Add(new PointSettingsEasing(Map, shader)); + + return base.CreateSettings().Concat(settings); } } diff --git a/fluXis.Game/Screens/Gameplay/GameplayScreen.cs b/fluXis.Game/Screens/Gameplay/GameplayScreen.cs index bc715e09..81f20fe8 100644 --- a/fluXis.Game/Screens/Gameplay/GameplayScreen.cs +++ b/fluXis.Game/Screens/Gameplay/GameplayScreen.cs @@ -20,6 +20,9 @@ using fluXis.Game.Graphics.Shaders.Noise; using fluXis.Game.Graphics.Shaders.Retro; using fluXis.Game.Graphics.Shaders.Vignette; +using fluXis.Game.Graphics.Shaders.HueShift; +using fluXis.Game.Graphics.Shaders.Pixelate; +using fluXis.Game.Graphics.Shaders.Glitch; using fluXis.Game.Input; using fluXis.Game.Map; using fluXis.Game.Map.Structures.Events; @@ -329,6 +332,9 @@ private ShaderStackContainer buildShaders() ShaderType.Noise => new NoiseContainer(), ShaderType.Vignette => new VignetteContainer(), ShaderType.Retro => new RetroContainer(), + ShaderType.HueShift => new HueShiftContainer(), + ShaderType.Pixelate => new PixelateContainer(), + ShaderType.Glitch => new GlitchContainer(), _ => null }; diff --git a/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs b/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs index 8dcfc36f..15be12c7 100644 --- a/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs +++ b/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs @@ -43,9 +43,13 @@ private void trigger(ShaderEvent ev) throw new Exception($"Handler with type {ev.ShaderName} is not in scene tree!"); if (ev.UseStartParams) + { handler.StrengthTo(ev.StartParameters.Strength); + handler.Strength2To(ev.StartParameters.Strength2); + } handler.StrengthTo(ev.EndParameters.Strength, ev.Duration, ev.Easing); + handler.Strength2To(ev.EndParameters.Strength2, ev.Duration, ev.Easing); } // the shader stack is outside the gameplay clock. @@ -61,6 +65,12 @@ private float strength set => container.Strength = value; } + private float strength2 + { + get => container.Strength2; + set => container.Strength2 = value; + } + public TransformHandler(ShaderContainer container) { this.container = container; @@ -69,5 +79,8 @@ public TransformHandler(ShaderContainer container) public void StrengthTo(float str, double dur = 0, Easing ease = Easing.None) => this.TransformTo(nameof(strength), str, dur, ease); + + public void Strength2To(float str, double dur = 0, Easing ease = Easing.None) + => this.TransformTo(nameof(strength2), str, dur, ease); } } diff --git a/fluXis.Resources/Shaders/sh_Glitch.fs b/fluXis.Resources/Shaders/sh_Glitch.fs new file mode 100644 index 00000000..8e71a703 --- /dev/null +++ b/fluXis.Resources/Shaders/sh_Glitch.fs @@ -0,0 +1,31 @@ +layout(std140, set = 0, binding = 0) uniform m_GlitchParameters +{ + vec2 g_TexSize; + float g_Strength; + float g_Time; + float g_BlockSize; +}; + +layout(set = 1, binding = 0) uniform texture2D m_Texture; +layout(set = 1, binding = 1) uniform sampler m_Sampler; + +layout(location = 0) out vec4 o_Colour; + +highp float random(highp vec2 st, float seed) +{ + return fract(sin(dot(st.xy, vec2(12.9898, 78.233) + seed)) * 43758.5453123); +} + +void main(void) +{ + vec2 uv = gl_FragCoord.xy / g_TexSize; + float blockSizeInPixels = mix(1.0, min(g_TexSize.x, g_TexSize.y), g_BlockSize); + vec2 blockUV = floor(uv * blockSizeInPixels) / blockSizeInPixels; + + float randomShift = (random(blockUV, g_Time) - 0.5) * g_Strength; + + uv.x += randomShift; + + vec4 pixelColor = textureLod(sampler2D(m_Texture, m_Sampler), uv, 0.0); + o_Colour = pixelColor; +} diff --git a/fluXis.Resources/Shaders/sh_HueShift.fs b/fluXis.Resources/Shaders/sh_HueShift.fs new file mode 100644 index 00000000..c2702dc7 --- /dev/null +++ b/fluXis.Resources/Shaders/sh_HueShift.fs @@ -0,0 +1,48 @@ +layout(std140, set = 0, binding = 0) uniform m_HueShiftParameters +{ + vec2 g_TexSize; + float g_Strength; +}; + +layout(set = 1, binding = 0) uniform texture2D m_Texture; +layout(set = 1, binding = 1) uniform sampler m_Sampler; + +layout(location = 0) out vec4 o_Colour; + +vec3 hueShift(vec3 color, float hueAdjust) { + const vec3 kRGBToYPrime = vec3(0.299, 0.587, 0.114); + const vec3 kRGBToI = vec3(0.596, -0.275, -0.321); + const vec3 kRGBToQ = vec3(0.212, -0.523, 0.311); + + const vec3 kYIQToR = vec3(1.0, 0.956, 0.621); + const vec3 kYIQToG = vec3(1.0, -0.272, -0.647); + const vec3 kYIQToB = vec3(1.0, -1.107, 1.704); + + float YPrime = dot(color, kRGBToYPrime); + float I = dot(color, kRGBToI); + float Q = dot(color, kRGBToQ); + float chroma = sqrt(I * I + Q * Q); + + if (chroma < 1e-5) { + return color; + } + + float hue = atan(Q, I); + hue += hueAdjust; + + Q = chroma * sin(hue); + I = chroma * cos(hue); + + vec3 yIQ = vec3(YPrime, I, Q); + + return vec3(dot(yIQ, kYIQToR), dot(yIQ, kYIQToG), dot(yIQ, kYIQToB)); +} + +void main(void) { + vec2 uv = gl_FragCoord.xy / g_TexSize; + vec4 colour = texture(sampler2D(m_Texture, m_Sampler), uv); + + vec3 shiftedColour = hueShift(colour.rgb, radians(g_Strength * 360.0)); + + o_Colour = vec4(shiftedColour, colour.a); +} diff --git a/fluXis.Resources/Shaders/sh_Pixelate.fs b/fluXis.Resources/Shaders/sh_Pixelate.fs new file mode 100644 index 00000000..c0f3470e --- /dev/null +++ b/fluXis.Resources/Shaders/sh_Pixelate.fs @@ -0,0 +1,19 @@ +layout(std140, set = 0, binding = 0) uniform m_PixelateParameters +{ + vec2 g_TexSize; + float g_Strength; +}; + +layout(set = 1, binding = 0) uniform texture2D m_Texture; +layout(set = 1, binding = 1) uniform sampler m_Sampler; + +layout(location = 0) out vec4 o_Colour; + +void main(void) { + vec2 uv = gl_FragCoord.xy / g_TexSize; + float pixelSizeFactor = mix(1.0, min(g_TexSize.x, g_TexSize.y), 1.0 - g_Strength); + vec2 pixelSize = vec2(pixelSizeFactor, pixelSizeFactor * (g_TexSize.y / g_TexSize.x)); + vec2 pixelatedUV = (floor(uv * pixelSize) + 0.5) / pixelSize; + + o_Colour = textureLod(sampler2D(m_Texture, m_Sampler), pixelatedUV, 0.0); +} diff --git a/fluXis.Resources/fluXis.Resources.csproj b/fluXis.Resources/fluXis.Resources.csproj index ad45af01..6e5f29ca 100644 --- a/fluXis.Resources/fluXis.Resources.csproj +++ b/fluXis.Resources/fluXis.Resources.csproj @@ -11,4 +11,6 @@ + + From 7f0e3960adaeb662ba7e5644fa393fecdc0c76ee Mon Sep 17 00:00:00 2001 From: tylersfoot Date: Sun, 27 Oct 2024 02:11:09 -0400 Subject: [PATCH 2/2] added shaders & organized shader code - Added pixelate, glitch, and hue shift shaders - Made existing shader code (draw nodes) more uniform - Added more universal shader parameters (strength2/strength3) - Added support for multiple/custom settings/sliders in ShaderEntry.cs --- .../Graphics/Shaders/Bloom/BloomDrawNode.cs | 14 +- .../Shaders/Chromatic/ChromaticDrawNote.cs | 17 +- .../Graphics/Shaders/Glitch/GlitchDrawNode.cs | 32 +-- .../Shaders/Greyscale/GreyscaleDrawNode.cs | 24 ++- .../Shaders/HueShift/HueShiftDrawNode.cs | 17 +- .../Graphics/Shaders/Invert/InvertDrawNode.cs | 7 +- .../Graphics/Shaders/Mosaic/MosaicDrawNode.cs | 16 +- .../Graphics/Shaders/Noise/NoiseDrawNode.cs | 4 +- .../Shaders/Pixelate/PixelateDrawNode.cs | 17 +- .../Graphics/Shaders/Retro/RetroDrawNode.cs | 6 +- .../Graphics/Shaders/ShaderContainer.cs | 14 ++ .../Shaders/Vignette/VignetteDrawNode.cs | 4 +- .../Map/Structures/Events/ShaderEvent.cs | 3 + .../Edit/Tabs/Design/DesignShaderHandler.cs | 22 +- .../Tabs/Design/Points/Entries/ShaderEntry.cs | 199 ++++++++++++------ .../Screens/Gameplay/ShaderEventHandler.cs | 11 + fluXis.Resources/Shaders/sh_Glitch.fs | 22 +- fluXis.Resources/Shaders/sh_Pixelate.fs | 1 + 18 files changed, 287 insertions(+), 143 deletions(-) diff --git a/fluXis.Game/Graphics/Shaders/Bloom/BloomDrawNode.cs b/fluXis.Game/Graphics/Shaders/Bloom/BloomDrawNode.cs index 1e150442..bc201ae1 100644 --- a/fluXis.Game/Graphics/Shaders/Bloom/BloomDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Bloom/BloomDrawNode.cs @@ -16,8 +16,8 @@ public partial class BloomContainer { private class BloomContainerDrawNode : ShaderDrawNode { - private IUniformBuffer blurParametersBuffer; private float strength; + private IUniformBuffer parametersBuffer; private int radius; @@ -52,7 +52,7 @@ protected override void PopulateContents(IRenderer renderer) private void drawFrameBuffer(IRenderer renderer, int kernelRadius, float sigma, int rotation) { - blurParametersBuffer ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -61,7 +61,7 @@ private void drawFrameBuffer(IRenderer renderer, int kernelRadius, float sigma, { float radians = float.DegreesToRadians(rotation); - blurParametersBuffer.Data = blurParametersBuffer.Data with + parametersBuffer.Data = parametersBuffer.Data with { Radius = kernelRadius, Sigma = sigma, @@ -69,13 +69,19 @@ private void drawFrameBuffer(IRenderer renderer, int kernelRadius, float sigma, Direction = new Vector2(MathF.Cos(radians), MathF.Sin(radians)) }; - Shader.BindUniformBlock("m_BlurParameters", blurParametersBuffer); + Shader.BindUniformBlock("m_BlurParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); } } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + parametersBuffer?.Dispose(); + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] private record struct BlurParameters { diff --git a/fluXis.Game/Graphics/Shaders/Chromatic/ChromaticDrawNote.cs b/fluXis.Game/Graphics/Shaders/Chromatic/ChromaticDrawNote.cs index a5d0cc49..d65df1c8 100644 --- a/fluXis.Game/Graphics/Shaders/Chromatic/ChromaticDrawNote.cs +++ b/fluXis.Game/Graphics/Shaders/Chromatic/ChromaticDrawNote.cs @@ -13,7 +13,7 @@ public partial class ChromaticContainer private class ChromaticContainerDrawNode : ShaderDrawNode { private float strength; - private IUniformBuffer chromaticParametersBuffer; + private IUniformBuffer parametersBuffer; public ChromaticContainerDrawNode(ChromaticContainer source, BufferedDrawNodeSharedData sharedData) : base(source, sharedData) @@ -32,12 +32,12 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { - chromaticParametersBuffer ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -46,13 +46,13 @@ private void drawFrameBuffer(IRenderer renderer, float strength) using (BindFrameBuffer(target)) { - chromaticParametersBuffer.Data = chromaticParametersBuffer.Data with + parametersBuffer.Data = parametersBuffer.Data with { TexSize = current.Size, Radius = strength }; - Shader.BindUniformBlock("m_ChromaticParameters", chromaticParametersBuffer); + Shader.BindUniformBlock("m_ChromaticParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); @@ -62,7 +62,7 @@ private void drawFrameBuffer(IRenderer renderer, float strength) protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - chromaticParametersBuffer?.Dispose(); + parametersBuffer?.Dispose(); } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -70,8 +70,7 @@ private record struct ChromaticParameters { public UniformVector2 TexSize; public UniformFloat Radius; - private readonly UniformPadding8 pad1; - private readonly UniformPadding12 pad2; + private readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs b/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs index 2dd7c94c..b1045839 100644 --- a/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs @@ -12,9 +12,10 @@ public partial class GlitchContainer { private class GlitchContainerDrawNode : ShaderDrawNode { - private float strength; - private float strength2; // block size - private IUniformBuffer glitchParametersBuffer; + private float strength; // x strength + private float strength2; // y strength + private float strength3; // glitch block size + private IUniformBuffer parametersBuffer; public GlitchContainerDrawNode(GlitchContainer source, BufferedDrawNodeSharedData sharedData) : base(source, sharedData) @@ -26,20 +27,21 @@ public override void ApplyState() base.ApplyState(); strength = Source.Strength / 10f; - strength2 = Source.Strength2; + strength2 = Source.Strength2 / 10f; + strength3 = Source.Strength3; } protected override void PopulateContents(IRenderer renderer) { base.PopulateContents(renderer); - if (strength > 0) + if (strength > 0 || strength2 > 0) drawFrameBuffer(renderer); } private void drawFrameBuffer(IRenderer renderer) { - glitchParametersBuffer ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -48,15 +50,16 @@ private void drawFrameBuffer(IRenderer renderer) using (BindFrameBuffer(target)) { - glitchParametersBuffer.Data = glitchParametersBuffer.Data with + parametersBuffer.Data = parametersBuffer.Data with { TexSize = current.Size, - Strength = strength, - BlockSize = strength2, - Time = (float)Source.Time.Current % 10000 + StrengthX = strength, + StrengthY = strength2, + BlockSize = strength3, + Time = (float)Source.Time.Current % 10000f }; - Shader.BindUniformBlock("m_GlitchParameters", glitchParametersBuffer); + Shader.BindUniformBlock("m_GlitchParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); @@ -66,17 +69,18 @@ private void drawFrameBuffer(IRenderer renderer) protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - glitchParametersBuffer?.Dispose(); + parametersBuffer?.Dispose(); } [StructLayout(LayoutKind.Sequential, Pack = 1)] private record struct GlitchParameters { public UniformVector2 TexSize; - public UniformFloat Strength; + public UniformFloat StrengthX; + public UniformFloat StrengthY; public UniformFloat BlockSize; public UniformFloat Time; - private readonly UniformPadding12 pad1; + private readonly UniformPadding8 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/Greyscale/GreyscaleDrawNode.cs b/fluXis.Game/Graphics/Shaders/Greyscale/GreyscaleDrawNode.cs index f63164d3..4c2fa98e 100644 --- a/fluXis.Game/Graphics/Shaders/Greyscale/GreyscaleDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Greyscale/GreyscaleDrawNode.cs @@ -12,22 +12,32 @@ public partial class GreyscaleContainer { private class GreyscaleDrawNode : ShaderDrawNode { - private IUniformBuffer parameters; + private float strength; + private IUniformBuffer parametersBuffer; public GreyscaleDrawNode(ShaderContainer source, BufferedDrawNodeSharedData sharedData) : base(source, sharedData) { } + public override void ApplyState() + { + base.ApplyState(); + + strength = Source.Strength; + } + protected override void PopulateContents(IRenderer renderer) { base.PopulateContents(renderer); - drawFrameBuffer(renderer); + + if (strength > 0) + drawFrameBuffer(renderer); } private void drawFrameBuffer(IRenderer renderer) { - parameters ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -36,13 +46,13 @@ private void drawFrameBuffer(IRenderer renderer) using (BindFrameBuffer(target)) { - parameters.Data = parameters.Data with + parametersBuffer.Data = parametersBuffer.Data with { TexSize = current.Size, Strength = Source.Strength }; - Shader.BindUniformBlock("m_GreyscaleParameters", parameters); + Shader.BindUniformBlock("m_GreyscaleParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); @@ -52,7 +62,7 @@ private void drawFrameBuffer(IRenderer renderer) protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - parameters?.Dispose(); + parametersBuffer?.Dispose(); } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -61,8 +71,6 @@ private record struct GreyscaleParameters public UniformVector2 TexSize; public UniformFloat Strength; private readonly UniformPadding4 pad1; - private readonly UniformPadding4 pad2; - private readonly UniformPadding12 pad3; } } } diff --git a/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs index bde916e0..0305dcc7 100644 --- a/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs @@ -13,7 +13,7 @@ public partial class HueShiftContainer private class HueShiftContainerDrawNode : ShaderDrawNode { private float strength; - private IUniformBuffer hueShiftParametersBuffer; + private IUniformBuffer parametersBuffer; public HueShiftContainerDrawNode(HueShiftContainer source, BufferedDrawNodeSharedData sharedData) : base(source, sharedData) @@ -32,12 +32,12 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { - hueShiftParametersBuffer ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -46,13 +46,13 @@ private void drawFrameBuffer(IRenderer renderer, float strength) using (BindFrameBuffer(target)) { - hueShiftParametersBuffer.Data = hueShiftParametersBuffer.Data with + parametersBuffer.Data = parametersBuffer.Data with { TexSize = current.Size, Strength = strength }; - Shader.BindUniformBlock("m_HueShiftParameters", hueShiftParametersBuffer); + Shader.BindUniformBlock("m_HueShiftParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); @@ -62,7 +62,7 @@ private void drawFrameBuffer(IRenderer renderer, float strength) protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - hueShiftParametersBuffer?.Dispose(); + parametersBuffer?.Dispose(); } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -70,8 +70,7 @@ private record struct HueShiftParameters { public UniformVector2 TexSize; public UniformFloat Strength; - private readonly UniformPadding8 pad1; - private readonly UniformPadding12 pad2; + private readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/Invert/InvertDrawNode.cs b/fluXis.Game/Graphics/Shaders/Invert/InvertDrawNode.cs index 740b6f9f..eaa79733 100644 --- a/fluXis.Game/Graphics/Shaders/Invert/InvertDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Invert/InvertDrawNode.cs @@ -32,10 +32,10 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { invertParametersBuffer ??= renderer.CreateUniformBuffer(); @@ -70,8 +70,7 @@ private record struct InvertParameters { public UniformVector2 TexSize; public UniformFloat Strength; - private readonly UniformPadding8 pad1; - private readonly UniformPadding12 pad2; + private readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/Mosaic/MosaicDrawNode.cs b/fluXis.Game/Graphics/Shaders/Mosaic/MosaicDrawNode.cs index 3f6b3d23..e6a1abe1 100644 --- a/fluXis.Game/Graphics/Shaders/Mosaic/MosaicDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Mosaic/MosaicDrawNode.cs @@ -12,8 +12,8 @@ public partial class MosaicContainer { private class MosaicDrawNode : ShaderDrawNode { - private IUniformBuffer paramBuffer; private float strength; + private IUniformBuffer parametersBuffer; public MosaicDrawNode(MosaicContainer source, BufferedDrawNodeSharedData sharedData) : base(source, sharedData) @@ -37,7 +37,7 @@ protected override void PopulateContents(IRenderer renderer) private void drawFrameBuffer(IRenderer renderer) { - paramBuffer ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -46,9 +46,13 @@ private void drawFrameBuffer(IRenderer renderer) using (BindFrameBuffer(target)) { - paramBuffer.Data = new MosaicParameters { TexSize = current.Size, Strength = strength }; + parametersBuffer.Data = parametersBuffer.Data with + { + TexSize = current.Size, + Strength = strength + }; - Shader.BindUniformBlock("m_MosaicParameters", paramBuffer); + Shader.BindUniformBlock("m_MosaicParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); @@ -58,7 +62,7 @@ private void drawFrameBuffer(IRenderer renderer) protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - paramBuffer?.Dispose(); + parametersBuffer?.Dispose(); } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -66,7 +70,7 @@ private record struct MosaicParameters { public UniformVector2 TexSize; public UniformFloat Strength; - public UniformPadding4 _padding; + private readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/Noise/NoiseDrawNode.cs b/fluXis.Game/Graphics/Shaders/Noise/NoiseDrawNode.cs index 3dcb6737..e8d3efe9 100644 --- a/fluXis.Game/Graphics/Shaders/Noise/NoiseDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Noise/NoiseDrawNode.cs @@ -32,10 +32,10 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { parametersBuffer ??= renderer.CreateUniformBuffer(); diff --git a/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs index ffa7d9d1..e1119083 100644 --- a/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs @@ -13,7 +13,7 @@ public partial class PixelateContainer private class PixelateContainerDrawNode : ShaderDrawNode { private float strength; - private IUniformBuffer pixelateParametersBuffer; + private IUniformBuffer parametersBuffer; public PixelateContainerDrawNode(PixelateContainer source, BufferedDrawNodeSharedData sharedData) : base(source, sharedData) @@ -32,12 +32,12 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { - pixelateParametersBuffer ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -46,13 +46,13 @@ private void drawFrameBuffer(IRenderer renderer, float strength) using (BindFrameBuffer(target)) { - pixelateParametersBuffer.Data = pixelateParametersBuffer.Data with + parametersBuffer.Data = parametersBuffer.Data with { TexSize = current.Size, Strength = strength }; - Shader.BindUniformBlock("m_PixelateParameters", pixelateParametersBuffer); + Shader.BindUniformBlock("m_PixelateParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); @@ -62,7 +62,7 @@ private void drawFrameBuffer(IRenderer renderer, float strength) protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - pixelateParametersBuffer?.Dispose(); + parametersBuffer?.Dispose(); } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -70,8 +70,7 @@ private record struct PixelateParameters { public UniformVector2 TexSize; public UniformFloat Strength; - private readonly UniformPadding8 pad1; - private readonly UniformPadding12 pad2; + private readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/Retro/RetroDrawNode.cs b/fluXis.Game/Graphics/Shaders/Retro/RetroDrawNode.cs index 0d727496..640f0fe5 100644 --- a/fluXis.Game/Graphics/Shaders/Retro/RetroDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Retro/RetroDrawNode.cs @@ -32,10 +32,10 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { parametersBuffer ??= renderer.CreateUniformBuffer(); @@ -70,7 +70,7 @@ private record struct RetroParameters { public UniformVector2 TexSize; public UniformFloat Strength; - public readonly UniformPadding4 Pad; + public readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/ShaderContainer.cs b/fluXis.Game/Graphics/Shaders/ShaderContainer.cs index df0ed9bd..ac886d45 100644 --- a/fluXis.Game/Graphics/Shaders/ShaderContainer.cs +++ b/fluXis.Game/Graphics/Shaders/ShaderContainer.cs @@ -20,6 +20,7 @@ public abstract partial class ShaderContainer : Container, IBufferedDrawable private float strength; private float strength2; + private float strength3; public float Strength { @@ -47,6 +48,19 @@ public float Strength2 } } + public float Strength3 + { + get => strength3; + set + { + if (value == strength3) + return; + + strength3 = value; + Invalidate(Invalidation.DrawNode); + } + } + public bool DrawOriginal { get; set; } public ColourInfo EffectColour { get; set; } = Color4.White; public BlendingParameters EffectBlending { get; set; } = BlendingParameters.Inherit; diff --git a/fluXis.Game/Graphics/Shaders/Vignette/VignetteDrawNode.cs b/fluXis.Game/Graphics/Shaders/Vignette/VignetteDrawNode.cs index a17e5ac1..c1e9b60e 100644 --- a/fluXis.Game/Graphics/Shaders/Vignette/VignetteDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Vignette/VignetteDrawNode.cs @@ -32,10 +32,10 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { parametersBuffer ??= renderer.CreateUniformBuffer(); diff --git a/fluXis.Game/Map/Structures/Events/ShaderEvent.cs b/fluXis.Game/Map/Structures/Events/ShaderEvent.cs index 4aa1c07c..7e876b8b 100644 --- a/fluXis.Game/Map/Structures/Events/ShaderEvent.cs +++ b/fluXis.Game/Map/Structures/Events/ShaderEvent.cs @@ -53,6 +53,9 @@ public class ShaderParameters [JsonProperty("strength2")] public float Strength2 { get; set; } + + [JsonProperty("strength3")] + public float Strength3 { get; set; } } } diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs b/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs index 8b2d1f4a..50cfe5b2 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs @@ -44,28 +44,38 @@ private void handleGroup(ShaderType type, IEnumerable events) { container.Strength = 0; container.Strength2 = 0; + container.Strength3 = 0; return; } var progress = (clock.CurrentTime - current.Time) / current.Duration; - var end = current.EndParameters.Strength; + var endStrength = current.EndParameters.Strength; + var endStrength2 = current.EndParameters.Strength2; + var endStrength3 = current.EndParameters.Strength3; if (progress >= 1) { - container.Strength = end; - container.Strength2 = end; + container.Strength = endStrength; + container.Strength2 = endStrength2; + container.Strength3 = endStrength3; return; } var previous = events.LastOrDefault(e => e.Time < current.Time); - var start = current.UseStartParams ? current.StartParameters.Strength : previous?.EndParameters.Strength ?? 0; + var startStrength = current.UseStartParams ? current.StartParameters.Strength : previous?.EndParameters.Strength ?? 0; + var startStrength2 = current.UseStartParams ? current.StartParameters.Strength2 : previous?.EndParameters.Strength2 ?? 0; + var startStrength3 = current.UseStartParams ? current.StartParameters.Strength3 : previous?.EndParameters.Strength3 ?? 0; if (progress < 0) { - container.Strength = start; + container.Strength = startStrength; + container.Strength2 = startStrength2; + container.Strength3 = startStrength3; return; } - container.Strength = Interpolation.ValueAt(clock.CurrentTime, start, end, current.Time, current.Time + current.Duration); + container.Strength = Interpolation.ValueAt(clock.CurrentTime, startStrength, endStrength, current.Time, current.Time + current.Duration); + container.Strength2 = Interpolation.ValueAt(clock.CurrentTime, startStrength2, endStrength2, current.Time, current.Time + current.Duration); + container.Strength3 = Interpolation.ValueAt(clock.CurrentTime, startStrength3, endStrength3, current.Time, current.Time + current.Duration); } } diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs b/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs index 36bbf21c..aa2301ad 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs @@ -33,6 +33,8 @@ private float maxStrength private float maxStrength2 => 1f; + private float maxStrength3 => 1f; + private float step { get @@ -98,8 +100,10 @@ protected override IEnumerable CreateSettings() Bindable = new Bindable(shader.UseStartParams), OnStateChanged = enabled => { + RequestClose?.Invoke(); // until there is a way to refresh shader.UseStartParams = enabled; Map.Update(shader); + OpenSettings(); } }; @@ -114,11 +118,12 @@ protected override IEnumerable CreateSettings() Items = Enum.GetValues().ToList(), OnValueChanged = value => { + RequestClose?.Invoke(); // until there is a way to refresh shader.Type = value; Map.Update(shader); + OpenSettings(); } }, - new PointSettingsToggle { Text = "Use Start Value", @@ -129,76 +134,150 @@ protected override IEnumerable CreateSettings() shader.UseStartParams = enabled; Map.Update(shader); } - }, - - new PointSettingsSlider - { - Enabled = startValToggle.Bindable, - Text = "Start Strength", - TooltipText = "The strength of the shader effect.", - CurrentValue = shader.StartParameters.Strength, - Min = 0, - Max = maxStrength, - Step = step, - OnValueChanged = value => - { - shader.StartParameters.Strength = value; - Map.Update(shader); - } - }, - - new PointSettingsSlider - { - Text = "End Strength", - TooltipText = "The strength of the shader effect.", - CurrentValue = shader.EndParameters.Strength, - Min = 0, - Max = maxStrength, - Step = step, - OnValueChanged = value => - { - shader.EndParameters.Strength = value; - Map.Update(shader); - } } }; - // edge cases for shaders with extra parameters - if (shader.Type == ShaderType.Glitch) + // edge cases for shaders with extra/different parameter(s) + switch (shader.Type) { - settings.AddRange(new Drawable[] - { - new PointSettingsSlider + case ShaderType.Glitch: + settings.AddRange(new Drawable[] { - Enabled = startValToggle.Bindable, - Text = "Start Block Size", - TooltipText = "The size of the glitch blocks.", - CurrentValue = shader.StartParameters.Strength2, - Min = 0, - Max = maxStrength2, - Step = step, - OnValueChanged = value => + new PointSettingsSlider + { + Enabled = startValToggle.Bindable, + Text = "Start X Strength", + TooltipText = "The strength of the glitch effect on the x-axis.", + CurrentValue = shader.StartParameters.Strength, + Min = 0, + Max = maxStrength, + Step = step, + OnValueChanged = value => + { + shader.StartParameters.Strength = value; + Map.Update(shader); + } + }, + new PointSettingsSlider + { + Text = "End X Strength", + TooltipText = "The strength of the glitch effect on the x-axis.", + CurrentValue = shader.EndParameters.Strength, + Min = 0, + Max = maxStrength, + Step = step, + OnValueChanged = value => + { + shader.EndParameters.Strength = value; + Map.Update(shader); + } + }, + new PointSettingsSlider { - shader.StartParameters.Strength2 = value; - Map.Update(shader); + Enabled = startValToggle.Bindable, + Text = "Start Y Strength", + TooltipText = "The strength of the glitch effect on the y-axis.", + CurrentValue = shader.StartParameters.Strength2, + Min = 0, + Max = maxStrength2, + Step = step, + OnValueChanged = value => + { + shader.StartParameters.Strength2 = value; + Map.Update(shader); + } + }, + new PointSettingsSlider + { + Text = "End Y Strength", + TooltipText = "The strength of the glitch effect on the y-axis.", + CurrentValue = shader.EndParameters.Strength2, + Min = 0, + Max = maxStrength2, + Step = step, + OnValueChanged = value => + { + shader.EndParameters.Strength2 = value; + Map.Update(shader); + } + }, + new PointSettingsSlider + { + Enabled = startValToggle.Bindable, + Text = "Start Block Size", + TooltipText = "The size of the glitch blocks.", + CurrentValue = shader.StartParameters.Strength3, + Min = 0, + Max = maxStrength3, + Step = step, + OnValueChanged = value => + { + shader.StartParameters.Strength3 = value; + Map.Update(shader); + } + }, + new PointSettingsSlider + { + Text = "End Block Size", + TooltipText = "The size of the glitch blocks.", + CurrentValue = shader.EndParameters.Strength3, + Min = 0, + Max = maxStrength3, + Step = step, + OnValueChanged = value => + { + shader.EndParameters.Strength3 = value; + Map.Update(shader); + } } - }, + }); + break; - new PointSettingsSlider + case ShaderType.Bloom: + case ShaderType.Greyscale: + case ShaderType.Invert: + case ShaderType.Chromatic: + case ShaderType.Mosaic: + case ShaderType.Noise: + case ShaderType.Vignette: + case ShaderType.Retro: + case ShaderType.HueShift: + case ShaderType.Pixelate: + default: // default shader settings + settings.AddRange(new Drawable[] { - Text = "End Block Size", - TooltipText = "The size of the glitch blocks.", - CurrentValue = shader.EndParameters.Strength2, - Min = 0, - Max = maxStrength2, - Step = step, - OnValueChanged = value => + new PointSettingsSlider { - shader.EndParameters.Strength2 = value; - Map.Update(shader); + Enabled = startValToggle.Bindable, + Text = "Start Strength", + TooltipText = "The strength of the shader effect.", + CurrentValue = shader.StartParameters.Strength, + Min = 0, + Max = maxStrength, + Step = step, + OnValueChanged = value => + { + shader.StartParameters.Strength = value; + Map.Update(shader); + } + }, + + new PointSettingsSlider + { + Text = "End Strength", + TooltipText = "The strength of the shader effect.", + CurrentValue = shader.EndParameters.Strength, + Min = 0, + Max = maxStrength, + Step = step, + OnValueChanged = value => + { + shader.EndParameters.Strength = value; + Map.Update(shader); + } } - } - }); + }); + break; } settings.Add(new PointSettingsEasing(Map, shader)); diff --git a/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs b/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs index 15be12c7..813f38be 100644 --- a/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs +++ b/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs @@ -46,10 +46,12 @@ private void trigger(ShaderEvent ev) { handler.StrengthTo(ev.StartParameters.Strength); handler.Strength2To(ev.StartParameters.Strength2); + handler.Strength3To(ev.StartParameters.Strength3); } handler.StrengthTo(ev.EndParameters.Strength, ev.Duration, ev.Easing); handler.Strength2To(ev.EndParameters.Strength2, ev.Duration, ev.Easing); + handler.Strength3To(ev.EndParameters.Strength3, ev.Duration, ev.Easing); } // the shader stack is outside the gameplay clock. @@ -71,6 +73,12 @@ private float strength2 set => container.Strength2 = value; } + private float strength3 + { + get => container.Strength3; + set => container.Strength3 = value; + } + public TransformHandler(ShaderContainer container) { this.container = container; @@ -82,5 +90,8 @@ public void StrengthTo(float str, double dur = 0, Easing ease = Easing.None) public void Strength2To(float str, double dur = 0, Easing ease = Easing.None) => this.TransformTo(nameof(strength2), str, dur, ease); + + public void Strength3To(float str, double dur = 0, Easing ease = Easing.None) + => this.TransformTo(nameof(strength3), str, dur, ease); } } diff --git a/fluXis.Resources/Shaders/sh_Glitch.fs b/fluXis.Resources/Shaders/sh_Glitch.fs index 8e71a703..2fca3e73 100644 --- a/fluXis.Resources/Shaders/sh_Glitch.fs +++ b/fluXis.Resources/Shaders/sh_Glitch.fs @@ -1,9 +1,10 @@ layout(std140, set = 0, binding = 0) uniform m_GlitchParameters { vec2 g_TexSize; - float g_Strength; - float g_Time; + float g_StrengthX; + float g_StrengthY; float g_BlockSize; + float g_Time; }; layout(set = 1, binding = 0) uniform texture2D m_Texture; @@ -16,16 +17,23 @@ highp float random(highp vec2 st, float seed) return fract(sin(dot(st.xy, vec2(12.9898, 78.233) + seed)) * 43758.5453123); } + void main(void) { vec2 uv = gl_FragCoord.xy / g_TexSize; + float blockSizeInPixels = mix(1.0, min(g_TexSize.x, g_TexSize.y), g_BlockSize); + vec2 blockUV = floor(uv * blockSizeInPixels) / blockSizeInPixels; - float randomShift = (random(blockUV, g_Time) - 0.5) * g_Strength; + float randomShiftX = (random(blockUV, g_Time) - 0.5) * g_StrengthX; + float randomShiftY = (random(blockUV + vec2(5.0), g_Time) - 0.5) * g_StrengthY; + + vec2 fixedUV = uv; + fixedUV.x += randomShiftX; + fixedUV.y += randomShiftY; + + vec4 pixelColor = textureLod(sampler2D(m_Texture, m_Sampler), fixedUV, 0.0); - uv.x += randomShift; - - vec4 pixelColor = textureLod(sampler2D(m_Texture, m_Sampler), uv, 0.0); o_Colour = pixelColor; -} +} \ No newline at end of file diff --git a/fluXis.Resources/Shaders/sh_Pixelate.fs b/fluXis.Resources/Shaders/sh_Pixelate.fs index c0f3470e..20a0f1ad 100644 --- a/fluXis.Resources/Shaders/sh_Pixelate.fs +++ b/fluXis.Resources/Shaders/sh_Pixelate.fs @@ -11,6 +11,7 @@ layout(location = 0) out vec4 o_Colour; void main(void) { vec2 uv = gl_FragCoord.xy / g_TexSize; + float pixelSizeFactor = mix(1.0, min(g_TexSize.x, g_TexSize.y), 1.0 - g_Strength); vec2 pixelSize = vec2(pixelSizeFactor, pixelSizeFactor * (g_TexSize.y / g_TexSize.x)); vec2 pixelatedUV = (floor(uv * pixelSize) + 0.5) / pixelSize;