Skip to content

Add CascadeDistance to DirectionalLight component#10464

Closed
zhuberty wants to merge 935 commits intoFacepunch:masterfrom
zhuberty:feature/add-cascade-distance-to-dirlight
Closed

Add CascadeDistance to DirectionalLight component#10464
zhuberty wants to merge 935 commits intoFacepunch:masterfrom
zhuberty:feature/add-cascade-distance-to-dirlight

Conversation

@zhuberty
Copy link
Copy Markdown

Summary

Adds a ShadowCascadeDistance property to the DirectionalLight component, allowing per-light control over the maximum shadow cascade distance. When set to 0 (the default), the light falls back to the global r.shadows.csm.distance ConVar value.

Motivation & Context

Previously, the maximum shadow cascade distance for directional lights was only controllable via the global r.shadows.csm.distance ConVar (defaulting to 15000 units). There was no way to override this on a per-light basis from the editor or in code, making it difficult to tune shadow quality for individual scenes or lights without affecting all directional lights globally.

Fixes:

Implementation Details

  • DirectionalLight.cs — Added a ShadowCascadeDistance float property (grouped under "Shadows", titled "Shadow Distance", range 0–50000) with an [InfoBox] hint. The setter propagates the value to the underlying SceneDirectionalLight scene object immediately if it is valid, following the same pattern used by other properties on this component.
  • SceneDirectionalLight.cs — Added a CascadeDistance float property (default 0f) to the scene-level light object. Includes XML doc comments explaining the override semantics.
  • ShadowMapper.Directional.cs — Updated the farClip calculation to use a pattern match: if the light is a SceneDirectionalLight with a CascadeDistance > 0, that value is used; otherwise the global CascadeDistance ConVar fallback is used. This keeps the override opt-in and non-breaking.

The value 0 is used as a sentinel meaning "use the global setting," which avoids introducing a nullable type and keeps the property simple to use in the editor.

Screenshots / Videos (if applicable)

Recording.2026-04-13.134357.mp4

Checklist

  • Code follows existing style and conventions
  • No unnecessary formatting or unrelated changes
  • Public APIs are documented (if applicable)
  • Unit tests added where applicable and all passing
  • I'm okay with this PR being rejected or requested to change 🙂

aylaylay and others added 30 commits March 6, 2026 08:41
* Can query FileIds, Author

* Store the published file id so we can open an existing workshop item instead of publishing a new one each time, hook up OnComplete action while we're here
* Calculate file sizes and sha256 in parallel, since this is I/O bound

* Batch all files and use a single rclone call
* [MakeDirty] allocates a Action delegate even if it's not used.

* Use field keyword instead of manual backing fields

* Add fast path for render object cloning, avoids expensive round trip through JsonPopulator
Avoids list allocation for GameObjects that have no components
Avoid RenderGroupKey allocations

This would allocate a lot easily 60Mb/s.
Instead of a dedicated struct we now compute a 64bit hash and use that for render grouping.

Remove per frame HashSet, List and LINQ allocations
* More accurate and less allocation heavy version of Task.Delay

- Shoot a single task delay for longer intervals
- Only use expensive polling for the last sub threshold

* Avoid ExecutingJob allocations when not tracking jobs
* Start moving SSR to bindless

* Classify pass stub

* Separable bilateral upscale, 0.3ms > 0.08ms, not happy with it still

* start classify and intersect indirect

* Commandlist support for UAV barriers and clearing a texture and gpubuffer

* Simplify this, move classify to it's own shader

* All indirect

* ResourceState.IndirectArgument missing from ResourceStateToVulkanFlags switch

* Fix indirect, all works

* classify doesnt get skybox

* Add Clear method to CommandList for clearing render target colors

* bilateral upscale indirect too

* Cleanup

* Simplify bilateral upscale, With RADIUS=1, separable saves only 3 taps (6 vs 9), but costs 3 barriers + shared memory + atomics — the synchronization overhead far exceeds 3 extra texture loads of doing it with a normal X Y loop

* Dotnet format, increase roughness threshold (we can afford it 😘 ) and dont need to discard these buffers on disable

* compile shaders

* this shouldnt be a property

* Add FillGPUBuffer method for efficient buffer filling using native GPU commands
…4200)

CollisionEventSystem is quite alloc heavy especially the action wiring causes 10+ heap allocations per collider.
Collect pending acks in List rather than spamming async tasks.
Process List in Tick.
So we don't allocate when a GameObejct doesn't have any tags
Fast & alloc free pass for GameTags.SetFrom
* Remove unnecessary static singletons in MainMenu code

* Empty SceneWorld delete queues during shutdown

* Dresser cancel async load operation on destroy

* Use reflection to null references to static native resources on shutdown

This way we don't  have to remember doing this manually.

* Fix SoundOcclusionSystem using static lists to reference resources

* Sound System: Use weak references to refer to scenes

* Cleanup static logging listeners that kept strong refs to panels

* UISystem Cleanup, make sure all panel/stylesheet refs are released

* RenderTarget and RenderAttributes shutdown cleanup

* Rework AvatarLoader, ThumbLoader & HTTPImageLoader Cache

First try to go through ResourceLibrary.WeakIndex which might already hold the texture.

If there is no hit, go through a second cache that caches HTTP & Steam API response bytes instead of textures.
We want to cache the response bytes rather than the actual Texture, so stuff cached sits in RAM not VRAM.
Before avatars and thumbs would reside in VRAM.

* Fix rendertarget leak in CommandList.Attr.SetValue

GetDepthTarget() / GetColorTarget() return a new strong handle (ref count +1).
We need to DestroyStrongHandle()  that ref. So handles don't leak.

* Call EngineLoop.DrainFrameEndDisposables before shutdown

* NativeResourceCache now report leaks on shutdown

* Override Resource.Destroy for native resources, kill stronghandles

* Deregister SceneWorld from SceneWorld.All during destruction

* Ensure async texture loading cancels on shutdown

* SkinnedModelRender bonemergetarget deregister from target OnDisabled

* Clear shaderMaterials cache during shutdown

* Refactor Shutdown code

Mostly renaming methods from Clear() -> Shutdown()
Adding separate GlobalContext.Shutdown function (more aggressive than GlobalContext.Reset).
Clear some static input state.

* Deregister surfaces from Surface.All in OnDestroy

* RunAllStaticConstructors when loading a mount

* Advanced managed resource leak tracker enabled via `resource_leak_tracking 1`

Works by never pruning the WeakTable in NativeResourceCache.
So we can check for all resources if they are still being held on to and log a callstack.
* Support types like Curve, Gradient, ParticleGradient in movies
* Fix TransformOperation.OnReduce: old implementation was nonsense, could stack overflow
* Add optional filePath parameter to GenerateScreenshotFilename
* Force movie project to save even if we don't think it's changed
* ITemporaryEffect.IsActive pseudo-property for movie recordings
* Add ITrack.GetPathString() extension
* Safety when trying to compress a sample block
* Skip updating playback rate on renderers with a bone merge target
* Move PropertySignal<T>.FromSamples to PropertySignal
* Fix view not always updating when zooming
* Enabled tracks defaults to false when applying
* Movie export: manually call Scene.EditorTick, pause updates elsewhere (fixes Facepunch#10137)
* CanMakeTrackFromProperties: default to only allowing user types
Introduced in Facepunch/sbox#4242 , which added some additional panel cleanup
Ignore static members when serializing or cloning components, makes no sense and breaks cloning with Expression Trees (that was introduced in Facepunch/sbox#4202)

Fixes Facepunch#10161
Synthesizer never disposed its SpeechSynthesizer, causing background VoiceSynthesis threads to accumulate indefinitely (30+ seen in crash dumps).
This may have caused crashes in TTS heavy games like DXRP.

In addition we now properly terminate the SoundStream so SoundHandle.IsPlaying will become false after the stream has been played.

See: Facepunch#4184
solwllms and others added 26 commits April 8, 2026 11:04
…te (Facepunch#4489)

* Raise GameInstance load exceptions in editor instead of silently continuing with a shutdown instance
* Key ResourceLoader watchers on AssemblyQualifiedName instead
* Init AssetTypeAttribute Name from TargetType name if it's null
* Common components

* Replace PackageCard with GameCard in content blocks, wrapped grid layout

* Move GameCard to New/ folder, use ThumbWide for all sizes

* Add `overflow: clip` and `overflow: clip-whole` modes

* New game hub layout, hero

* Layout + hero tweaks

* Hero tweaks

* Clean up content blocks, make it so that game cards don't clip on hover

* Dynamic mask

* Don't bother building CL for panels outside scroll view (400% perf benefit in main game hub)

* Disable 3D bg when not visible (50% performance benefit)

* Cards take their sizes from the image within them

* Stash tweaks before big refactor

* Initial hero carousel

* Better carousel transitions

* Try and reduce allocs inside CL combos

* `background-playback-state` CSS property (`paused` or `running`, applies to video `background-image`)

* Make out-of-focus carousel elements more obvious (no playing video, darkened)

* New branding

* Tweak navbar

* Carousel shows full thumb if not visible, helps with visual noise

* Accurate vote percentage 🙈

* Fix some carousel jankiness

* Navbar feels less disjointed

* Rebake menu lighting & envmaps

* Finalize

https://files.facepunch.com/alexguthrie/1b0311b1/bZKOQIQD0o.jpg

* Trim down visual noise

https://files.facepunch.com/alexguthrie/1b0311b1/oJh4qqaPsC.jpg

* Gradient

https://files.facepunch.com/alexguthrie/1b0511b1/uCyZyolkXE.jpg

* Format

* .heading labels use heading vars

* Carousel slower time between auto switch

* No play button on GameCard

* Content blocks full width

* Adjust GameCard sizes

* Content block header padding

* Add MenuHelpers.PlayGame, GameModal uses it, make hero "Play Now" button use it

---------

Co-authored-by: Matt Stevens <matt@mattstevens.co.uk>
Fix transform update regression from 7b853ce

Rotation.AlmostEqual default threshold was too loose (0.0001 dot-product ~ 1.62° angular tolerance), causing SetLocalTransform to silently drop small transform updates.

- Rotation.AlmostEqual: default delta 0.0001 -> 0.0000001 (~0.05°), use MathF.Abs(Dot) to handle antipodal quaternions (q === -q)
- Transform.AlmostEqual: use Rotation's own default instead of passing the Position/Scale delta to a dot-product metric
Add `DeferGeneration` property to skip navmesh generation during scene load, allowing tiles to be generated and unloaded on demand at runtime.

New public API:
- `NavMesh.DeferGeneration` - skip tile generation on load
- `NavMesh.RequestTileGeneration`/`RequestTilesGeneration` - fire-and-forget via cache loop
- `NavMesh.UnloadTile`/`UnloadTiles` - remove tiles from the navmesh
* preload resolutions on init
Managed will queue deletion no need to check for proper destruction this early
…acepunch#4525)

* WildcardMatch use MatchesSimpleExpression instead of expensive regex

* More WildcardMatch tests
Dot-based AlmostEqual returned false for zero quaternions (default==default would be false), breaking the transform guard that catches uninitialized transforms.
* Don't UpdatePrefabInstances if the edited PrefabScene is the only one open in editor

* Avoid some allocations when processing prefab guid mappings

* Json Diff use 64bit hash isntead of paths for presence tracking, which avoids a ton of string allocations

* Less LINQ in prefab GUID tracking code
@sampavlovic sampavlovic added the triaged triaged pull-requests are replicated on the internal sbox repo label Apr 13, 2026
/// Set to 0 to use the global <c>r.shadows.csm.distance</c> ConVar value (default 15000).
/// </summary>
[Property, Group( "Shadows" ), Title( "Shadow Distance" ), Range( 0, 50000 )]
[InfoBox( "Maximum shadow cascade distance in world units. 0 uses the global quality setting." )]
Copy link
Copy Markdown
Author

@zhuberty zhuberty Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the InfoBox doesn't really need to be here. the on-hover tooltip should be enough.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triaged triaged pull-requests are replicated on the internal sbox repo

Projects

None yet

Development

Successfully merging this pull request may close these issues.