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
This commit is contained in:
Christopher Rothert
2023-10-07 02:40:52 +02:00
parent fd94cfb469
commit 00aa54cde8
2 changed files with 72 additions and 98 deletions

View File

@@ -26,101 +26,108 @@ namespace FlaxEditor.Options
public float MouseWheelSensitivity { get; set; } = 1.0f;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default minimum camera movement speed.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default maximum camera movement speed.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default camera easing mode.
/// </summary>
[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;
/// <summary>
/// Gets or sets the degree to which the camera will be eased when using camera flight in the editor window.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values).
/// </summary>
[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;
/// <summary>
/// Gets or sets the default minimum camera movement speed.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default maximum camera movement speed.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default camera easing mode.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Defaults"), EditorOrder(130), Tooltip("The default camera easing mode.")]
public bool UseCameraEasing { get; set; } = true;
/// <summary>
/// Gets or sets the default near clipping plane distance for the viewport camera.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default far clipping plane distance for the viewport camera.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default field of view angle (in degrees) for the viewport camera.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default camera orthographic mode.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default camera orthographic scale (if camera uses orthographic mode).
/// </summary>
[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;
/// <summary>
/// Gets or sets the default panning direction for the viewport camera.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default relative panning mode.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default panning speed (ignored if relative panning is speed enabled).
/// </summary>
[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;
/// <summary>
/// Gets or sets the default editor viewport grid scale.
/// </summary>
[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;
}
}

View File

@@ -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;
/// <summary>
/// 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
}
}
/// <summary>
/// The inverse of <see cref="Mathf.InterpEaseIn"/>.<br/>
/// Interpolate between A and B, applying a reverse ease in function. Exponent controls the degree of the curve.
/// </summary>
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);
}
/// <summary>
/// The inverse of <see cref="Mathf.InterpEaseOut"/>.<br/>
/// Interpolate between A and B, applying a reverse ease out function. Exponent controls the degree of the curve.
/// </summary>
private float InterpInverseEaseOut(float a, float b, float alpha, float exponent)
{
return 1.0f - InterpInverseEaseIn(a, b, 1.0f - alpha, exponent);
}
/// <summary>
/// The inverse of <see cref="Mathf.InterpEaseInOut"/>.<br/>
/// Interpolate between A and B, applying a reverse ease in/out function. Exponent controls the degree of the curve.
/// </summary>
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);
}
/// <summary>
/// Increases or decreases the camera movement speed.
/// </summary>
/// <param name="speedDelta">The difference in camera speed adjustment as a fraction of 1.</param>
protected void AdjustCameraMoveSpeed(float speedDelta)
/// <param name="step">The stepping direction for speed adjustment.</param>
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);
}
}