Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add normal maps #5643

Draft
wants to merge 50 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
69172ac
Yes
notquitehadouken Jan 23, 2025
19fe76c
ok
notquitehadouken Jan 24, 2025
f3874c7
the
notquitehadouken Jan 27, 2025
a6433f4
pain
notquitehadouken Jan 27, 2025
ddde708
ok
notquitehadouken Jan 28, 2025
271badb
Merge branch 'master' of https://github.com/space-wizards/RobustToolb…
notquitehadouken Jan 28, 2025
e5b40d2
funny
notquitehadouken Jan 28, 2025
bafcc9a
Add function normal generation
notquitehadouken Jan 28, 2025
329f3eb
no
notquitehadouken Jan 28, 2025
49b73be
OH MY GOD WHY IS HE BLACK
notquitehadouken Jan 29, 2025
4371fc8
funni
Jan 30, 2025
cb16b06
yeuAUA
Jan 30, 2025
b361b90
no
Jan 30, 2025
d1f4491
Merge branch 'master' of https://github.com/space-wizards/RobustToolb…
Jan 30, 2025
a06e422
ok
Jan 30, 2025
b9b5d79
the
notquitehadouken Jan 30, 2025
dc8e6a4
ok
notquitehadouken Jan 30, 2025
c053bca
make sure
notquitehadouken Jan 30, 2025
3c6dc64
unused
notquitehadouken Jan 30, 2025
7263940
fix offset
notquitehadouken Jan 30, 2025
5e31e1a
remove
notquitehadouken Jan 31, 2025
c038d5a
explain
notquitehadouken Jan 31, 2025
487f341
fuck
notquitehadouken Jan 31, 2025
670d5b9
Tile time
notquitehadouken Jan 31, 2025
b895e0e
Fix weird mask rotation
notquitehadouken Jan 31, 2025
37d5cf4
Fix the horrendous 0.441 problem
Feb 1, 2025
3b51002
glue
Feb 1, 2025
52b9c9c
sussy
Feb 1, 2025
f53350d
toggle
Feb 1, 2025
24ed251
highp
Feb 1, 2025
fb480e6
add toggling
Feb 1, 2025
653eb41
remove stupid headers
Feb 1, 2025
af926d4
you idiot
Feb 1, 2025
c3c011f
p
Feb 2, 2025
ad42758
Get swizzled, idiot.
Feb 2, 2025
2a81568
no
Feb 2, 2025
e5dd9be
FUCK
Feb 2, 2025
05db39e
THIS THE THIRD COMMIT FOR THIS ONE GODDAM FILE HBJHKJBHSJVHBKJSHBPOIU…
Feb 2, 2025
1337b3f
SOmeone goin' die
Feb 2, 2025
91a4df2
no
Feb 2, 2025
9a26bff
Funni
notquitehadouken Feb 3, 2025
09a5f72
Fix sprite rotations
notquitehadouken Feb 3, 2025
5a41c7e
Default fales
notquitehadouken Feb 3, 2025
7ef6074
Reduce yap-fu
notquitehadouken Feb 3, 2025
76e0600
bro
notquitehadouken Feb 3, 2025
9898327
lower precision to readable levels
notquitehadouken Feb 3, 2025
7638708
very very light cleanup
Feb 4, 2025
4e34fe7
Make normals not load when the CVar is disabled
notquitehadouken Feb 4, 2025
42b209c
Support for having flat normals
Feb 5, 2025
15c6bff
.0
notquitehadouken Feb 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Resources/EnginePrototypes/Shaders/stockshaders.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@
id: ColorPicker
kind: source
path: "/Shaders/color_picker.swsl"

- type: shader
id: NormalRotator
kind: source
path: "/Shaders/Internal/normal-rotator.swsl"
5 changes: 5 additions & 0 deletions Resources/Shaders/Internal/color.swsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
uniform highp vec4 InputColor;

void fragment() {
COLOR = InputColor;
}
37 changes: 36 additions & 1 deletion Resources/Shaders/Internal/light_shared.swsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,24 @@ const highp float LIGHTING_HEIGHT = 1.0;

const highp float g_MinVariance = 0.0;

const highp float COLOR_POWER = 0.4586603;

varying highp vec2 worldPosition;

uniform highp vec4 lightColor;
// Position of the light, in world coordinates.
uniform highp vec2 lightCenter;
uniform highp vec2 eyeCenter;
uniform highp vec2 eyeZoom;
uniform highp float lightRange;
uniform highp float lightPower;
uniform highp float lightSoftness;
uniform highp float lightIndex;
uniform highp int useNormals;
uniform highp float globalRotation;
uniform highp float maskRotation;
uniform sampler2D shadowMap;
uniform sampler2D normalMap;

void vertex()
{
Expand All @@ -26,6 +34,11 @@ void vertex()
VERTEX = transformed.xy;
}

highp vec2 rotateVector(highp vec2 vector, highp float theta)
{
return vector * cos(theta) + vector.yx * vec2(-1, 1) * sin(theta);
}

highp float shadowContrib(highp vec2 diff)
{
highp float dist = length(diff);
Expand Down Expand Up @@ -53,6 +66,28 @@ void fragment()
val *= lightPower;
val *= mask;

COLOR = vec4(lightColor.rgb, val * occlusion);
highp float run = 1.0;

if (useNormals == 1)
{
highp vec2 lightDir = rotateVector(normalize(diff), globalRotation);
highp vec2 newUV = rotateVector(UV - vec2(0.5, 0.5) + rotateVector((lightCenter - eyeCenter) / vec2(2, -2) / lightRange, maskRotation), -globalRotation);
newUV *= (projectionMatrix * vec3(1.0, 1.0, 0.0)).xy * vec2(1.0, -1.0) / eyeZoom * lightRange;
newUV += vec2(0.5, 0.5);

highp vec4 origSample = texture2D(normalMap, newUV);
if (origSample.xyzw == vec4(0.0, 0.0, 0.0, 1.0))
discard;

// origSample is on the range 0 - 1 in all components,
// but every color component has been raised to the log_0.5(ln(2)/pi)th power (yes i know) by some unknown mechanism
// so we first raise it to the log_(ln2/pi)(0.5)th power (yes, i know) to reset it
highp vec3 normalSample = pow(origSample.xyz, vec3(COLOR_POWER)) * vec3(2.0, 2.0, 1.0) - vec3(1.0, 1.0, 0.0);
run = dot(normalize(vec3(lightDir, LIGHTING_HEIGHT)), normalSample * vec3(-1.0, -1.0, 1.0));
if (run <= 0.0)
discard;
}

COLOR = vec4(lightColor.xyz, val * occlusion * run);
}

12 changes: 12 additions & 0 deletions Resources/Shaders/Internal/normal-rotator.swsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
uniform highp float rotation;
const highp float COLOR_POWER = 0.4586603;
const highp float COLOR_POWERNT = 2.1802625;

void fragment()
{
highp vec4 Col = zTexture(UV);
Col = vec4(pow(Col.xy, vec2(COLOR_POWER)) - vec2(0.5, 0.5), Col.zw);
Col = vec4(Col.xy * cos(rotation) + vec2(-1.0, 1.0) * Col.yx * sin(rotation), Col.zw);
Col = vec4(pow(Col.xy + vec2(0.5, 0.5), vec2(COLOR_POWERNT)), Col.zw);
COLOR = Col;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Robust.Shared.Animations;
using Robust.Shared.ComponentTrees;
using Robust.Shared.GameObjects;
using Robust.Shared.Graphics;
using Robust.Shared.Graphics.RSI;
using Robust.Shared.IoC;
using Robust.Shared.Log;
Expand Down Expand Up @@ -58,6 +59,8 @@ public sealed partial class SpriteComponent : Component, IComponentDebug, ISeria
[DataField("visible")]
private bool _visible = true;

private const string NormalShaderPrototype = "NormalRotator";

// VV convenience variable to examine layer objects using layer keys
[ViewVariables]
private Dictionary<object, Layer> _mappedLayers => LayerMap.ToDictionary(x => x.Key, x => Layers[x.Value]);
Expand Down Expand Up @@ -786,6 +789,9 @@ public void LayerSetData(int index, PrototypeLayerData layerDatum)
}
}

prototypes.TryIndex<ShaderPrototype>(NormalShaderPrototype, out var normalProto);
layer.NormalShader = normalProto!.Instance();

layer.RenderingStrategy = layerDatum.RenderingStrategy ?? layer.RenderingStrategy;
layer.Cycle = layerDatum.Cycle;

Expand Down Expand Up @@ -1289,7 +1295,7 @@ public bool SnapCardinals
[ViewVariables(VVAccess.ReadWrite)]
public bool NoRotation { get => _screenLock; set => _screenLock = value; }

internal void RenderInternal(DrawingHandleWorld drawingHandle, Angle eyeRotation, Angle worldRotation, Vector2 worldPosition, Direction? overrideDirection)
internal void RenderInternal(DrawingHandleWorld drawingHandle, Angle eyeRotation, Angle worldRotation, Vector2 worldPosition, Direction? overrideDirection, bool normal = false)
{
var angle = worldRotation + eyeRotation; // angle on-screen. Used to decide the direction of 4/8 directional RSIs
angle = angle.Reduced().FlipPositive(); // Reduce the angles to fix math shenanigans
Expand Down Expand Up @@ -1324,16 +1330,16 @@ internal void RenderInternal(DrawingHandleWorld drawingHandle, Angle eyeRotation
switch (layer.RenderingStrategy)
{
case LayerRenderingStrategy.NoRotation:
layer.Render(drawingHandle, ref transformNoRot, angle, overrideDirection);
layer.Render(drawingHandle, ref transformNoRot, angle, overrideDirection, (float)eyeRotation, normal: normal);
break;
case LayerRenderingStrategy.SnapToCardinals:
layer.Render(drawingHandle, ref transformSnap, angle, overrideDirection);
layer.Render(drawingHandle, ref transformSnap, angle, overrideDirection, (float)eyeRotation, normal: normal);
break;
case LayerRenderingStrategy.Default:
layer.Render(drawingHandle, ref transformDefault, angle, overrideDirection);
layer.Render(drawingHandle, ref transformDefault, angle, overrideDirection, (float)eyeRotation, normal: normal);
break;
case LayerRenderingStrategy.UseSpriteStrategy:
layer.Render(drawingHandle, ref transformSprite, angle, overrideDirection);
layer.Render(drawingHandle, ref transformSprite, angle, overrideDirection, (float)eyeRotation, normal: normal);
break;
default:
Logger.Error($"Tried to render a layer with unknown rendering stragegy: {layer.RenderingStrategy}");
Expand All @@ -1346,7 +1352,7 @@ internal void RenderInternal(DrawingHandleWorld drawingHandle, Angle eyeRotation
{
foreach (var layer in Layers)
{
layer.Render(drawingHandle, ref transformSprite, angle, overrideDirection);
layer.Render(drawingHandle, ref transformSprite, angle, overrideDirection, (float)eyeRotation, normal: normal);
}
}
}
Expand Down Expand Up @@ -1492,9 +1498,9 @@ public enum DirectionOffset : byte
public sealed class Layer : ISpriteLayer, ISerializationHooks
{
[ViewVariables] private readonly SpriteComponent _parent;

[ViewVariables] public string? ShaderPrototype;
[ViewVariables] public ShaderInstance? Shader;
/* no vv 4 u */ public ShaderInstance? NormalShader;
[ViewVariables] public Texture? Texture;

private RSI? _rsi;
Expand Down Expand Up @@ -2017,7 +2023,7 @@ public static RsiDirection GetDirection(RsiDirectionType dirType, Angle angle)
/// <summary>
/// Render a layer. This assumes that the input angle is between 0 and 2pi.
/// </summary>
internal void Render(DrawingHandleWorld drawingHandle, ref Matrix3x2 spriteMatrix, Angle angle, Direction? overrideDirection)
internal void Render(DrawingHandleWorld drawingHandle, ref Matrix3x2 spriteMatrix, Angle angle, Direction? overrideDirection, float eyeRotation = 0f, bool normal = false)
{
if (!Visible || Blank)
return;
Expand All @@ -2042,7 +2048,7 @@ internal void Render(DrawingHandleWorld drawingHandle, ref Matrix3x2 spriteMatri
var transformMatrix = Matrix3x2.Multiply(layerMatrix, spriteMatrix);
drawingHandle.SetTransform(in transformMatrix);

RenderTexture(drawingHandle, texture);
RenderTexture(drawingHandle, texture, eyeRotation, normal: normal);
}
else
{
Expand Down Expand Up @@ -2072,18 +2078,24 @@ internal void Render(DrawingHandleWorld drawingHandle, ref Matrix3x2 spriteMatri
}
}

private void RenderTexture(DrawingHandleWorld drawingHandle, Texture texture)
private void RenderTexture(DrawingHandleWorld drawingHandle, Texture texture, float textureRotation = 0f, bool normal = false)
{
if (Shader != null)
if (normal && NormalShader is {} normalShader)
{
NormalShader = normalShader.Mutable ? normalShader : normalShader.Duplicate();
drawingHandle.UseShader(NormalShader);
NormalShader.SetParameter("rotation", textureRotation + (float)drawingHandle.GetTransform().Rotation());
}
else if (Shader != null)
drawingHandle.UseShader(Shader);

var layerColor = _parent.color * Color;
var layerColor = normal ? Color.White : _parent.color * Color;
var textureSize = texture.Size / (float)EyeManager.PixelsPerMeter;
var quad = Box2.FromDimensions(textureSize/-2, textureSize);

drawingHandle.DrawTextureRectRegion(texture, quad, layerColor);
drawingHandle.DrawTextureRectRegion(texture, quad, layerColor, normal: normal);

if (Shader != null)
if (Shader != null || normal)
drawingHandle.UseShader(null);
}

Expand Down
4 changes: 2 additions & 2 deletions Robust.Client/GameObjects/EntitySystems/SpriteSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ public sealed partial class SpriteSystem : EntitySystem

private ISawmill _sawmill = default!;

internal void Render(EntityUid uid, SpriteComponent sprite, DrawingHandleWorld drawingHandle, Angle eyeRotation, in Angle worldRotation, in Vector2 worldPosition)
internal void Render(EntityUid uid, SpriteComponent sprite, DrawingHandleWorld drawingHandle, Angle eyeRotation, in Angle worldRotation, in Vector2 worldPosition, bool normal = false)
{
if (!sprite.IsInert)
_queuedFrameUpdate.Add(uid);

sprite.RenderInternal(drawingHandle, eyeRotation, worldRotation, worldPosition, sprite.EnableDirectionOverride ? sprite.DirectionOverride : null);
sprite.RenderInternal(drawingHandle, eyeRotation, worldRotation, worldPosition, sprite.EnableDirectionOverride ? sprite.DirectionOverride : null, normal: normal);
}

public override void Initialize()
Expand Down
8 changes: 7 additions & 1 deletion Robust.Client/Graphics/AtlasTexture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ namespace Robust.Client.Graphics
[PublicAPI]
public sealed class AtlasTexture : Texture
{
public AtlasTexture(Texture texture, UIBox2 subRegion) : base((Vector2i) subRegion.Size)
public AtlasTexture(Texture texture, UIBox2 subRegion, int? width = null) : base((Vector2i) subRegion.Size)
{
DebugTools.Assert(SubRegion.Right < texture.Width);
DebugTools.Assert(SubRegion.Bottom < texture.Height);
DebugTools.Assert(SubRegion.Left >= 0);
DebugTools.Assert(SubRegion.Top >= 0);

SubRegion = subRegion;
RegionWidth = width ?? (int)subRegion.Width;
SourceTexture = texture;
}

Expand All @@ -33,6 +34,11 @@ public AtlasTexture(Texture texture, UIBox2 subRegion) : base((Vector2i) subRegi
/// </summary>
public UIBox2 SubRegion { get; }

/// <summary>
/// The width of the texture we came from, used for offsetting to get normals
/// </summary>
public int RegionWidth { get; }

public override Color GetPixel(int x, int y)
{
DebugTools.Assert(x < SubRegion.Right);
Expand Down
18 changes: 15 additions & 3 deletions Robust.Client/Graphics/Clyde/Clyde.GridRendering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using OpenToolkit.Graphics.OpenGL4;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.Graphics;
Expand All @@ -27,8 +29,14 @@ internal partial class Clyde

private List<Entity<MapGridComponent>> _grids = new();

private void _drawGrids(Viewport viewport, Box2 worldAABB, Box2Rotated worldBounds, IEye eye)
private void _drawGrids(Viewport viewport, Box2 worldAABB, Box2Rotated worldBounds, IEye eye, bool normal = false)
{
if (normal && (!_lightManager.Enabled
|| !_lightManager.DrawLighting
|| !_cfg.GetCVar(CVars.LightNormals)
|| !_resourceCache.GetNormalsEnabled()))
return;

var mapId = eye.Position.MapId;
if (!_mapManager.MapExists(mapId))
{
Expand All @@ -55,12 +63,16 @@ private void _drawGrids(Viewport viewport, Box2 worldAABB, Box2Rotated worldBoun
{
SetTexture(TextureUnit.Texture0, _tileDefinitionManager.TileTextureAtlas);
SetTexture(TextureUnit.Texture1, _lightingReady ? viewport.LightRenderTarget.Texture : _stockTextureWhite);
gridProgram = ActivateShaderInstance(_defaultShader.Handle).Item1;

gridProgram = ActivateShaderInstance((normal ? _colorShader : _defaultShader).Handle).Item1;
if (normal)
gridProgram.SetUniformMaybe("InputColor", new Color(0.5f, 0.5f, 1f));
SetupGlobalUniformsImmediate(gridProgram, (ClydeTexture) _tileDefinitionManager.TileTextureAtlas);

gridProgram.SetUniformTextureMaybe(UniIMainTexture, TextureUnit.Texture0);
gridProgram.SetUniformTextureMaybe(UniILightTexture, TextureUnit.Texture1);
gridProgram.SetUniform(UniIModUV, new Vector4(0, 0, 1, 1));
if (!normal)
gridProgram.SetUniform(UniIModUV, new Vector4(0, 0, 1, 1));
}

var transform = _entityManager.GetComponent<TransformComponent>(mapGrid);
Expand Down
30 changes: 28 additions & 2 deletions Robust.Client/Graphics/Clyde/Clyde.HLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Robust.Shared.Maths;
using Robust.Shared.Profiling;
using Robust.Shared.Utility;
using Color = Robust.Shared.Maths.Color;

namespace Robust.Client.Graphics.Clyde
{
Expand Down Expand Up @@ -247,8 +248,14 @@ private List<Overlay> GetOverlaysForSpace(OverlaySpace space)
return ScreenBufferTexture;
}

private void DrawEntities(Viewport viewport, Box2Rotated worldBounds, Box2 worldAABB, IEye eye)
private void DrawEntities(Viewport viewport, Box2Rotated worldBounds, Box2 worldAABB, IEye eye, bool normal = false)
{
if (normal && (!_lightManager.Enabled
|| !_lightManager.DrawLighting
|| !_cfg.GetCVar(CVars.LightNormals)
|| !_resourceCache.GetNormalsEnabled()))
return;

var mapId = eye.Position.MapId;
if (mapId == MapId.Nullspace)
return;
Expand Down Expand Up @@ -353,7 +360,13 @@ private void DrawEntities(Viewport viewport, Box2Rotated worldBounds, Box2 world
}
}

spriteSystem.Render(entry.Uid, entry.Sprite, _renderHandle.DrawingHandleWorld, eye.Rotation, in entry.WorldRot, in entry.WorldPos);
spriteSystem.Render(entry.Uid,
entry.Sprite,
_renderHandle.DrawingHandleWorld,
eye.Rotation,
in entry.WorldRot,
in entry.WorldPos,
normal: normal);

if (entry.Sprite.PostShader != null && entityPostRenderTarget != null)
{
Expand Down Expand Up @@ -481,6 +494,19 @@ private void RenderViewport(Viewport viewport)

if (eye.Position.MapId != MapId.Nullspace)
{
// prob not needed
using (DebugGroup("GridNormals"))
using (_prof.Group("GridNormals"))
{
_drawGrids(viewport, worldAABB, worldBounds, eye, normal: true);
}

using (DebugGroup("EntityNormals"))
using (_prof.Group("EntityNormals"))
{
DrawEntities(viewport, worldBounds, worldAABB, eye, normal: true);
}

using (DebugGroup("Lights"))
using (_prof.Group("Lights"))
{
Expand Down
10 changes: 10 additions & 0 deletions Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,8 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w

SetTexture(TextureUnit.Texture1, ShadowTexture);
lightShader.SetUniformTextureMaybe("shadowMap", TextureUnit.Texture1);
SetTexture(TextureUnit.Texture2, viewport.RenderTarget.Texture);
lightShader.SetUniformTextureMaybe("normalMap", TextureUnit.Texture2);

GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One);
CheckGlError();
Expand Down Expand Up @@ -489,6 +491,14 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w
lightShader.SetUniformMaybe("lightIndex",
component.CastShadows ? (i + 0.5f) / ShadowTexture.Height : -1);

lightShader.SetUniformMaybe("globalRotation", (float)eye.Rotation.Theta + (float)rotation.Theta -
(float)_transformSystem.GetWorldRotation(mapUid).Theta);
lightShader.SetUniformMaybe("maskRotation", component.MaskAutoRotate ? (float)rot : 0);

lightShader.SetUniformMaybe("eyeZoom", eye.Zoom / viewport.RenderScale);
lightShader.SetUniformMaybe("eyeCenter", eye.Position.Position + eye.Offset);
lightShader.SetUniformMaybe("useNormals", (_cfg.GetCVar(CVars.LightNormals) && _resourceCache.GetNormalsEnabled()) ? (int)1 : (int)0); // me when shaders do not support boolean values

var offset = new Vector2(component.Radius, component.Radius);

Matrix3x2 matrix;
Expand Down
Loading
Loading