From 00aa54cde82da867b2a861cd1b6bf307dafc0a7f Mon Sep 17 00:00:00 2001 From: Christopher Rothert Date: Sat, 7 Oct 2023 02:40:52 +0200 Subject: [PATCH] Update camera speed stepping and easing * remove complex curve function * update camera easing feature to use Mathf.Pow instead * add total camera speed steps to ViewportOptions * change default value for max camera speed from 64 to 32 * update ViewportOptions ordering and grouping * update string format for movement speed --- Source/Editor/Options/ViewportOptions.cs | 77 +++++++++++--------- Source/Editor/Viewport/EditorViewport.cs | 93 ++++++++---------------- 2 files changed, 72 insertions(+), 98 deletions(-) diff --git a/Source/Editor/Options/ViewportOptions.cs b/Source/Editor/Options/ViewportOptions.cs index c934fc348..0fd018cbc 100644 --- a/Source/Editor/Options/ViewportOptions.cs +++ b/Source/Editor/Options/ViewportOptions.cs @@ -26,101 +26,108 @@ namespace FlaxEditor.Options public float MouseWheelSensitivity { get; set; } = 1.0f; /// - /// Gets or sets the default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values). + /// Gets or sets the total amount of steps the camera needs to go from minimum to maximum speed. /// - [DefaultValue(1.0f), Limit(0.05f, 64.0f)] - [EditorDisplay("Defaults"), EditorOrder(110), Tooltip("The default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values).")] - public float MovementSpeed { get; set; } = 1.0f; - - /// - /// Gets or sets the default minimum camera movement speed. - /// - [DefaultValue(0.05f), Limit(0.05f, 64.0f)] - [EditorDisplay("Defaults"), EditorOrder(111), Tooltip("The default minimum movement speed for the viewport camera.")] - public float MinMovementSpeed { get; set; } = 0.05f; - - /// - /// Gets or sets the default maximum camera movement speed. - /// - [DefaultValue(64.0f), Limit(32.0f, 1000.0f)] - [EditorDisplay("Defaults"), EditorOrder(112), Tooltip("The default maximum movement speed for the viewport camera.")] - public float MaxMovementSpeed { get; set; } = 64f; - - /// - /// Gets or sets the default camera easing mode. - /// - [DefaultValue(true)] - [EditorDisplay("Defaults"), EditorOrder(120), Tooltip("The default camera easing mode.")] - public bool UseCameraEasing { get; set; } = true; + [DefaultValue(64), Limit(1, 128)] + [EditorDisplay("Camera"), EditorOrder(110), Tooltip("The total amount of steps the camera needs to go from minimum to maximum speed.")] + public int TotalCameraSpeedSteps { get; set; } = 64; /// /// Gets or sets the degree to which the camera will be eased when using camera flight in the editor window. /// [DefaultValue(3.0f), Limit(1.0f, 8.0f)] - [EditorDisplay("Defaults"), EditorOrder(121), Tooltip("The default degree to which the camera will be eased when using camera flight in the editor window (ignored if camera easing degree is enabled).")] + [EditorDisplay("Camera"), EditorOrder(111), Tooltip("The degree to which the camera will be eased when using camera flight in the editor window (ignored if camera easing degree is enabled).")] public float CameraEasingDegree { get; set; } = 3.0f; + /// + /// Gets or sets the default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values). + /// + [DefaultValue(1.0f), Limit(0.05f, 32.0f)] + [EditorDisplay("Defaults"), EditorOrder(120), Tooltip("The default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values).")] + public float MovementSpeed { get; set; } = 1.0f; + + /// + /// Gets or sets the default minimum camera movement speed. + /// + [DefaultValue(0.05f), Limit(0.05f, 32.0f)] + [EditorDisplay("Defaults"), EditorOrder(121), Tooltip("The default minimum movement speed for the viewport camera.")] + public float MinMovementSpeed { get; set; } = 0.05f; + + /// + /// Gets or sets the default maximum camera movement speed. + /// + [DefaultValue(32.0f), Limit(16.0f, 1000.0f)] + [EditorDisplay("Defaults"), EditorOrder(122), Tooltip("The default maximum movement speed for the viewport camera.")] + public float MaxMovementSpeed { get; set; } = 32f; + + /// + /// Gets or sets the default camera easing mode. + /// + [DefaultValue(true)] + [EditorDisplay("Defaults"), EditorOrder(130), Tooltip("The default camera easing mode.")] + public bool UseCameraEasing { get; set; } = true; + /// /// Gets or sets the default near clipping plane distance for the viewport camera. /// [DefaultValue(10.0f), Limit(0.001f, 1000.0f)] - [EditorDisplay("Defaults"), EditorOrder(130), Tooltip("The default near clipping plane distance for the viewport camera.")] + [EditorDisplay("Defaults"), EditorOrder(140), Tooltip("The default near clipping plane distance for the viewport camera.")] public float NearPlane { get; set; } = 10.0f; /// /// Gets or sets the default far clipping plane distance for the viewport camera. /// [DefaultValue(40000.0f), Limit(10.0f)] - [EditorDisplay("Defaults"), EditorOrder(140), Tooltip("The default far clipping plane distance for the viewport camera.")] + [EditorDisplay("Defaults"), EditorOrder(150), Tooltip("The default far clipping plane distance for the viewport camera.")] public float FarPlane { get; set; } = 40000.0f; /// /// Gets or sets the default field of view angle (in degrees) for the viewport camera. /// [DefaultValue(60.0f), Limit(35.0f, 160.0f, 0.1f)] - [EditorDisplay("Defaults"), EditorOrder(150), Tooltip("The default field of view angle (in degrees) for the viewport camera.")] + [EditorDisplay("Defaults"), EditorOrder(160), Tooltip("The default field of view angle (in degrees) for the viewport camera.")] public float FieldOfView { get; set; } = 60.0f; /// /// Gets or sets the default camera orthographic mode. /// [DefaultValue(false)] - [EditorDisplay("Defaults"), EditorOrder(160), Tooltip("The default camera orthographic mode.")] + [EditorDisplay("Defaults"), EditorOrder(170), Tooltip("The default camera orthographic mode.")] public bool UseOrthographicProjection { get; set; } = false; /// /// Gets or sets the default camera orthographic scale (if camera uses orthographic mode). /// [DefaultValue(5.0f), Limit(0.001f, 100000.0f, 0.1f)] - [EditorDisplay("Defaults"), EditorOrder(170), Tooltip("The default camera orthographic scale (if camera uses orthographic mode).")] + [EditorDisplay("Defaults"), EditorOrder(180), Tooltip("The default camera orthographic scale (if camera uses orthographic mode).")] public float OrthographicScale { get; set; } = 5.0f; /// /// Gets or sets the default panning direction for the viewport camera. /// [DefaultValue(false)] - [EditorDisplay("Defaults"), EditorOrder(180), Tooltip("The default panning direction for the viewport camera.")] + [EditorDisplay("Defaults"), EditorOrder(190), Tooltip("The default panning direction for the viewport camera.")] public bool InvertPanning { get; set; } = false; /// /// Gets or sets the default relative panning mode. /// [DefaultValue(true)] - [EditorDisplay("Defaults"), EditorOrder(190), Tooltip("The default relative panning mode. Uses distance between camera and target to determine panning speed.")] + [EditorDisplay("Defaults"), EditorOrder(200), Tooltip("The default relative panning mode. Uses distance between camera and target to determine panning speed.")] public bool UseRelativePanning { get; set; } = true; /// /// Gets or sets the default panning speed (ignored if relative panning is speed enabled). /// [DefaultValue(0.8f), Limit(0.01f, 128.0f, 0.1f)] - [EditorDisplay("Defaults"), EditorOrder(200), Tooltip("The default camera panning speed (ignored if relative panning is enabled).")] + [EditorDisplay("Defaults"), EditorOrder(210), Tooltip("The default camera panning speed (ignored if relative panning is enabled).")] public float PanningSpeed { get; set; } = 0.8f; /// /// Gets or sets the default editor viewport grid scale. /// [DefaultValue(50.0f), Limit(25.0f, 500.0f, 5.0f)] - [EditorDisplay("Defaults"), EditorOrder(210), Tooltip("The default editor viewport grid scale.")] + [EditorDisplay("Defaults"), EditorOrder(220), Tooltip("The default editor viewport grid scale.")] public float ViewportGridScale { get; set; } = 50.0f; } } diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index 399a71418..ba4087025 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -178,7 +178,6 @@ namespace FlaxEditor.Viewport protected Float2 _mouseDelta; // Camera - private ViewportCamera _camera; private float _yaw; private float _pitch; @@ -193,8 +192,8 @@ namespace FlaxEditor.Viewport private bool _relativePanning; private bool _invertPanning; - private float _linearMovementProgress; - private float _easedMovementProgress = 0.0f; + private int _speedStep; + private int _maxSpeedSteps; /// /// Speed of the mouse. @@ -216,8 +215,9 @@ namespace FlaxEditor.Viewport { _movementSpeed = value; + var format = (_movementSpeed < 1.0f) ? "{0:0.##}" : "{0:#}"; if (_cameraButton != null) - _cameraButton.Text = string.Format("{0:0.##}", _movementSpeed); + _cameraButton.Text = string.Format(format, _movementSpeed); } } @@ -527,13 +527,14 @@ namespace FlaxEditor.Viewport var largestText = "Relative Panning"; var textSize = Style.Current.FontMedium.MeasureText(largestText); var xLocationForExtras = textSize.X + 5; + var format = (_movementSpeed < 1.0f) ? "{0:0.##}" : "{0:#}"; // Camera settings widget _cameraWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); // Camera settings menu var cameraCM = new ContextMenu(); - _cameraButton = new ViewportWidgetButton(string.Format("{0:0.##}", _movementSpeed), Editor.Instance.Icons.Camera64, cameraCM, false, Style.Current.FontMedium.MeasureText("000.00").X) + _cameraButton = new ViewportWidgetButton(string.Format(format, _movementSpeed), Editor.Instance.Icons.Camera64, cameraCM, false, Style.Current.FontMedium.MeasureText("0.00").X) { Tag = this, TooltipText = "Camera Settings", @@ -884,8 +885,8 @@ namespace FlaxEditor.Viewport InputActions.Add(options => options.ViewpointRight, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Right").Orientation))); InputActions.Add(options => options.ViewpointLeft, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Left").Orientation))); InputActions.Add(options => options.CameraToggleRotation, () => _isVirtualMouseRightDown = !_isVirtualMouseRightDown); - InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(Editor.Instance.Options.Options.Viewport.MouseWheelSensitivity * 0.01f)); - InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(Editor.Instance.Options.Options.Viewport.MouseWheelSensitivity * -0.01f)); + InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(1)); + InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(-1)); // Link for task event task.Begin += OnRenderBegin; @@ -1052,74 +1053,42 @@ namespace FlaxEditor.Viewport } } - /// - /// The inverse of .
- /// Interpolate between A and B, applying a reverse ease in function. Exponent controls the degree of the curve. - ///
- private float InterpInverseEaseIn(float a, float b, float alpha, float exponent) - { - return 0.5f * Mathf.Pow((2.0f * (alpha - a) / (b - a)), 1.0f / exponent); - } - - /// - /// The inverse of .
- /// Interpolate between A and B, applying a reverse ease out function. Exponent controls the degree of the curve. - ///
- private float InterpInverseEaseOut(float a, float b, float alpha, float exponent) - { - return 1.0f - InterpInverseEaseIn(a, b, 1.0f - alpha, exponent); - } - - /// - /// The inverse of .
- /// Interpolate between A and B, applying a reverse ease in/out function. Exponent controls the degree of the curve. - ///
- private float InterpInverseEaseInOut(float a, float b, float alpha, float exponent) - { - if (alpha <= 0.0f) - return a; - if (alpha >= 1.0f) - return b; - - return (alpha < 0.5f) ? InterpInverseEaseIn(a, b, alpha, exponent) : InterpInverseEaseOut(a, b, alpha, exponent); - } - private void OnCameraMovementProgressChanged() { - _linearMovementProgress = Math.Abs(_minMovementSpeed - _maxMovementSpeed) < Mathf.Epsilon - ? 0.0f - : Mathf.Remap(_movementSpeed, _minMovementSpeed, _maxMovementSpeed, 0.0f, 1.0f); - - if (!_useCameraEasing) + // prevent NaN + if (Math.Abs(_minMovementSpeed - _maxMovementSpeed) < Mathf.Epsilon) { + _speedStep = 0; return; - _easedMovementProgress = InterpInverseEaseInOut(0.0f, 1.0f, _linearMovementProgress, _cameraEasingDegree); + } + + // calculate current linear/eased progress + float progress = Mathf.Remap(_movementSpeed, _minMovementSpeed, _maxMovementSpeed, 0.0f, 1.0f); + if (_useCameraEasing) + progress = Mathf.Pow(progress, 1.0f / _cameraEasingDegree); + + _speedStep = Mathf.RoundToInt(progress * _maxSpeedSteps); } /// /// Increases or decreases the camera movement speed. /// - /// The difference in camera speed adjustment as a fraction of 1. - protected void AdjustCameraMoveSpeed(float speedDelta) + /// The stepping direction for speed adjustment. + protected void AdjustCameraMoveSpeed(int step) { - float speed; + _speedStep = Mathf.Clamp(_speedStep + step, 0, _maxSpeedSteps); - if (_useCameraEasing) - { - _easedMovementProgress = Mathf.Saturate(_easedMovementProgress + speedDelta); - speed = Mathf.InterpEaseInOut(_minMovementSpeed, _maxMovementSpeed, _easedMovementProgress, _cameraEasingDegree); - } - else - { - _linearMovementProgress = Mathf.Saturate(_linearMovementProgress + speedDelta); - speed = Mathf.Lerp(_minMovementSpeed, _maxMovementSpeed, _linearMovementProgress); - } + // calculate new linear/eased progress + var progress = _useCameraEasing + ? Mathf.Pow((float)_speedStep / _maxSpeedSteps, _cameraEasingDegree) + : (float)_speedStep / _maxSpeedSteps; - MovementSpeed = speed; + MovementSpeed = Mathf.Lerp(_minMovementSpeed, _maxMovementSpeed, progress); } private void OnEditorOptionsChanged(EditorOptions options) { _mouseSensitivity = options.Viewport.MouseSensitivity; + _maxSpeedSteps = options.Viewport.TotalCameraSpeedSteps; _cameraEasingDegree = options.Viewport.CameraEasingDegree; OnCameraMovementProgressChanged(); } @@ -1507,10 +1476,8 @@ namespace FlaxEditor.Viewport rmbWheel = useMovementSpeed && (_input.IsMouseRightDown || _isVirtualMouseRightDown) && wheelInUse; if (rmbWheel) { - // speed delta can be adjusted through mouse wheel sensitivity in editor - // with default sensitivity (1.0), it takes about ~100 scrolls from min to max - var camSpeedDelta = _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity * 0.01f; - AdjustCameraMoveSpeed(camSpeedDelta); + var step = _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity; + AdjustCameraMoveSpeed(step > 0.0f ? 1 : -1); } }