Free-Flying Camera Controller
Summary#
The FreeFlyingCameraController controls a camera that can fly freely around in 3D space without being constrained to a ground plane (in contrast to the first-person controller). The camera is moved via Position and oriented via Yaw and Pitch.
- Adjusting
Positionmoves the camera through space (in any direction). - Adjusting
Yawrotates the camera left or right around the configuredWorldUpaxis. - Adjusting
Pitchtilts the camera up or down.
By default, Pitch is automatically clamped to ±90° each frame so the camera never flips upside-down. This can be disabled via AllowUpsideDownFlip.
Example Usage#
// One time setup:
var controller = camera.CreateController<FreeFlyingCameraController>(); // (1)!
controller.WorldForward = Direction.Forward; // (2)!
controller.WorldUp = Direction.Up; // (3)!
controller.AllowUpsideDownFlip = false; // (4)!
// Per-frame:
controller.AdjustAllViaDefaultControls(input.KeyboardAndMouse, deltaTime); // (5)!
controller.AdjustAllViaDefaultControls(input.GameControllersCombined, deltaTime); // (6)!
controller.Progress(deltaTime); // (7)!
- This creates the controller, attached to the given
camera. -
This sets the "forward" direction of the world. Any direction orthogonal to
WorldUpis permitted. -
This sets the "up" direction of the world. Any direction orthogonal to
WorldForwardis permitted.When
AllowUpsideDownFlipisfalsethis value sets the maximum upward-pitch direction (and its reverse sets the maximum downward-pitch direction). -
This controls whether or not you're allowed to flip upside down while "flying around" with this camera controller.
-
This manipulates the camera according to the default keyboard and mouse scheme. The position/yaw/pitch properties will change according to any registered user inputs for this frame.
You can replace this with more specific control code if desired (see below); or remove it entirely if you do not wish to allow user keyboard/mouse input control.
-
This manipulates the camera according to the default game controller scheme for all game controllers combined. The position/yaw/pitch properties will change according to any registered user inputs for this frame.
You can replace this with more specific control code if desired (see below); or remove it entirely if you do not wish to allow user gamepad input control.
-
Calling
Progress()once per frame is required on all camera controllers in order for them to actually alter their targetCamera's parameters.
Properties#
Per-Frame Targets#
-
Position -
Sets the location of the camera in the world.
Defaults to
Location.Origin. -
Yaw -
Sets the left/right turn amount of the camera.
Increasing this value turns the camera to the left; decreasing to the right.
Defaults to
0°. -
Pitch -
Sets the up/down turn amount of the camera.
A value of
0°means the camera is looking horizontally; positive values tilt upward, negative values tilt downward.Unless
AllowUpsideDownFlipistrue,Pitchis automatically clamped to ±90° duringProgress()so that the camera never flips upside-down.Defaults to
0°.
Configuration#
-
WorldForward -
The "forward" direction in the world that corresponds to the camera's view direction when both
YawandPitchare0°.Defaults to
Direction.Forward. -
WorldUp -
The "up" axis in the world.
Yawrotates the camera around this axis.When set,
WorldUpis automatically orthogonalized againstWorldForward— if you supply a value that is not perpendicular toWorldForward, the component parallel toWorldForwardwill be removed. SettingWorldForwardafterWorldUpwill also re-orthogonalizeWorldUp.Defaults to
Direction.Up. -
AllowUpsideDownFlip -
When
false(the default), the controller automatically clampsPitchto the range ±90° duringProgress()so that the camera will never appear upside-down.When
true, this clamp is removed andPitchmay take any angle, allowing the camera to flip upside-down (useful for flight-sim style controllers).Defaults to
false.
Reacting to Input#
As camera controllers are often meant to be affected by user input, there are some convenience methods supplied for controlling the primary per-frame target properties:
Adjusting Pitch#
Keyboard / Mouse#
-
AdjustPitchViaMouseCursor(...) -
Adjusts
Pitchaccording to the captured mouse cursor movement for this frame.The
axissets which cursor movement direction will be used (defaults toY, e.g. up/down).The
adjustmentPerPixelvalue is the angle to add toPitchfor each pixel moved according to the givenaxis. If null,DefaultPitchSensitivityMouseCursorwill be used.If
invertMouseControlistrue, the calculated adjustment will be reversed. -
AdjustPitchViaMouseWheel(...) -
Adjusts
Pitchaccording to the captured mouse wheel movement for this frame.The
adjustmentPerWheelIncrementvalue is the angle to add toPitchfor each scroll increment on the mouse wheel. If null,DefaultPitchSensitivityMouseWheelwill be used.If
invertMouseControlistrue, the calculated adjustment will be reversed. -
AdjustPitchViaKeyPress(...) -
Adjusts
Pitchaccording to whether a certain key is depressed for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
keyToTestForis the key that, when pressed, will adjust this property.If
reverseistrue, the calculated adjustment will be reversed. Defaults tofalse. This parameter lets you specify two keys in a pair that mirror each other by invoking this method twice (once withreverseasfalseand once withreverseastrue).The
adjustmentPerSecvalue is the angle to add toPitchfor each second this key is depressed. If null,DefaultPitchSensitivityKeyOrButtonPresswill be used.
Gamepad#
-
AdjustPitchViaControllerStick(...) -
Adjusts
Pitchaccording to the captured controller stick position for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
axissets which stick movement direction will be used (defaults toY, e.g. up/down).The
maxAdjustmentPerSecvalue is the angle to add toPitchwhen the stick is fully displaced along the givenaxis. If null,DefaultPitchSensitivityControllerStickwill be used.If
useLeftStickis true, the left controller stick will be measured; otherwise the right stick will be measured. Defaults tofalse.If
invertStickControlistrue, the calculated adjustment will be reversed. -
AdjustPitchViaControllerTriggers(...) -
Adjusts
Pitchaccording to the captured controller trigger positions for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
maxAdjustmentPerSecvalue is the angle to add toPitchwhen the trigger is fully displaced. If null,DefaultPitchSensitivityControllerTriggerwill be used.If
rightTriggerPitchesUpis true, the right trigger will pitch up and the left trigger pitch down; otherwise these directions will be reversed. Defaults totrue. -
AdjustPitchViaButtonPress(...) -
Adjusts
Pitchaccording to whether a certain button is depressed for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
buttonToTestForis the button that, when pressed, will adjust this property.If
reverseistrue, the calculated adjustment will be reversed. Defaults tofalse. This parameter lets you specify two buttons in a pair that mirror each other by invoking this method twice (once withreverseasfalseand once withreverseastrue).The
adjustmentPerSecvalue is the angle to add toPitchfor each second this button is depressed. If null,DefaultPitchSensitivityKeyOrButtonPresswill be used.
Other#
-
AdjustPitch(...) -
Adjusts
Pitchaccording to the given turn rate (adjustmentPerSec) and time step (deltaTime).This method does not inspect any user input data but is provided as a convenience for building custom per-frame control code.
Adjusting Yaw#
Keyboard / Mouse#
-
AdjustYawViaMouseCursor(...) -
Adjusts
Yawaccording to the captured mouse cursor movement for this frame.The
axissets which cursor movement direction will be used (defaults toX, e.g. left/right).The
adjustmentPerPixelvalue is the angle to add toYawfor each pixel moved according to the givenaxis. If null,DefaultYawSensitivityMouseCursorwill be used.If
invertMouseControlistrue, the calculated adjustment will be reversed. -
AdjustYawViaMouseWheel(...) -
Adjusts
Yawaccording to the captured mouse wheel movement for this frame.The
adjustmentPerWheelIncrementvalue is the angle to add toYawfor each scroll increment on the mouse wheel. If null,DefaultYawSensitivityMouseWheelwill be used.If
invertMouseControlistrue, the calculated adjustment will be reversed. -
AdjustYawViaKeyPress(...) -
Adjusts
Yawaccording to whether a certain key is depressed for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
keyToTestForis the key that, when pressed, will adjust this property.If
reverseistrue, the calculated adjustment will be reversed. Defaults tofalse. This parameter lets you specify two keys in a pair that mirror each other by invoking this method twice (once withreverseasfalseand once withreverseastrue).The
adjustmentPerSecvalue is the angle to add toYawfor each second this key is depressed. If null,DefaultYawSensitivityKeyOrButtonPresswill be used.
Gamepad#
-
AdjustYawViaControllerStick(...) -
Adjusts
Yawaccording to the captured controller stick position for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
axissets which stick movement direction will be used (defaults toX, e.g. left/right).The
maxAdjustmentPerSecvalue is the angle to add toYawwhen the stick is fully displaced along the givenaxis. If null,DefaultYawSensitivityControllerStickwill be used.If
useLeftStickis true, the left controller stick will be measured; otherwise the right stick will be measured. Defaults tofalse.If
invertStickControlistrue, the calculated adjustment will be reversed. -
AdjustYawViaControllerTriggers(...) -
Adjusts
Yawaccording to the captured controller trigger positions for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
maxAdjustmentPerSecvalue is the angle to add toYawwhen the trigger is fully displaced. If null,DefaultYawSensitivityControllerTriggerwill be used.If
leftTriggerYawsLeftis true, the left trigger will yaw left and the right trigger yaw right; otherwise these directions will be reversed. Defaults totrue. -
AdjustYawViaButtonPress(...) -
Adjusts
Yawaccording to whether a certain button is depressed for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
buttonToTestForis the button that, when pressed, will adjust this property.If
reverseistrue, the calculated adjustment will be reversed. Defaults tofalse. This parameter lets you specify two buttons in a pair that mirror each other by invoking this method twice (once withreverseasfalseand once withreverseastrue).The
adjustmentPerSecvalue is the angle to add toYawfor each second this button is depressed. If null,DefaultYawSensitivityKeyOrButtonPresswill be used.
Other#
-
AdjustYaw(...) -
Adjusts
Yawaccording to the given turn rate (adjustmentPerSec) and time step (deltaTime).This method does not inspect any user input data but is provided as a convenience for building custom per-frame control code.
Adjusting Position#
Position adjustments can be specified in one of two equivalent ways:
- Using a camera-relative
Orientation(e.g.Orientation.Forward,Orientation.Right,Orientation.Up, etc.) and a scalarspeed/distance. TheOrientationis interpreted relative to the camera's current view direction. - Using a
Vect(a world-space vector) directly. This bypasses camera-relative interpretation entirely.
Each AdjustPositionVia* method below provides both overloads. The Orientation-based form is generally more convenient; the Vect-based form is provided for cases where you wish to specify a fixed world-space movement vector.
Keyboard / Mouse#
-
AdjustPositionViaMouseCursor(...) -
Adjusts
Positionaccording to the captured mouse cursor movement for this frame.The
axissets which cursor movement direction will be used (defaults toX, e.g. left/right).Orientation-form: ThecameraRelativeOrientationparameter sets the camera-relative direction the camera moves in when the cursor is moved positively alongaxis. Thespeedvalue is the distance (in world units) to move per pixel of cursor movement. If null,DefaultPositionSensitivityMouseCursorwill be used.Vect-form: TheadjustmentPerPixelparameter is a world-spaceVectrepresenting the movement applied per pixel of cursor movement.If
invertMouseControlistrue, the calculated adjustment will be reversed. -
AdjustPositionViaMouseWheel(...) -
Adjusts
Positionaccording to the captured mouse wheel movement for this frame.Orientation-form: ThecameraRelativeOrientationparameter sets the camera-relative direction the camera moves in when the wheel is scrolled forward. Thespeedvalue is the distance (in world units) to move per scroll increment. If null,DefaultPositionSensitivityMouseWheelwill be used.Vect-form: TheadjustmentPerWheelIncrementparameter is a world-spaceVectrepresenting the movement applied per scroll increment.If
invertMouseControlistrue, the calculated adjustment will be reversed. -
AdjustPositionViaKeyPress(...) -
Adjusts
Positionaccording to whether a certain key is depressed for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
keyToTestForis the key that, when pressed, will move the camera.Orientation-form: ThecameraRelativeOrientationparameter is the camera-relative direction the camera moves in while the key is depressed. Thespeedvalue is the distance per second to move while the key is depressed. If null,DefaultPositionSensitivityKeyOrButtonPresswill be used.Vect-form: TheadjustmentPerSecparameter is a world-spaceVectrepresenting the movement applied per second while the key is depressed.
Gamepad#
-
AdjustPositionViaControllerStick(...) -
Adjusts
Positionaccording to the captured controller stick position for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
axissets which stick movement direction will be used (defaults toX, e.g. left/right).Orientation-form: ThecameraRelativeOrientationparameter sets the camera-relative direction the camera moves in when the stick is fully displaced alongaxis. ThemaxSpeedvalue is the maximum distance per second when the stick is fully displaced. If null,DefaultPositionSensitivityControllerStickwill be used.Vect-form: ThemaxAdjustmentPerSecparameter is a world-spaceVectrepresenting the maximum movement per second.If
useLeftStickis true, the left controller stick will be measured; otherwise the right stick will be measured. Defaults totrue.If
invertStickControlistrue, the calculated adjustment will be reversed. -
AdjustPositionViaControllerTriggers(...) -
Adjusts
Positionaccording to the captured controller trigger positions for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.Orientation-form: ThecameraRelativeOrientationparameter sets the camera-relative direction the camera moves in when the "positive" trigger is held. ThemaxSpeedvalue is the maximum distance per second when the trigger is fully displaced. If null,DefaultPositionSensitivityControllerTriggerwill be used.Vect-form: ThemaxAdjustmentPerSecparameter is a world-spaceVectrepresenting the maximum movement per second when the "positive" trigger is fully displaced.If
leftTriggerMovesPositiveis true, the left trigger moves in the configured direction and the right trigger in the opposite direction; otherwise these directions will be reversed. Defaults totrue. -
AdjustPositionViaButtonPress(...) -
Adjusts
Positionaccording to whether a certain button is depressed for this frame.The
deltaTimevalue is expected to be the time in seconds of this frame iteration.The
buttonToTestForis the button that, when pressed, will move the camera.Orientation-form: ThecameraRelativeOrientationparameter is the camera-relative direction the camera moves in while the button is depressed. Thespeedvalue is the distance per second to move while the button is depressed. If null,DefaultPositionSensitivityKeyOrButtonPresswill be used.Vect-form: TheadjustmentPerSecparameter is a world-spaceVectrepresenting the movement applied per second while the button is depressed.
Other#
-
AdjustPosition(...) -
Several overloads are provided to directly adjust
Positionwithout inspecting any user input data, for building custom per-frame control code:AdjustPosition(Orientation cameraRelativeOrientation, float distance)— moves a fixed distance in the given camera-relative orientation.AdjustPosition(float deltaTime, Orientation cameraRelativeOrientation, float speed)— speed/time-based version of the above.AdjustPosition(float deltaTime, Vect adjustmentPerSec)— moves at the given world-space rate scaled bydeltaTime.
Default Controls#
The following snippets show the implementation of AdjustAllViaDefaultControls(...) for keyboard/mouse and gamepad respectively:
// AdjustAllViaDefaultControls(input.KeyboardAndMouse, deltaTime):
AdjustPitchViaMouseCursor(input, pitchAdjustmentPerPixel, invertMouseControl: invertPitchControl);
AdjustYawViaMouseCursor(input, yawAdjustmentPerPixel, invertMouseControl: invertYawControl);
AdjustPositionViaKeyPress(input, deltaTime, KeyboardOrMouseKey.ArrowLeft, Orientation.Left, positionAdjustmentSpeed);
AdjustPositionViaKeyPress(input, deltaTime, KeyboardOrMouseKey.ArrowRight, Orientation.Right, positionAdjustmentSpeed);
AdjustPositionViaKeyPress(input, deltaTime, KeyboardOrMouseKey.ArrowUp, Orientation.Forward, positionAdjustmentSpeed);
AdjustPositionViaKeyPress(input, deltaTime, KeyboardOrMouseKey.ArrowDown, Orientation.Backward, positionAdjustmentSpeed);
AdjustPositionViaKeyPress(input, deltaTime, KeyboardOrMouseKey.RightShift, invertUpDownPositionalControl ? Orientation.Down : Orientation.Up, positionAdjustmentSpeed);
AdjustPositionViaKeyPress(input, deltaTime, KeyboardOrMouseKey.RightControl, invertUpDownPositionalControl ? Orientation.Up : Orientation.Down, positionAdjustmentSpeed);
// AdjustAllViaDefaultControls(input.GameControllersCombined, deltaTime):
AdjustPitchViaControllerStick(input, deltaTime, maxPitchAdjustmentPerSec, invertStickControl: invertPitchControl);
AdjustYawViaControllerStick(input, deltaTime, maxYawAdjustmentPerSec, invertStickControl: invertYawControl);
AdjustPositionViaControllerStick(input, deltaTime, Orientation.Forward, maxPositionAdjustmentSpeed, axis: Axis2D.Y);
AdjustPositionViaControllerStick(input, deltaTime, Orientation.Right, maxPositionAdjustmentSpeed, axis: Axis2D.X);
AdjustPositionViaControllerTriggers(input, deltaTime, invertUpDownPositionalControl ? Orientation.Up : Orientation.Down, maxPositionAdjustmentSpeed);
Smoothing#
Smoothing changes how quickly the controller adjusts the camera to match the current target properties.
The Position, Yaw, and Pitch target properties can have smoothing applied. Note that Yaw and Pitch share a single RotationSmoothingStrength setting — they cannot be smoothed independently of one another.
// Set properties' smoothing individually:
controller.PositionSmoothingStrength = Strength.VeryMild;
controller.RotationSmoothingStrength = Strength.VeryMild; // Applies to both Yaw and Pitch
// Set all properties' smoothing simutaneously:
controller.SetGlobalSmoothing(Strength.VeryMild);
The default smoothing for all properties is VeryMild. You can choose from VeryMild, Mild, Moderate, Strong, VeryStrong, or None.
- Smoothing makes the camera feel more 'real' or physical.
- Higher strengths increase this feeling but also increase the latency between setting a target value and the camera actually meeting that target.
- Setting the smoothing to
Nonedisables smoothing entirely. This means the camera will always be updated to meet exactly the target value of each property on each frame; reducing latency to 0 but making the camera feel less physical.
Custom Smoothing Values
If the enum-based approach is not specific enough for your needs, every property can instead have a custom smoothing strength applied via a method named like "SetCustom[...]SmoothingStrength".
This method takes a single float parameter that indicates the half-life of decay between the current value of a property and its target value.
For example, if the current value of X is 50 and the target value of X is 100, a half-life of 1f would move X to 75 after one second, and then 87.5 after the next second, and so-on.
Advanced: Smoothing is implemented via critically-damped spring. The smoothingHalfLife parameter is translated to become the Ω of the spring equation via the formula Ω = 1.6783469f / smoothingHalfLife.