From a38c6c1aca7e93cf1ac09facd33bf41358d02593 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sun, 14 Sep 2025 20:48:24 +0200 Subject: [PATCH] Revert "Add heat distortion shader for hot gases" (#40352) --- .../EntitySystems/GasTileOverlaySystem.cs | 5 - .../Atmos/Overlays/GasTileHeatOverlay.cs | 210 ------------------ .../EntitySystems/GasTileOverlaySystem.cs | 44 +--- .../SharedGasTileOverlaySystem.cs | 79 +------ Content.Shared/CCVar/CCVars.Net.cs | 19 -- Resources/Prototypes/Shaders/shaders.yml | 10 - Resources/Textures/Shaders/heat.swsl | 90 -------- 7 files changed, 14 insertions(+), 443 deletions(-) delete mode 100644 Content.Client/Atmos/Overlays/GasTileHeatOverlay.cs delete mode 100644 Resources/Textures/Shaders/heat.swsl diff --git a/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs index d7894265c8..ad26436946 100644 --- a/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -19,7 +19,6 @@ namespace Content.Client.Atmos.EntitySystems [Dependency] private readonly SharedTransformSystem _xformSys = default!; private GasTileOverlay _overlay = default!; - private GasTileHeatOverlay _heatOverlay = default!; public override void Initialize() { @@ -29,16 +28,12 @@ namespace Content.Client.Atmos.EntitySystems _overlay = new GasTileOverlay(this, EntityManager, _resourceCache, ProtoMan, _spriteSys, _xformSys); _overlayMan.AddOverlay(_overlay); - - _heatOverlay = new GasTileHeatOverlay(); - _overlayMan.AddOverlay(_heatOverlay); } public override void Shutdown() { base.Shutdown(); _overlayMan.RemoveOverlay(); - _overlayMan.RemoveOverlay(); } private void OnHandleState(EntityUid gridUid, GasTileOverlayComponent comp, ref ComponentHandleState args) diff --git a/Content.Client/Atmos/Overlays/GasTileHeatOverlay.cs b/Content.Client/Atmos/Overlays/GasTileHeatOverlay.cs deleted file mode 100644 index 36f0a065c1..0000000000 --- a/Content.Client/Atmos/Overlays/GasTileHeatOverlay.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System.Numerics; -using Content.Shared.Atmos; -using Content.Shared.Atmos.Components; -using Content.Client.Atmos.EntitySystems; -using Content.Shared.CCVar; -using Robust.Client.Graphics; -using Robust.Shared.Configuration; -using Robust.Shared.Enums; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Prototypes; - -namespace Content.Client.Atmos.Overlays; - -public sealed class GasTileHeatOverlay : Overlay -{ - public override bool RequestScreenTexture { get; set; } = true; - private static readonly ProtoId UnshadedShader = "unshaded"; - private static readonly ProtoId HeatOverlayShader = "Heat"; - - [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly IPrototypeManager _proto = default!; - [Dependency] private readonly IClyde _clyde = default!; - [Dependency] private readonly IConfigurationManager _configManager = default!; - // We can't resolve this immediately, because it's an entitysystem, but we will attempt to resolve and cache this - // once we begin to draw. - private GasTileOverlaySystem? _gasTileOverlay; - private readonly SharedTransformSystem _xformSys; - - private IRenderTexture? _heatTarget; - private IRenderTexture? _heatBlurTarget; - - public override OverlaySpace Space => OverlaySpace.WorldSpace; - private readonly ShaderInstance _shader; - - public GasTileHeatOverlay() - { - IoCManager.InjectDependencies(this); - _xformSys = _entManager.System(); - - _shader = _proto.Index(HeatOverlayShader).InstanceUnique(); - - _configManager.OnValueChanged(CCVars.ReducedMotion, SetReducedMotion, invokeImmediately: true); - - } - - private void SetReducedMotion(bool reducedMotion) - { - _shader.SetParameter("strength_scale", reducedMotion ? 0.5f : 1f); - _shader.SetParameter("speed_scale", reducedMotion ? 0.25f : 1f); - } - - protected override bool BeforeDraw(in OverlayDrawArgs args) - { - if (args.MapId == MapId.Nullspace) - return false; - - // If we haven't resolved this yet, give it a try or bail - _gasTileOverlay ??= _entManager.System(); - - if (_gasTileOverlay == null) - return false; - - var target = args.Viewport.RenderTarget; - - // Probably the resolution of the game window changed, remake the textures. - if (_heatTarget?.Texture.Size != target.Size) - { - _heatTarget?.Dispose(); - _heatTarget = _clyde.CreateRenderTarget( - target.Size, - new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), - name: nameof(GasTileHeatOverlay)); - } - if (_heatBlurTarget?.Texture.Size != target.Size) - { - _heatBlurTarget?.Dispose(); - _heatBlurTarget = _clyde.CreateRenderTarget( - target.Size, - new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), - name: $"{nameof(GasTileHeatOverlay)}-blur"); - } - - var overlayQuery = _entManager.GetEntityQuery(); - - args.WorldHandle.UseShader(_proto.Index(UnshadedShader).Instance()); - - var mapId = args.MapId; - var worldAABB = args.WorldAABB; - var worldBounds = args.WorldBounds; - var worldHandle = args.WorldHandle; - var worldToViewportLocal = args.Viewport.GetWorldToLocalMatrix(); - - // If there is no distortion after checking all visible tiles, we can bail early - var anyDistortion = false; - - // We're rendering in the context of the heat target texture, which will encode data as to where and how strong - // the heat distortion will be - args.WorldHandle.RenderInRenderTarget(_heatTarget, - () => - { - List> grids = new(); - _mapManager.FindGridsIntersecting(mapId, worldAABB, ref grids); - foreach (var grid in grids) - { - if (!overlayQuery.TryGetComponent(grid.Owner, out var comp)) - continue; - - var gridEntToWorld = _xformSys.GetWorldMatrix(grid.Owner); - var gridEntToViewportLocal = gridEntToWorld * worldToViewportLocal; - - if (!Matrix3x2.Invert(gridEntToViewportLocal, out var viewportLocalToGridEnt)) - continue; - - var uvToUi = Matrix3Helpers.CreateScale(_heatTarget.Size.X, -_heatTarget.Size.Y); - var uvToGridEnt = uvToUi * viewportLocalToGridEnt; - - // Because we want the actual distortion to be calculated based on the grid coordinates*, we need - // to pass a matrix transformation to go from the viewport coordinates to grid coordinates. - // * (why? because otherwise the effect would shimmer like crazy as you moved around, think - // moving a piece of warped glass above a picture instead of placing the warped glass on the - // paper and moving them together) - _shader.SetParameter("grid_ent_from_viewport_local", uvToGridEnt); - - // Draw commands (like DrawRect) will be using grid coordinates from here - worldHandle.SetTransform(gridEntToViewportLocal); - - // We only care about tiles that fit in these bounds - var floatBounds = worldToViewportLocal.TransformBox(worldBounds).Enlarged(grid.Comp.TileSize); - var localBounds = new Box2i( - (int)MathF.Floor(floatBounds.Left), - (int)MathF.Floor(floatBounds.Bottom), - (int)MathF.Ceiling(floatBounds.Right), - (int)MathF.Ceiling(floatBounds.Top)); - - // for each tile and its gas ---> - foreach (var chunk in comp.Chunks.Values) - { - var enumerator = new GasChunkEnumerator(chunk); - - while (enumerator.MoveNext(out var tileGas)) - { - // ---> - // Check and make sure the tile is within the viewport/screen - var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y); - if (!localBounds.Contains(tilePosition)) - continue; - - // Get the distortion strength from the temperature and bail if it's not hot enough - var strength = _gasTileOverlay.GetHeatDistortionStrength(tileGas.Temperature); - if (strength <= 0f) - continue; - - anyDistortion = true; - // Encode the strength in the red channel, then 1.0 alpha if it's an active tile. - // BlurRenderTarget will then apply a blur around the edge, but we don't want it to bleed - // past the tile. - // So we use this alpha channel to chop the lower alpha values off in the shader to fit a - // fit mask back into the tile. - worldHandle.DrawRect( - Box2.CenteredAround(tilePosition + new Vector2(0.5f, 0.5f), grid.Comp.TileSizeVector), - new Color(strength,0f, 0f, strength > 0f ? 1.0f : 0f)); - } - } - } - }, - // This clears the buffer to all zero first... - new Color(0, 0, 0, 0)); - - // no distortion, no need to render - if (!anyDistortion) - { - // Return the draw handle to normal settings - args.WorldHandle.UseShader(null); - args.WorldHandle.SetTransform(Matrix3x2.Identity); - return false; - } - - // Clear to draw - return true; - } - - protected override void Draw(in OverlayDrawArgs args) - { - if (ScreenTexture is null || _heatTarget is null || _heatBlurTarget is null) - return; - - // Blur to soften the edges of the distortion. the lower parts of the alpha channel need to get cut off in the - // distortion shader to keep them in tile bounds. - _clyde.BlurRenderTarget(args.Viewport, _heatTarget, _heatBlurTarget, args.Viewport.Eye!, 14f); - - // Set up and render the distortion - _shader.SetParameter("SCREEN_TEXTURE", ScreenTexture); - args.WorldHandle.UseShader(_shader); - args.WorldHandle.DrawTextureRect(_heatTarget.Texture, args.WorldBounds); - - // Return the draw handle to normal settings - args.WorldHandle.UseShader(null); - args.WorldHandle.SetTransform(Matrix3x2.Identity); - } - - protected override void DisposeBehavior() - { - _heatTarget = null; - _heatBlurTarget = null; - _configManager.UnsubValueChanged(CCVars.ReducedMotion, SetReducedMotion); - base.DisposeBehavior(); - } -} diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs index e63a57c3b6..4882e93d23 100644 --- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -1,4 +1,6 @@ +using System.Linq; using System.Runtime.CompilerServices; +using System.Threading.Tasks; using Content.Server.Atmos.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; @@ -11,6 +13,7 @@ using JetBrains.Annotations; using Microsoft.Extensions.ObjectPool; using Robust.Server.Player; using Robust.Shared; +using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -29,6 +32,7 @@ namespace Content.Server.Atmos.EntitySystems [Robust.Shared.IoC.Dependency] private readonly IGameTiming _gameTiming = default!; [Robust.Shared.IoC.Dependency] private readonly IPlayerManager _playerManager = default!; [Robust.Shared.IoC.Dependency] private readonly IMapManager _mapManager = default!; + [Robust.Shared.IoC.Dependency] private readonly IConfigurationManager _confMan = default!; [Robust.Shared.IoC.Dependency] private readonly IParallelManager _parMan = default!; [Robust.Shared.IoC.Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Robust.Shared.IoC.Dependency] private readonly ChunkingSystem _chunkingSys = default!; @@ -60,12 +64,6 @@ namespace Content.Server.Atmos.EntitySystems private EntityQuery _gridQuery; private EntityQuery _query; - /// - /// How much the distortion strength should change for the temperature of a tile to be dirtied. - /// The strength goes from 0.0f to 1.0f, so 0.05f gives it essentially 20 "steps" - /// - private float _heatDistortionStrengthChangeTolerance; - public override void Initialize() { base.Initialize(); @@ -87,10 +85,9 @@ namespace Content.Server.Atmos.EntitySystems }; _playerManager.PlayerStatusChanged += OnPlayerStatusChanged; - Subs.CVar(ConfMan, CCVars.NetGasOverlayTickRate, UpdateTickRate, true); - Subs.CVar(ConfMan, CCVars.GasOverlayThresholds, UpdateThresholds, true); - Subs.CVar(ConfMan, CVars.NetPVS, OnPvsToggle, true); - Subs.CVar(ConfMan, CCVars.GasOverlayHeatThreshold, UpdateHeatThresholds, true); + Subs.CVar(_confMan, CCVars.NetGasOverlayTickRate, UpdateTickRate, true); + Subs.CVar(_confMan, CCVars.GasOverlayThresholds, UpdateThresholds, true); + Subs.CVar(_confMan, CVars.NetPVS, OnPvsToggle, true); SubscribeLocalEvent(Reset); SubscribeLocalEvent(OnStartup); @@ -140,7 +137,6 @@ namespace Content.Server.Atmos.EntitySystems private void UpdateTickRate(float value) => _updateInterval = value > 0.0f ? 1 / value : float.MaxValue; private void UpdateThresholds(int value) => _thresholds = value; - private void UpdateHeatThresholds(float v) => _heatDistortionStrengthChangeTolerance = MathHelper.Clamp01(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Invalidate(Entity grid, Vector2i index) @@ -179,9 +175,7 @@ namespace Content.Server.Atmos.EntitySystems public GasOverlayData GetOverlayData(GasMixture? mixture) { - var data = new GasOverlayData(0, - new byte[VisibleGasId.Length], - mixture?.Temperature ?? Atmospherics.TCMB); + var data = new GasOverlayData(0, new byte[VisibleGasId.Length]); for (var i = 0; i < VisibleGasId.Length; i++) { @@ -221,17 +215,15 @@ namespace Content.Server.Atmos.EntitySystems } var changed = false; - var temp = tile.Hotspot.Valid ? tile.Hotspot.Temperature : tile.Air?.Temperature ?? Atmospherics.TCMB; if (oldData.Equals(default)) { changed = true; - oldData = new GasOverlayData(tile.Hotspot.State, new byte[VisibleGasId.Length], temp); + oldData = new GasOverlayData(tile.Hotspot.State, new byte[VisibleGasId.Length]); } - else if (oldData.FireState != tile.Hotspot.State || - CheckTemperatureTolerance(oldData.Temperature, temp, _heatDistortionStrengthChangeTolerance)) + else if (oldData.FireState != tile.Hotspot.State) { changed = true; - oldData = new GasOverlayData(tile.Hotspot.State, oldData.Opacity, temp); + oldData = new GasOverlayData(tile.Hotspot.State, oldData.Opacity); } if (tile is {Air: not null, NoGridTile: false}) @@ -279,20 +271,6 @@ namespace Content.Server.Atmos.EntitySystems return true; } - /// - /// This function determines whether the change in temperature is significant enough to warrant dirtying the tile data. - /// - private bool CheckTemperatureTolerance(float tempA, float tempB, float tolerance) - { - var (strengthA, strengthB) = (GetHeatDistortionStrength(tempA), GetHeatDistortionStrength(tempB)); - - return (strengthA <= 0f && strengthB > 0f) || // change to or from 0 - (strengthB <= 0f && strengthA > 0f) || - (strengthA >= 1f && strengthB < 1f) || // change to or from 1 - (strengthB >= 1f && strengthA < 1f) || - Math.Abs(strengthA - strengthB) > tolerance; // other change within tolerance - } - private void UpdateOverlayData() { // TODO parallelize? diff --git a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs index 1c7da938d4..8e7dfdedaf 100644 --- a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs +++ b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs @@ -1,7 +1,5 @@ using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Prototypes; -using Content.Shared.CCVar; -using Robust.Shared.Configuration; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; @@ -10,26 +8,11 @@ namespace Content.Shared.Atmos.EntitySystems { public abstract class SharedGasTileOverlaySystem : EntitySystem { - /// - /// The temperature at which the heat distortion effect starts to be applied. - /// - private float _tempAtMinHeatDistortion; - /// - /// The temperature at which the heat distortion effect is at maximum strength. - /// - private float _tempAtMaxHeatDistortion; - /// - /// Calculated linear slope and intercept to map temperature to a heat distortion strength from 0.0 to 1.0 - /// - private float _heatDistortionSlope; - private float _heatDistortionIntercept; - public const byte ChunkSize = 8; protected float AccumulatedFrameTime; protected bool PvsEnabled; [Dependency] protected readonly IPrototypeManager ProtoMan = default!; - [Dependency] protected readonly IConfigurationManager ConfMan = default!; /// /// array of the ids of all visible gases. @@ -39,11 +22,6 @@ namespace Content.Shared.Atmos.EntitySystems public override void Initialize() { base.Initialize(); - - // Make sure the heat distortion variables are updated if the CVars change - Subs.CVar(ConfMan, CCVars.GasOverlayHeatMinimum, UpdateMinHeat, true); - Subs.CVar(ConfMan, CCVars.GasOverlayHeatMaximum, UpdateMaxHeat, true); - SubscribeLocalEvent(OnGetState); List visibleGases = new(); @@ -58,29 +36,6 @@ namespace Content.Shared.Atmos.EntitySystems VisibleGasId = visibleGases.ToArray(); } - private void UpdateMaxHeat(float val) - { - _tempAtMaxHeatDistortion = val; - UpdateHeatSlopeAndIntercept(); - } - - private void UpdateMinHeat(float val) - { - _tempAtMinHeatDistortion = val; - UpdateHeatSlopeAndIntercept(); - } - - private void UpdateHeatSlopeAndIntercept() - { - // Make sure to avoid invalid settings (min == max or min > max) - // I'm not sure if CVars can have constraints or if CVar subscribers can reject changes. - var diff = _tempAtMinHeatDistortion < _tempAtMaxHeatDistortion - ? _tempAtMaxHeatDistortion - _tempAtMinHeatDistortion - : 0.001f; - _heatDistortionSlope = 1.0f / diff; - _heatDistortionIntercept = -_tempAtMinHeatDistortion * _heatDistortionSlope; - } - private void OnGetState(EntityUid uid, GasTileOverlayComponent component, ref ComponentGetState args) { if (PvsEnabled && !args.ReplayState) @@ -117,26 +72,14 @@ namespace Content.Shared.Atmos.EntitySystems [ViewVariables] public readonly byte[] Opacity; - /// - /// This temperature is currently only used by the GasTileHeatOverlay. - /// This value will only reflect the true temperature of the gas when the temperature is between - /// and as these are the only - /// values at which the heat distortion varies. - /// Additionally, it will only update when the heat distortion strength changes by - /// . By default, this is 5%, which corresponds to - /// 20 steps from to . - /// For 325K to 1000K with 5% tolerance, then this field will dirty only if it differs by 33.75K, or 20 steps. - /// - [ViewVariables] - public readonly float Temperature; - // TODO change fire color based on temps + // But also: dont dirty on a 0.01 kelvin change in temperatures. + // Either have a temp tolerance, or map temperature -> byte levels - public GasOverlayData(byte fireState, byte[] opacity, float temperature) + public GasOverlayData(byte fireState, byte[] opacity) { FireState = fireState; Opacity = opacity; - Temperature = temperature; } public bool Equals(GasOverlayData other) @@ -156,26 +99,10 @@ namespace Content.Shared.Atmos.EntitySystems } } - // This is only checking if two datas are equal -- a different routine is used to check if the - // temperature differs enough to dirty the chunk using a much wider tolerance. - if (!MathHelper.CloseToPercent(Temperature, other.Temperature)) - return false; - return true; } } - /// - /// Calculate the heat distortion from a temperature. - /// Returns 0.0f below TempAtMinHeatDistortion and 1.0f above TempAtMaxHeatDistortion. - /// - /// - /// - public float GetHeatDistortionStrength(float temp) - { - return MathHelper.Clamp01(temp * _heatDistortionSlope + _heatDistortionIntercept); - } - [Serializable, NetSerializable] public sealed class GasOverlayUpdateEvent : EntityEventArgs { diff --git a/Content.Shared/CCVar/CCVars.Net.cs b/Content.Shared/CCVar/CCVars.Net.cs index df8dc6932d..b7465def2e 100644 --- a/Content.Shared/CCVar/CCVars.Net.cs +++ b/Content.Shared/CCVar/CCVars.Net.cs @@ -12,23 +12,4 @@ public sealed partial class CCVars public static readonly CVarDef GasOverlayThresholds = CVarDef.Create("net.gasoverlaythresholds", 20); - - public static readonly CVarDef GasOverlayHeatThreshold = - CVarDef.Create("net.gasoverlayheatthreshold", - 0.05f, - CVar.SERVER | CVar.REPLICATED, - "Threshold for sending tile temperature updates to client in percent of distortion strength," + - "from 0.0 to 1.0. Example: 0.05 = 5%, which means heat distortion will appear in 20 'steps'."); - - public static readonly CVarDef GasOverlayHeatMinimum = - CVarDef.Create("net.gasoverlayheatminimum", - 325f, - CVar.SERVER | CVar.REPLICATED, - "Temperature at which heat distortion effect will begin to apply."); - - public static readonly CVarDef GasOverlayHeatMaximum = - CVarDef.Create("net.gasoverlayheatmaximum", - 1000f, - CVar.SERVER | CVar.REPLICATED, - "Temperature at which heat distortion effect will be at maximum strength."); } diff --git a/Resources/Prototypes/Shaders/shaders.yml b/Resources/Prototypes/Shaders/shaders.yml index f7c704909e..057abf0ac2 100644 --- a/Resources/Prototypes/Shaders/shaders.yml +++ b/Resources/Prototypes/Shaders/shaders.yml @@ -115,13 +115,3 @@ id: Hologram kind: source path: "/Textures/Shaders/hologram.swsl" - -- type: shader - id: Heat - kind: source - path: "/Textures/Shaders/heat.swsl" - params: - spatial_scale: 1.0 - strength_scale: 1.0 - speed_scale: 1.0 - grid_ent_from_viewport_local: 1,0,0,1,0,1 diff --git a/Resources/Textures/Shaders/heat.swsl b/Resources/Textures/Shaders/heat.swsl deleted file mode 100644 index 8e478f471a..0000000000 --- a/Resources/Textures/Shaders/heat.swsl +++ /dev/null @@ -1,90 +0,0 @@ -uniform sampler2D SCREEN_TEXTURE; - -// Number of frequencies to combine, can't be a parameter/uniform else it causes problems in compatibility mode -// I have no idea why -const highp int N = 32; - -uniform highp float spatial_scale; // spatial scaling of modes, higher = fine turbulence, lower = coarse turbulence -uniform highp float strength_scale; // distortion strength -uniform highp float speed_scale; // scaling factor on the speed of the animation -// Matrix to convert screen coordinates into grid coordinates -// This is to "pin" the effect to the grid, so that it does not shimmer as you move -uniform highp mat3 grid_ent_from_viewport_local; - -const highp float TWO_PI = 6.28318530718; - // This is just the default target values so that the external parameters can be normalized to 1 -const highp float strength_factor = 0.0005; -const highp float spatial_factor = 22.0; - -// 1D pseudo-random function -highp float random_1d(highp float n) { - return fract(sin(n * 12.9898) * 43758.5453); -} - -// Kolmogorov amplitude, power spectrum goes as k^(–11/6) -highp float kolAmp(highp float k) { - return pow(k, -11.0 / 6.0); -} - -void fragment() { - - highp vec2 ps = vec2(1.0/SCREEN_PIXEL_SIZE.x, 1.0/SCREEN_PIXEL_SIZE.y); - highp float aspectratio = ps.x / ps.y; - - // scale the scale factor with the number of modes just cuz it works reasonably - highp float s_scale = spatial_scale * spatial_factor / sqrt(float(N)); - - // Coordinates to use to calculate the effects, convert to grid coordinates - highp vec2 uvW = (grid_ent_from_viewport_local * vec3(UV.x, UV.y, 1.0)).xy; - // Scale the coordinates - uvW *= s_scale; - - // accumulate phase gradienta - highp vec2 grad = vec2(0.0); - - for (lowp int i = 0; i < N; i++) { - // float cast of the index - highp float fi = float(i); - - // Pick a random direction - highp float ang = random_1d(fi + 1.0) * TWO_PI; - highp vec2 dir = vec2(cos(ang), sin(ang)); - - // Pick a random spatial frequency from 0.5 to 30 - highp float k = mix(0.5, 30.0, random_1d(fi + 17.0)); - - // Pick a random speed from 0.05 to 0.20 - highp float speed = mix(3., 8., random_1d(fi + 33.0)); - - // Pick a random phase offset - highp float phi_0 = random_1d(fi + 49.0) * TWO_PI; - - // phase argument - highp float t = dot(dir, uvW) * k + TIME * speed * speed_scale + phi_0; - - // analytical gradient: ∇[sin(t)] = cos(t) * ∇t - // ∇t = k * dir * scale (scale is factored out) - grad += kolAmp(k) * cos(t) * k * dir; - } - // Spatial scaling (coarse or fine turbulence) - grad *= s_scale; - - // The texture should have been blurred using a previous operation - // We use the alpha channel to cut off the blur that bleeds outside the tile, then we rescale - // the mask back up to 0.0 to 1.0 - highp float mask = clamp((zTexture(UV).a - 0.5)*2.0, 0.00, 1.0); - - // Calculate warped UV using the turbulence gradient - // The strength of the turbulence is encoded into the red channel of TEXTURE - // Give it a little polynomial boost: https://www.wolframalpha.com/input?i=-x%5E2+%2B2x+from+0+to+1 - highp float heatStrength = zTexture(UV).r*1.0; - heatStrength = clamp(-heatStrength*heatStrength + 2.0*heatStrength, 0.0, 1.0); - highp vec2 uvDist = UV + (strength_scale * strength_factor * heatStrength * mask) * grad; - - // Apply to the texture - COLOR = texture2D(SCREEN_TEXTURE, uvDist); - - // Uncomment the following two lines to view the strength buffer directly - // COLOR.rgb = vec3(heatStrength * mask); - // COLOR.a = mask; -}