Skip to content

Commit

Permalink
Planet lighting pre-reqs (#5490)
Browse files Browse the repository at this point in the history
* Add another lookup overload

* Fix RenderInRenderTarget

See the linked issue for what happens.

* Also this one

* stuff

* Fix stencilling

* fixes

* mix blend

* fix

* blur fixes

* Tile flag

* Minor tweak

* Fixes

* Render state fixes

* Fixes

* Fix stupidity

* More state render bug fixes

* MapUid on overlay draw

* Remove blur comment

* Fixes

* Fixes

* Remove

* Engine vibe
  • Loading branch information
metalgearsloth authored Feb 16, 2025
1 parent bcb5c2d commit ea1cc5e
Show file tree
Hide file tree
Showing 21 changed files with 381 additions and 120 deletions.
11 changes: 8 additions & 3 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,20 @@ END TEMPLATE-->

### Breaking changes

*None yet*
* The fixes to renderer state may have inadvertantly broken some rendering code that relied upon the old behavior.
* TileRenderFlag has been removed and now it's just a byte flag on the tile for content usage.

### New features

*None yet*
* Add BeforeLighting overlay draw space for overlays that need to draw directly to lighting and want to do it immediately beforehand.
* Change BlurLights to BlurRenderTarget and make it public for content usage.
* Add ContentFlag to tiles for content-flag usage.
* Add a basic mix shader for doing canvas blends.
* Add GetClearColorEvent for content to override the clear color behavior.

### Bugfixes

*None yet*
* Fix pushing renderer state not restoring stencil status, blend status, queued shader instance scissor state.

### Other

Expand Down
6 changes: 6 additions & 0 deletions Resources/EnginePrototypes/Shaders/stockshaders.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
kind: canvas
light_mode: unshaded

# Simple mix blend
- type: shader
id: Mix
kind: canvas
blend_mode: Mix

- type: shader
id: shaded
kind: canvas
Expand Down
27 changes: 22 additions & 5 deletions Robust.Client/Graphics/Clyde/Clyde.HLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ private void RenderSingleWorldOverlay(Overlay overlay, Viewport vp, OverlaySpace
{
DebugTools.Assert(space != OverlaySpace.ScreenSpaceBelowWorld && space != OverlaySpace.ScreenSpace);

var args = new OverlayDrawArgs(space, null, vp, _renderHandle, new UIBox2i((0, 0), vp.Size), vp.Eye!.Position.MapId, worldBox, worldBounds);
var mapId = vp.Eye!.Position.MapId;
var args = new OverlayDrawArgs(space, null, vp, _renderHandle, new UIBox2i((0, 0), vp.Size), _mapManager.GetMapEntityIdOrThrow(mapId), mapId, worldBox, worldBounds);

if (!overlay.BeforeDraw(args))
return;
Expand Down Expand Up @@ -175,8 +176,9 @@ private void RenderOverlaysDirect(

var worldBounds = CalcWorldBounds(vp);
var worldAABB = worldBounds.CalcBoundingBox();
var mapId = vp.Eye!.Position.MapId;

var args = new OverlayDrawArgs(space, vpControl, vp, handle, bounds, vp.Eye!.Position.MapId, worldAABB, worldBounds);
var args = new OverlayDrawArgs(space, vpControl, vp, handle, bounds, _mapManager.GetMapEntityIdOrThrow(mapId), mapId, worldAABB, worldBounds);

foreach (var overlay in list)
{
Expand Down Expand Up @@ -421,12 +423,19 @@ private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color? clearCol

var oldTransform = _currentMatrixModel;
var oldScissor = _currentScissorState;
var oldMatrixProj = _currentMatrixProj;
var oldMatrixView = _currentMatrixView;
var oldBoundTarget = _currentBoundRenderTarget;
var oldRenderTarget = _currentRenderTarget;
var oldShader = _queuedShaderInstance;
var oldCaps = _glCaps;

// Need to get state before flushing render queue in case they modify the original state.
var state = PushRenderStateFull();

// Have to flush the render queue so that all commands finish rendering to the previous framebuffer.
FlushRenderQueue();

var state = PushRenderStateFull();

{
BindRenderTargetFull(RtToLoaded(rt));
if (clearColor is not null)
Expand All @@ -448,8 +457,16 @@ private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color? clearCol
PopRenderStateFull(state);
_updateUniformConstants(_currentRenderTarget.Size);

SetScissorFull(oldScissor);
_currentMatrixModel = oldTransform;

DebugTools.Assert(oldCaps.Equals(_glCaps));
DebugTools.Assert(_currentMatrixModel.Equals(oldTransform));
DebugTools.Assert(_currentScissorState.Equals(oldScissor));
DebugTools.Assert(_currentMatrixProj.Equals(oldMatrixProj));
DebugTools.Assert(oldMatrixView.Equals(_currentMatrixView));
DebugTools.Assert(oldRenderTarget.Equals(_currentRenderTarget));
DebugTools.Assert(oldBoundTarget.Equals(_currentBoundRenderTarget));
DebugTools.Assert(oldShader.Equals(_queuedShaderInstance));
}

private void RenderViewport(Viewport viewport)
Expand Down
123 changes: 71 additions & 52 deletions Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
using System;
using System.Collections.Generic;
using System.Buffers;
using System.Diagnostics.Contracts;
using System.Numerics;
using OpenToolkit.Graphics.OpenGL4;
using Robust.Client.GameObjects;
using Robust.Client.ResourceManagement;
using Robust.Shared;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using OGLTextureWrapMode = OpenToolkit.Graphics.OpenGL.TextureWrapMode;
using TKStencilOp = OpenToolkit.Graphics.OpenGL4.StencilOp;
using Robust.Shared.Physics;
using Robust.Client.ComponentTrees;
using Robust.Shared.Enums;
using Robust.Shared.Graphics;
using static Robust.Shared.GameObjects.OccluderComponent;
using Robust.Shared.Utility;
Expand Down Expand Up @@ -279,8 +277,7 @@ private void PrepareDepthDraw(LoadedRenderTarget target)
{
const float arbitraryDistanceMax = 1234;

GL.Disable(EnableCap.Blend);
CheckGlError();
IsBlending = false;

GL.Enable(EnableCap.DepthTest);
CheckGlError();
Expand Down Expand Up @@ -329,8 +326,7 @@ private void FinalizeDepthDraw()
GL.Disable(EnableCap.DepthTest);
CheckGlError();

GL.Enable(EnableCap.Blend);
CheckGlError();
IsBlending = true;
}

private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 worldAABB, IEye eye)
Expand Down Expand Up @@ -394,21 +390,43 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w
FinalizeDepthDraw();
}

GL.Enable(EnableCap.StencilTest);
_isStencilling = true;
IsStencilling = true;

var (lightW, lightH) = GetLightMapSize(viewport.Size);
GL.Viewport(0, 0, lightW, lightH);
CheckGlError();

BindRenderTargetImmediate(RtToLoaded(viewport.LightRenderTarget));
DebugTools.Assert(_currentBoundRenderTarget.TextureHandle.Equals(viewport.LightRenderTarget.Texture.TextureId));
CheckGlError();
GLClearColor(_entityManager.GetComponentOrNull<MapLightComponent>(mapUid)?.AmbientLightColor ?? MapLightComponent.DefaultColor);

var clearEv = new GetClearColorEvent();
_entityManager.EventBus.RaiseEvent(EventSource.Local, ref clearEv);

var clearColor = clearEv.Color ?? GetClearColor(mapUid);
GLClearColor(clearColor);
GL.ClearStencil(0xFF);
GL.StencilMask(0xFF);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit);
CheckGlError();

var oldTarget = _currentRenderTarget;
var oldProj = _currentMatrixProj;
var oldShader = _queuedShaderInstance;
var oldModel = _currentMatrixModel;
var oldScissor = _currentScissorState;
var state = PushRenderStateFull();

RenderOverlays(viewport, OverlaySpace.BeforeLighting, worldAABB, worldBounds);
PopRenderStateFull(state);

DebugTools.Assert(oldScissor.Equals(_currentScissorState));
DebugTools.Assert(oldModel.Equals(_currentMatrixModel));
DebugTools.Assert(oldShader.Equals(_queuedShaderInstance));
DebugTools.Assert(oldProj.Equals(_currentMatrixProj));
DebugTools.Assert(oldTarget.Equals(_currentRenderTarget));
DebugTools.Assert(_currentBoundRenderTarget.TextureHandle.Equals(viewport.LightRenderTarget.Texture.TextureId));

ApplyLightingFovToBuffer(viewport, eye);

var lightShader = _loadedShaders[_enableSoftShadows ? _lightSoftShaderHandle : _lightHardShaderHandle]
Expand Down Expand Up @@ -509,13 +527,12 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w
}

ResetBlendFunc();
GL.Disable(EnableCap.StencilTest);
_isStencilling = false;
IsStencilling = false;

CheckGlError();

if (_cfg.GetCVar(CVars.LightBlur))
BlurLights(viewport, eye);
BlurRenderTarget(viewport, viewport.LightRenderTarget, viewport.LightBlurTarget, eye, 14f);

using (_prof.Group("BlurOntoWalls"))
{
Expand All @@ -531,9 +548,8 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w
GL.Viewport(0, 0, viewport.Size.X, viewport.Size.Y);
CheckGlError();

Array.Clear(_lightsToRenderList, 0, count);

_lightingReady = true;
Array.Clear(_lightsToRenderList, 0, count);
}

private static bool LightQuery(ref (
Expand Down Expand Up @@ -643,21 +659,33 @@ public int Compare(
return (state.count, expandedBounds);
}

private void BlurLights(Viewport viewport, IEye eye)
/// <inheritdoc/>
[Pure]
public Color GetClearColor(EntityUid mapUid)
{
using var _ = DebugGroup(nameof(BlurLights));
return _entityManager.GetComponentOrNull<MapLightComponent>(mapUid)?.AmbientLightColor ??
MapLightComponent.DefaultColor;
}

GL.Disable(EnableCap.Blend);
CheckGlError();
/// <inheritdoc/>
public void BlurRenderTarget(IClydeViewport viewport, IRenderTarget target, IRenderTarget blurBuffer, IEye eye, float multiplier)
{
if (target is not RenderTexture rTexture || blurBuffer is not RenderTexture blurTexture)
return;

using var _ = DebugGroup(nameof(BlurRenderTarget));

var state = PushRenderStateFull();
IsBlending = false;
CalcScreenMatrices(viewport.Size, out var proj, out var view);
SetProjViewBuffer(proj, view);

var shader = _loadedShaders[_lightBlurShaderHandle].Program;
shader.Use();

SetupGlobalUniformsImmediate(shader, viewport.LightRenderTarget.Texture);
SetupGlobalUniformsImmediate(shader, rTexture.Texture);

var size = viewport.LightRenderTarget.Size;
var size = target.Size;
shader.SetUniformMaybe("size", (Vector2)size);
shader.SetUniformTextureMaybe(UniIMainTexture, TextureUnit.Texture0);

Expand All @@ -667,14 +695,13 @@ private void BlurLights(Viewport viewport, IEye eye)
// Initially we're pulling from the light render target.
// So we set it out of the loop so
// _wallBleedIntermediateRenderTarget2 gets bound at the end of the loop body.
SetTexture(TextureUnit.Texture0, viewport.LightRenderTarget.Texture);
SetTexture(TextureUnit.Texture0, rTexture.Texture);

// Have to scale the blurring radius based on viewport size and camera zoom.
const float refCameraHeight = 14;
var facBase = _cfg.GetCVar(CVars.LightBlurFactor);
var cameraSize = eye.Zoom.Y * viewport.Size.Y * (1 / viewport.RenderScale.Y) / EyeManager.PixelsPerMeter;
// 7e-3f is just a magic factor that makes it look ok.
var factor = facBase * (refCameraHeight / cameraSize);
var factor = facBase * (multiplier / cameraSize);

// Multi-iteration gaussian blur.
for (var i = 3; i > 0; i--)
Expand All @@ -683,35 +710,31 @@ private void BlurLights(Viewport viewport, IEye eye)
// Set factor.
shader.SetUniformMaybe("radius", scale);

BindRenderTargetFull(viewport.LightBlurTarget);
BindRenderTargetImmediate(RtToLoaded(blurBuffer));

// Blur horizontally to _wallBleedIntermediateRenderTarget1.
shader.SetUniformMaybe("direction", Vector2.UnitX);
_drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader);

SetTexture(TextureUnit.Texture0, viewport.LightBlurTarget.Texture);
SetTexture(TextureUnit.Texture0, blurTexture.Texture);

BindRenderTargetFull(viewport.LightRenderTarget);
BindRenderTargetImmediate(RtToLoaded(rTexture));

// Blur vertically to _wallBleedIntermediateRenderTarget2.
shader.SetUniformMaybe("direction", Vector2.UnitY);
_drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader);

SetTexture(TextureUnit.Texture0, viewport.LightRenderTarget.Texture);
SetTexture(TextureUnit.Texture0, rTexture.Texture);
}

GL.Enable(EnableCap.Blend);
CheckGlError();
// We didn't trample over the old _currentMatrices so just roll it back.
SetProjViewBuffer(_currentMatrixProj, _currentMatrixView);
PopRenderStateFull(state);
}

private void BlurOntoWalls(Viewport viewport, IEye eye)
{
using var _ = DebugGroup(nameof(BlurOntoWalls));

GL.Disable(EnableCap.Blend);
CheckGlError();
IsBlending = false;
CalcScreenMatrices(viewport.Size, out var proj, out var view);
SetProjViewBuffer(proj, view);

Expand Down Expand Up @@ -761,8 +784,7 @@ private void BlurOntoWalls(Viewport viewport, IEye eye)
SetTexture(TextureUnit.Texture0, viewport.WallBleedIntermediateRenderTarget2.Texture);
}

GL.Enable(EnableCap.Blend);
CheckGlError();
IsBlending = true;
// We didn't trample over the old _currentMatrices so just roll it back.
SetProjViewBuffer(_currentMatrixProj, _currentMatrixView);
}
Expand All @@ -775,8 +797,7 @@ private void MergeWallLayer(Viewport viewport)

GL.Viewport(0, 0, viewport.LightRenderTarget.Size.X, viewport.LightRenderTarget.Size.Y);
CheckGlError();
GL.Disable(EnableCap.Blend);
CheckGlError();
IsBlending = false;

var shader = _loadedShaders[_mergeWallLayerShaderHandle].Program;
shader.Use();
Expand All @@ -796,8 +817,7 @@ private void MergeWallLayer(Viewport viewport)
IntPtr.Zero);
CheckGlError();

GL.Enable(EnableCap.Blend);
CheckGlError();
IsBlending = true;
}

private void ApplyFovToBuffer(Viewport viewport, IEye eye)
Expand Down Expand Up @@ -827,8 +847,7 @@ private void ApplyFovToBuffer(Viewport viewport, IEye eye)
FovSetTransformAndBlit(viewport, eye.Position.Position, fovShader);

GL.StencilMask(0x00);
GL.Disable(EnableCap.StencilTest);
_isStencilling = false;
IsStencilling = false;
}

private void ApplyLightingFovToBuffer(Viewport viewport, IEye eye)
Expand Down Expand Up @@ -1135,34 +1154,34 @@ private void RegenLightRts(Viewport viewport)

var lightMapSize = GetLightMapSize(viewport.Size);
var lightMapSizeQuart = GetLightMapSize(viewport.Size, true);
var lightMapColorFormat = _hasGLFloatFramebuffers
? RenderTargetColorFormat.R11FG11FB10F
: RenderTargetColorFormat.Rgba8;
var lightMapSampleParameters = new TextureSampleParameters { Filter = true };

viewport.LightRenderTarget?.Dispose();
viewport.WallMaskRenderTarget?.Dispose();
viewport.WallBleedIntermediateRenderTarget1?.Dispose();
viewport.WallBleedIntermediateRenderTarget2?.Dispose();
var lightMapColorFormat = _hasGLFloatFramebuffers
? RenderTargetColorFormat.R11FG11FB10F
: RenderTargetColorFormat.Rgba8;
var lightMapSampleParameters = new TextureSampleParameters { Filter = true };

viewport.WallMaskRenderTarget = CreateRenderTarget(viewport.Size, RenderTargetColorFormat.R8,
name: $"{viewport.Name}-{nameof(viewport.WallMaskRenderTarget)}");

viewport.LightRenderTarget = CreateRenderTarget(lightMapSize,
new RenderTargetFormatParameters(lightMapColorFormat, hasDepthStencil: true),
lightMapSampleParameters,
viewport.LightRenderTarget = (RenderTexture) CreateLightRenderTarget(lightMapSize,
$"{viewport.Name}-{nameof(viewport.LightRenderTarget)}");

viewport.LightBlurTarget = CreateRenderTarget(lightMapSize,
new RenderTargetFormatParameters(lightMapColorFormat),
lightMapSampleParameters,
$"{viewport.Name}-{nameof(viewport.LightBlurTarget)}");

viewport.WallBleedIntermediateRenderTarget1 = CreateRenderTarget(lightMapSizeQuart, lightMapColorFormat,
viewport.WallBleedIntermediateRenderTarget1 = CreateRenderTarget(lightMapSizeQuart,
new RenderTargetFormatParameters(lightMapColorFormat),
lightMapSampleParameters,
$"{viewport.Name}-{nameof(viewport.WallBleedIntermediateRenderTarget1)}");

viewport.WallBleedIntermediateRenderTarget2 = CreateRenderTarget(lightMapSizeQuart, lightMapColorFormat,
viewport.WallBleedIntermediateRenderTarget2 = CreateRenderTarget(lightMapSizeQuart,
new RenderTargetFormatParameters(lightMapColorFormat),
lightMapSampleParameters,
$"{viewport.Name}-{nameof(viewport.WallBleedIntermediateRenderTarget2)}");
}
Expand Down
Loading

0 comments on commit ea1cc5e

Please sign in to comment.