Шейдеры на лампочки (#655)

* +light shader

* fixed

* toggling logic

* nice

* add option to settings

---------

Co-authored-by: CaYpeN1 <artem7771art@gmail.com>
This commit is contained in:
ThereDrD
2024-08-22 05:08:56 +03:00
committed by GitHub
parent d8a616fdea
commit aedaf4fc25
12 changed files with 303 additions and 31 deletions

View File

@@ -41,6 +41,7 @@
<CheckBox Name="FpsCounterCheckBox" Text="{Loc 'ui-options-fps-counter'}" /> <CheckBox Name="FpsCounterCheckBox" Text="{Loc 'ui-options-fps-counter'}" />
<CheckBox Name="LogInChatCheckBox" Text="Логировать действия в чат" /> <CheckBox Name="LogInChatCheckBox" Text="Логировать действия в чат" />
<CheckBox Name="ShowTrailsCheckBox" Text="Отображать трейлы от пуль" /> <CheckBox Name="ShowTrailsCheckBox" Text="Отображать трейлы от пуль" />
<CheckBox Name="EnableLightsGlowingBox" Text="Включить свечение от ламп" />
</BoxContainer> </BoxContainer>
<controls:StripeBack HasBottomEdge="False" HasMargins="False"> <controls:StripeBack HasBottomEdge="False" HasMargins="False">
<Button Name="ApplyButton" <Button Name="ApplyButton"

View File

@@ -73,8 +73,9 @@ namespace Content.Client.Options.UI.Tabs
ViewportLowResCheckBox.OnToggled += OnCheckBoxToggled; ViewportLowResCheckBox.OnToggled += OnCheckBoxToggled;
ParallaxLowQualityCheckBox.OnToggled += OnCheckBoxToggled; ParallaxLowQualityCheckBox.OnToggled += OnCheckBoxToggled;
FpsCounterCheckBox.OnToggled += OnCheckBoxToggled; FpsCounterCheckBox.OnToggled += OnCheckBoxToggled;
LogInChatCheckBox.OnToggled += OnCheckBoxToggled; LogInChatCheckBox.OnToggled += OnCheckBoxToggled; // WD
ShowTrailsCheckBox.OnToggled += OnCheckBoxToggled; ShowTrailsCheckBox.OnToggled += OnCheckBoxToggled; // WD
EnableLightsGlowingBox.OnToggled += OnCheckBoxToggled; // WD
ApplyButton.OnPressed += OnApplyButtonPressed; ApplyButton.OnPressed += OnApplyButtonPressed;
VSyncCheckBox.Pressed = _cfg.GetCVar(CVars.DisplayVSync); VSyncCheckBox.Pressed = _cfg.GetCVar(CVars.DisplayVSync);
FullscreenCheckBox.Pressed = ConfigIsFullscreen; FullscreenCheckBox.Pressed = ConfigIsFullscreen;
@@ -86,8 +87,9 @@ namespace Content.Client.Options.UI.Tabs
ViewportLowResCheckBox.Pressed = !_cfg.GetCVar(CCVars.ViewportScaleRender); ViewportLowResCheckBox.Pressed = !_cfg.GetCVar(CCVars.ViewportScaleRender);
ParallaxLowQualityCheckBox.Pressed = _cfg.GetCVar(CCVars.ParallaxLowQuality); ParallaxLowQualityCheckBox.Pressed = _cfg.GetCVar(CCVars.ParallaxLowQuality);
FpsCounterCheckBox.Pressed = _cfg.GetCVar(CCVars.HudFpsCounterVisible); FpsCounterCheckBox.Pressed = _cfg.GetCVar(CCVars.HudFpsCounterVisible);
LogInChatCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.LogChatActions); LogInChatCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.LogChatActions); // WD
ShowTrailsCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.ShowTrails); ShowTrailsCheckBox.Pressed = _cfg.GetCVar(WhiteCVars.ShowTrails); // WD
EnableLightsGlowingBox.Pressed = _cfg.GetCVar(WhiteCVars.EnableLightsGlowing); // WD
ViewportWidthSlider.Value = _cfg.GetCVar(CCVars.ViewportWidth); ViewportWidthSlider.Value = _cfg.GetCVar(CCVars.ViewportWidth);
_cfg.OnValueChanged(CCVars.ViewportMinimumWidth, _ => UpdateViewportWidthRange()); _cfg.OnValueChanged(CCVars.ViewportMinimumWidth, _ => UpdateViewportWidthRange());
@@ -120,8 +122,9 @@ namespace Content.Client.Options.UI.Tabs
_cfg.SetCVar(CCVars.ViewportScaleRender, !ViewportLowResCheckBox.Pressed); _cfg.SetCVar(CCVars.ViewportScaleRender, !ViewportLowResCheckBox.Pressed);
_cfg.SetCVar(CCVars.ParallaxLowQuality, ParallaxLowQualityCheckBox.Pressed); _cfg.SetCVar(CCVars.ParallaxLowQuality, ParallaxLowQualityCheckBox.Pressed);
_cfg.SetCVar(CCVars.HudFpsCounterVisible, FpsCounterCheckBox.Pressed); _cfg.SetCVar(CCVars.HudFpsCounterVisible, FpsCounterCheckBox.Pressed);
_cfg.SetCVar(WhiteCVars.LogChatActions, LogInChatCheckBox.Pressed); _cfg.SetCVar(WhiteCVars.LogChatActions, LogInChatCheckBox.Pressed); // WD
_cfg.SetCVar(WhiteCVars.ShowTrails, ShowTrailsCheckBox.Pressed); _cfg.SetCVar(WhiteCVars.ShowTrails, ShowTrailsCheckBox.Pressed); // WD
_cfg.SetCVar(WhiteCVars.EnableLightsGlowing, EnableLightsGlowingBox.Pressed); // WD
_cfg.SetCVar(CCVars.ViewportWidth, (int) ViewportWidthSlider.Value); _cfg.SetCVar(CCVars.ViewportWidth, (int) ViewportWidthSlider.Value);
_cfg.SaveToFile(); _cfg.SaveToFile();
@@ -151,8 +154,9 @@ namespace Content.Client.Options.UI.Tabs
var isVPResSame = ViewportLowResCheckBox.Pressed == !_cfg.GetCVar(CCVars.ViewportScaleRender); var isVPResSame = ViewportLowResCheckBox.Pressed == !_cfg.GetCVar(CCVars.ViewportScaleRender);
var isPLQSame = ParallaxLowQualityCheckBox.Pressed == _cfg.GetCVar(CCVars.ParallaxLowQuality); var isPLQSame = ParallaxLowQualityCheckBox.Pressed == _cfg.GetCVar(CCVars.ParallaxLowQuality);
var isFpsCounterVisibleSame = FpsCounterCheckBox.Pressed == _cfg.GetCVar(CCVars.HudFpsCounterVisible); var isFpsCounterVisibleSame = FpsCounterCheckBox.Pressed == _cfg.GetCVar(CCVars.HudFpsCounterVisible);
var isLogInChatSame = LogInChatCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.LogChatActions); var isLogInChatSame = LogInChatCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.LogChatActions); // WD
var isShowTrailsSame = ShowTrailsCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.ShowTrails); var isShowTrailsSame = ShowTrailsCheckBox.Pressed == _cfg.GetCVar(WhiteCVars.ShowTrails); // WD
var isEnableLightsGlowing = EnableLightsGlowingBox.Pressed == _cfg.GetCVar(WhiteCVars.EnableLightsGlowing); // WD
var isWidthSame = (int) ViewportWidthSlider.Value == _cfg.GetCVar(CCVars.ViewportWidth); var isWidthSame = (int) ViewportWidthSlider.Value == _cfg.GetCVar(CCVars.ViewportWidth);
ApplyButton.Disabled = isVSyncSame && ApplyButton.Disabled = isVSyncSame &&
@@ -167,7 +171,8 @@ namespace Content.Client.Options.UI.Tabs
isFpsCounterVisibleSame && isFpsCounterVisibleSame &&
isWidthSame && isWidthSame &&
isLogInChatSame && isLogInChatSame &&
isShowTrailsSame; isShowTrailsSame &&
isEnableLightsGlowing;
} }
private bool ConfigIsFullscreen => private bool ConfigIsFullscreen =>

View File

@@ -0,0 +1,95 @@
using System.Numerics;
using Content.Shared._White;
using Content.Shared._White.Lighting.Shaders;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
namespace Content.Client._White.Lighting.Shaders;
public sealed class LightingOverlay : Overlay
{
private readonly IPrototypeManager _prototypeManager;
private readonly EntityManager _entityManager;
private readonly SpriteSystem _spriteSystem;
private readonly TransformSystem _transformSystem;
private readonly IConfigurationManager _cfg;
public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities;
public override bool RequestScreenTexture => true;
private readonly ShaderInstance _shader;
private bool _enableGlowing;
public LightingOverlay(EntityManager entityManager, IPrototypeManager prototypeManager)
{
_entityManager = entityManager;
_spriteSystem = entityManager.EntitySysManager.GetEntitySystem<SpriteSystem>();
_prototypeManager = prototypeManager;
_transformSystem = entityManager.EntitySysManager.GetEntitySystem<TransformSystem>();
_cfg = IoCManager.Resolve<IConfigurationManager>();
_cfg.OnValueChanged(WhiteCVars.EnableLightsGlowing, val => _enableGlowing = val, true);
IoCManager.InjectDependencies(this);
_shader = _prototypeManager.Index<ShaderPrototype>("LightingOverlay").InstanceUnique();
ZIndex = (int) DrawDepth.Overdoors;
}
protected override void Draw(in OverlayDrawArgs args)
{
if (!_enableGlowing)
return;
if (ScreenTexture == null)
return;
var xformCompQuery = _entityManager.GetEntityQuery<TransformComponent>();
var handle = args.WorldHandle;
var bounds = args.WorldAABB.Enlarged(5f);
_shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
var query = _entityManager.AllEntityQueryEnumerator<LightingOverlayComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var component, out var xform))
{
if (xform.MapID != args.MapId)
continue;
if (!component.Enabled)
continue;
var worldPos = _transformSystem.GetWorldPosition(xform, xformCompQuery);
if (!bounds.Contains(worldPos))
continue;
var color = component.Color;
if (color == null && _entityManager.TryGetComponent<PointLightComponent>(uid, out var pointLight))
color = pointLight.Color;
var (_, _, worldMatrix) = xform.GetWorldPositionRotationMatrix(xformCompQuery);
handle.SetTransform(worldMatrix);
var mask = _spriteSystem.Frame0(component.Sprite); // mask
var xOffset = component.Offsetx - (mask.Width / 2) / EyeManager.PixelsPerMeter;
var yOffset = component.Offsety - (mask.Height / 2) / EyeManager.PixelsPerMeter;
var textureVector = new Vector2(xOffset, yOffset);
handle.DrawTexture(mask, textureVector, color);
handle.UseShader(_shader);
}
handle.UseShader(null);
handle.SetTransform(Matrix3.Identity);
}
}

View File

@@ -0,0 +1,25 @@
using Robust.Client.Graphics;
using Robust.Shared.Prototypes;
namespace Content.Client._White.Lighting.Shaders;
public sealed class LightingOverlaySystem : EntitySystem
{
[Dependency] private readonly IOverlayManager _overlayManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private LightingOverlay _lightingOverlay = default!;
public override void Initialize()
{
base.Initialize();
_lightingOverlay = new LightingOverlay(EntityManager, _prototypeManager);
_overlayManager.AddOverlay(_lightingOverlay);
}
public override void Shutdown()
{
base.Shutdown();
_overlayManager.RemoveOverlay(_lightingOverlay);
}
}

View File

@@ -0,0 +1,21 @@
using Content.Shared._White.Lighting.Shaders;
using Content.Shared.Power;
using Robust.Client.GameObjects;
namespace Content.Client._White.Lighting.Shaders;
public sealed class TogglingLightOverlaySystem : EntitySystem
{
public override void Initialize()
{
SubscribeLocalEvent<LightingOverlayComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnAppearanceChange(EntityUid uid, LightingOverlayComponent component, AppearanceChangeEvent args)
{
if (!args.AppearanceData.TryGetValue(PowerDeviceVisuals.Powered, out var state))
return;
component.Enabled = (bool) state;
}
}

View File

@@ -93,14 +93,14 @@ namespace Content.Shared.DrawDepth
/// <summary> /// <summary>
/// Explosions, fire, melee swings. Whatever. /// Explosions, fire, melee swings. Whatever.
/// </summary> /// </summary>
Effects = DrawDepthTag.Default + 9, Effects = DrawDepthTag.Default + 10,
Ghosts = DrawDepthTag.Default + 10, Ghosts = DrawDepthTag.Default + 11,
/// <summary> /// <summary>
/// Use this selectively if it absolutely needs to be drawn above (almost) everything else. Examples include /// Use this selectively if it absolutely needs to be drawn above (almost) everything else. Examples include
/// the pointing arrow, the drag & drop ghost-entity, and some debug tools. /// the pointing arrow, the drag & drop ghost-entity, and some debug tools.
/// </summary> /// </summary>
Overlays = DrawDepthTag.Default + 11, Overlays = DrawDepthTag.Default + 12,
} }
} }

View File

@@ -0,0 +1,27 @@
using Robust.Shared.GameStates;
using Robust.Shared.Utility;
using static Robust.Shared.Utility.SpriteSpecifier;
namespace Content.Shared._White.Lighting.Shaders;
/// <summary>
/// This is used for LightOverlay
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class LightingOverlayComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public bool Enabled = true;
[DataField]
public SpriteSpecifier Sprite = new Texture(new ResPath("Effects/LightMasks/lightmask_lamp.png"));
[DataField]
public float Offsetx = -0.5f;
[DataField]
public float Offsety = 0.5f;
[DataField]
public Color? Color;
}

View File

@@ -20,6 +20,13 @@ public sealed class WhiteCVars
CVarDef.Create("white.show_trails", true, CVar.CLIENTONLY | CVar.ARCHIVE); CVarDef.Create("white.show_trails", true, CVar.CLIENTONLY | CVar.ARCHIVE);
/* /*
* Bullet trails
*/
public static readonly CVarDef<bool> EnableLightsGlowing =
CVarDef.Create("white.enable_lights_glowing", true, CVar.CLIENTONLY | CVar.ARCHIVE);
/*
* Offer Indicator * Offer Indicator
*/ */

View File

@@ -33,8 +33,8 @@
state: base state: base
- type: PointLight - type: PointLight
color: "#FFE4CE" # 5000K color temp color: "#FFE4CE" # 5000K color temp
energy: 0.8 energy: 0.65
radius: 10 radius: 6
softness: 1 softness: 1
offset: "0, -0.5" offset: "0, -0.5"
- type: Damageable - type: Damageable
@@ -70,6 +70,7 @@
- !type:PlaySoundBehavior - !type:PlaySoundBehavior
sound: sound:
collection: GlassBreak collection: GlassBreak
- type: LightingOverlay # WD
- type: LightMark - type: LightMark
placement: placement:
mode: SnapgridCenter mode: SnapgridCenter
@@ -154,9 +155,9 @@
types: types:
Heat: 5 Heat: 5
- type: PointLight - type: PointLight
radius: 15 radius: 10
energy: 1 energy: 0.7
softness: 0.9 softness: 1
color: "#EEEEFF" color: "#EEEEFF"
- type: entity - type: entity
@@ -166,8 +167,8 @@
components: components:
- type: PointLight - type: PointLight
radius: 10 radius: 10
energy: 2.5 energy: 0.7
softness: 0.9 softness: 1
color: "#EEEEFF" color: "#EEEEFF"
#Exterior lights #Exterior lights
@@ -189,9 +190,9 @@
suffix: Always Powered, Blue suffix: Always Powered, Blue
components: components:
- type: PointLight - type: PointLight
radius: 12 radius: 10
energy: 4.5 energy: 0.7
softness: 0.5 softness: 1
color: "#B4FCF0" color: "#B4FCF0"
#Sodium lights #Sodium lights
@@ -208,8 +209,8 @@
Heat: 5 Heat: 5
- type: PointLight - type: PointLight
radius: 10 radius: 10
energy: 2.5 energy: 0.7
softness: 0.9 softness: 1
color: "#FFAF38" color: "#FFAF38"
- type: entity - type: entity
@@ -219,8 +220,8 @@
components: components:
- type: PointLight - type: PointLight
radius: 10 radius: 10
energy: 4 energy: 0.7
softness: 0.5 softness: 1
color: "#FFAF38" color: "#FFAF38"
#Small lights #Small lights
@@ -240,9 +241,9 @@
sprite: Structures/Wallmounts/Lighting/light_small.rsi sprite: Structures/Wallmounts/Lighting/light_small.rsi
state: base state: base
- type: PointLight - type: PointLight
energy: 1.0 radius: 4
radius: 6 energy: 0.7
softness: 1.1 softness: 1
enabled: true enabled: true
- type: Damageable - type: Damageable
damageContainer: StructuralInorganic damageContainer: StructuralInorganic
@@ -324,7 +325,7 @@
- type: PointLight - type: PointLight
enabled: true enabled: true
radius: 8 radius: 8
energy: 1 energy: 0.7
softness: 1 softness: 1
color: "#EEEEFF" color: "#EEEEFF"
- type: PoweredLight - type: PoweredLight

View File

@@ -2,3 +2,8 @@
id: ShockWave id: ShockWave
kind: source kind: source
path: "/Textures/White/Shaders/shock_wave.swsl" path: "/Textures/White/Shaders/shock_wave.swsl"
- type: shader
id: LightingOverlay
kind: source
path: "/Textures/White/Shaders/light.swsl"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,85 @@
uniform sampler2D SCREEN_TEXTURE;
const highp float[3] weights = float[](0.2, 0.0625, 0.0375);
// Function to adjust alpha
highp float adjustAlpha(highp vec4 background) {
highp float avgColor = dot(background.rgb, vec3(0.3333));
highp float boost = (1.0 - (1.0 - avgColor) / 1.25);
highp float transition = clamp((avgColor - 0.035) / 0.125, 0.0, 2.0);
return boost * (1.0 - transition) + transition;
}
// Function to warm up the color
highp vec3 warmColor(highp vec3 color) {
highp vec3 warmTint = vec3(1.0, 0.8, 0.6);
return color * warmTint;
}
// Function to adjust saturation
highp vec3 adjustSaturation(highp vec3 color, highp float saturation) {
highp float luminance = dot(color, vec3(0.299, 0.587, 0.114));
return mix(vec3(luminance), color, saturation);
}
// Function to add haze effect
highp vec4 addHaze(highp vec4 color, highp float intensity) {
highp vec3 haze = vec3(0.9, 0.85, 0.8);
return vec4(mix(color.rgb, haze, intensity), color.a);
}
// Function to perform enhanced blur calculation
highp vec4 enhancedBlur(highp vec2 offset, highp vec2 uv, highp vec2 frag, lowp int step) {
highp vec4 bsample = texture2D(TEXTURE, uv + offset * TEXTURE_PIXEL_SIZE) * weights[step];
bsample.rgb = warmColor(bsample.rgb);
bsample.rgb = adjustSaturation(bsample.rgb, 1.2);
bsample = addHaze(bsample, 0.1);
bsample.a *= adjustAlpha(zTextureSpec(SCREEN_TEXTURE, (frag + offset) * SCREEN_PIXEL_SIZE));
return bsample;
}
// Function to calculate offset based on index
highp vec2 calculateOffset(highp int index, highp float step) {
highp vec3 offsetBase = vec3(1.0, 0.0, -1.0);
highp vec2 offsets[8];
offsets[0] = offsetBase.xy;
offsets[1] = -offsetBase.xy;
offsets[2] = offsetBase.yx;
offsets[3] = -offsetBase.yx;
offsets[4] = offsetBase.xx;
offsets[5] = offsetBase.xz;
offsets[6] = offsetBase.zx;
offsets[7] = offsetBase.zz;
return offsets[index % 8] * step;
}
void fragment() {
highp vec4 sprite = zTexture(UV);
if (sprite.a == 0.0) {
discard;
}
highp vec3 offsetBase = vec3(1.0, 0.0, -1.0);
highp vec4 sum = enhancedBlur(vec2(0), UV.xy, FRAGCOORD.xy, 0);
highp vec4 bsample;
highp float floatstep = 0.0;
for (lowp int i = 0; i < 2; i++) {
floatstep += 1.0;
for (lowp int j = 0; j < 8; j++) {
highp vec2 offset = calculateOffset(j, floatstep);
bsample = enhancedBlur(offset, UV.xy, FRAGCOORD.xy, i + 1);
sum += bsample;
}
}
sum.rgb = warmColor(sum.rgb);
sum.rgb = adjustSaturation(sum.rgb, 1.1);
sum = addHaze(sum, 0.05);
COLOR = sum;
}