Editor utility class that tracks and resolves a freecam and scene capture context for the SuperShot editor. It stores current freecam transform, FOV and clip planes, remembers the last valid camera state, resolves effective capture source and target resolution sizes.
using System;
using Sandbox;
namespace Editor.SuperShot;
public static class SuperShotContext
{
public static Transform FreecamTransform { get; private set; }
public static float FreecamFov { get; private set; } = 70f;
public static float FreecamZNear { get; private set; } = 1f;
public static float FreecamZFar { get; private set; } = 100000f;
static RealTimeSince _sinceFreecamUpdate = 1000f;
// Last resolved freecam, so a capture taken while the scene view isn't "current" still mirrors it.
static Transform _lastGoodTransform;
static float _lastGoodFov;
static float _lastGoodZNear = 1f;
static float _lastGoodZFar = 100000f;
static bool _hasLastGood;
public static bool HasFreecam => _sinceFreecamUpdate < 0.5f;
public static void UpdateFreecam( Transform transform, float fov, float zNear, float zFar )
{
FreecamTransform = transform;
FreecamFov = fov;
FreecamZNear = MathX.Clamp( zNear, 1f, 1000f );
FreecamZFar = zFar;
_sinceFreecamUpdate = 0f;
Remember( transform, FreecamFov, FreecamZNear, FreecamZFar );
}
static void Remember( Transform transform, float fov, float zNear, float zFar )
{
_lastGoodTransform = transform;
_lastGoodFov = fov;
_lastGoodZNear = zNear;
_lastGoodZFar = zFar;
_hasLastGood = true;
}
public static bool TryResolveFreecam( out Transform transform, out float fov, out float zNear, out float zFar )
{
var viewport = SceneViewWidget.Current?.LastSelectedViewportWidget;
if ( viewport?.State is not null )
{
transform = new Transform( viewport.State.CameraPosition, viewport.State.CameraRotation );
fov = EditorPreferences.CameraFieldOfView;
zNear = MathX.Clamp( EditorPreferences.CameraZNear, 1f, 1000f );
zFar = EditorPreferences.CameraZFar;
Remember( transform, fov, zNear, zFar );
return true;
}
if ( HasFreecam )
{
transform = FreecamTransform;
fov = FreecamFov;
zNear = FreecamZNear;
zFar = FreecamZFar;
Remember( transform, fov, zNear, zFar );
return true;
}
if ( _hasLastGood )
{
transform = _lastGoodTransform;
fov = _lastGoodFov;
zNear = _lastGoodZNear;
zFar = _lastGoodZFar;
return true;
}
transform = default;
fov = FreecamFov;
zNear = FreecamZNear;
zFar = FreecamZFar;
return false;
}
public static Scene ActiveScene => SceneEditorSession.Active?.Scene;
// True while playing and still following the game camera (not ejected to the free-fly editor camera).
public static bool IsAttachedGameView
=> SceneViewWidget.Current?.CurrentView == SceneViewWidget.ViewMode.Game;
// Attached-play uses the live game camera the player sees; ejected/not-playing honours Shot Preferences.
public static CaptureSource EffectiveSource( CaptureSettings settings )
=> IsAttachedGameView ? CaptureSource.SceneMainCamera : settings.Source;
public static float DesiredAspect { get; set; } = 16f / 9f;
public static (int width, int height) ResolveSize( CaptureSettings s )
{
return s.Resolution switch
{
ShotResolution.OneK => (1024, 576),
ShotResolution.HD720 => (1280, 720),
ShotResolution.HD1080 => (1920, 1080),
ShotResolution.QHD1440 => (2560, 1440),
ShotResolution.UHD4K => (3840, 2160),
ShotResolution.UHD5K => (5120, 2880),
ShotResolution.UHD8K => (7680, 4320),
ShotResolution.Square1080 => (1080, 1080),
ShotResolution.Square4K => (3840, 3840),
ShotResolution.Portrait => (1080, 1920),
ShotResolution.Ultrawide1440 => (3440, 1440),
ShotResolution.Ultrawide1080 => (2560, 1080),
ShotResolution.Cinematic => (3840, 1646),
ShotResolution.YouTubeThumbnail => (1280, 720),
ShotResolution.PackageSquare => (512, 512),
ShotResolution.PackageWide => (910, 512),
ShotResolution.PackageTall => (512, 910),
ShotResolution.Custom => (Math.Max( 64, s.CustomWidth ), Math.Max( 64, s.CustomHeight )),
_ => (1920, 1080)
};
}
}