SceneCamera.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using bs;
  4. namespace bs.Editor
  5. {
  6. /** @addtogroup Scene-Editor
  7. * @{
  8. */
  9. /// <summary>
  10. /// Handles camera movement in the scene view.
  11. /// </summary>
  12. [RunInEditor]
  13. internal sealed class SceneCamera : ManagedComponent
  14. {
  15. #region Constants
  16. public const float StartSpeed = 4.0f;
  17. public const float TopSpeed = 12.0f;
  18. public const string MoveForwardBinding = "SceneForward";
  19. public const string MoveLeftBinding = "SceneLeft";
  20. public const string MoveRightBinding = "SceneRight";
  21. public const string MoveBackBinding = "SceneBackward";
  22. public const string MoveUpBinding = "SceneUp";
  23. public const string MoveDownBinding = "SceneDown";
  24. public const string FastMoveBinding = "SceneFastMove";
  25. public const string PanBinding = "ScenePan";
  26. public const string RotateBinding = "SceneRotate";
  27. public const string HorizontalAxisBinding = "SceneHorizontal";
  28. public const string VerticalAxisBinding = "SceneVertical";
  29. public const string ScrollAxisBinding = "SceneScroll";
  30. public const string ViewSettingsKey = "SceneCamera0_ViewSettings";
  31. public const string MoveSettingsKey = "SceneCamera0_MoveSettings";
  32. public const string RenderSettingsKey = "SceneCamera0_RenderSettings";
  33. #endregion
  34. #region Fields
  35. private VirtualButton moveForwardBtn;
  36. private VirtualButton moveLeftBtn;
  37. private VirtualButton moveRightBtn;
  38. private VirtualButton moveBackwardBtn;
  39. private VirtualButton moveUpBtn;
  40. private VirtualButton moveDownBtn;
  41. private VirtualButton fastMoveBtn;
  42. private VirtualButton activeBtn;
  43. private VirtualButton panBtn;
  44. private VirtualAxis horizontalAxis;
  45. private VirtualAxis verticalAxis;
  46. private VirtualAxis scrollAxis;
  47. private float currentSpeed;
  48. private Degree yaw;
  49. private Degree pitch;
  50. private bool lastHideCursorState;
  51. private Camera camera;
  52. private bool inputEnabled = true;
  53. private SceneCameraViewSettings viewSettings;
  54. // Animating camera transitions
  55. private CameraAnimation animation = new CameraAnimation();
  56. private float frustumWidth = 50.0f;
  57. private float lerp;
  58. private bool isAnimating;
  59. #endregion
  60. #region Public properties
  61. /// <summary>
  62. /// Returns the internal camera component. You should not make modifications to the returned camera.
  63. /// </summary>
  64. public Camera Camera { get => camera; }
  65. /// <summary>
  66. /// Counter that increments every frame when the camera transform changes.
  67. /// </summary>
  68. public ulong UpdateCount { get; private set; }
  69. /// <summary>
  70. /// Settings for controlling scene camera view.
  71. /// </summary>
  72. public SceneCameraViewSettings ViewSettings
  73. {
  74. get => viewSettings;
  75. set
  76. {
  77. viewSettings = value;
  78. camera.ProjectionType = value.projectionType;
  79. camera.NearClipPlane = value.nearClipPlane;
  80. camera.FarClipPlane = value.farClipPlane;
  81. camera.OrthoHeight = value.orthographicSize;
  82. camera.FieldOfView = value.fieldOfView;
  83. camera.Viewport.ClearColor = value.backgroundColor;
  84. NotifyNeedsRedraw();
  85. }
  86. }
  87. /// <summary>
  88. /// Settings for controlling scene camera movement.
  89. /// </summary>
  90. public SceneCameraMoveSettings MoveSettings { get; set; }
  91. /// <summary>
  92. /// Options for controlling scene camera rendering.
  93. /// </summary>
  94. public RenderSettings RenderSettings
  95. {
  96. get => camera.RenderSettings;
  97. set => camera.RenderSettings = value;
  98. }
  99. #endregion
  100. #region Public methods
  101. /// <summary>
  102. /// Changes the scene camera projection type and animates the transition.
  103. /// </summary>
  104. /// <param name="projectionType">New projection type.</param>
  105. public void ChangeProjectionType(ProjectionType projectionType)
  106. {
  107. if (camera.ProjectionType != projectionType)
  108. {
  109. CameraState state = new CameraState();
  110. state.Position = camera.SceneObject.Position;
  111. state.Rotation = camera.SceneObject.Rotation;
  112. state.Orthographic = projectionType == ProjectionType.Orthographic;
  113. state.FrustumWidth = frustumWidth;
  114. viewSettings.projectionType = projectionType;
  115. ProjectSettings.SetObject(ViewSettingsKey, viewSettings);
  116. SetState(state);
  117. }
  118. }
  119. /// <summary>
  120. /// Enables or disables camera controls.
  121. /// </summary>
  122. /// <param name="enable">True to enable controls, false to disable.</param>
  123. public void EnableInput(bool enable)
  124. {
  125. inputEnabled = enable;
  126. }
  127. /// <summary>
  128. /// Focuses the camera on the currently selected object(s).
  129. /// </summary>
  130. public void FrameSelected()
  131. {
  132. SceneObject[] selectedObjects = Selection.SceneObjects;
  133. if (selectedObjects.Length > 0)
  134. {
  135. AABox box = EditorUtility.CalculateBounds(Selection.SceneObjects);
  136. FrameBounds(box);
  137. }
  138. }
  139. /// <summary>
  140. /// Orients the camera so it looks along the provided axis.
  141. /// </summary>
  142. public void LookAlong(Vector3 axis)
  143. {
  144. Vector3 up = Vector3.YAxis;
  145. if (MathEx.Abs(Vector3.Dot(axis, up)) > 0.9f)
  146. up = Vector3.ZAxis;
  147. CameraState state = new CameraState();
  148. state.Position = camera.SceneObject.Position;
  149. state.Rotation = Quaternion.LookRotation(axis, up);
  150. state.Orthographic = camera.ProjectionType == ProjectionType.Orthographic;
  151. state.FrustumWidth = frustumWidth;
  152. SetState(state);
  153. }
  154. /// <summary>
  155. /// Notifies the system that the 3D viewport should be redrawn.
  156. /// </summary>
  157. internal void NotifyNeedsRedraw()
  158. {
  159. camera.NotifyNeedsRedraw();
  160. }
  161. /// <summary>
  162. /// Enables or disables on-demand drawing. When enabled the 3D viewport will only be redrawn when
  163. /// <see cref="NotifyNeedsRedraw"/> is called. If disabled the viewport will be redrawn every frame.
  164. /// Normally you always want to keep this disabled unless you know the viewport will require updates
  165. /// every frame (e.g. when a game is running, or when previewing animations).
  166. /// </summary>
  167. /// <param name="enabled">True to enable on-demand drawing, false otherwise.</param>
  168. internal void ToggleOnDemandDrawing(bool enabled)
  169. {
  170. if (enabled)
  171. camera.Flags |= CameraFlag.OnDemand;
  172. else
  173. camera.Flags &= ~CameraFlag.OnDemand;
  174. }
  175. #endregion
  176. #region Private methods
  177. private void OnReset()
  178. {
  179. camera = SceneObject.GetComponent<Camera>();
  180. ViewSettings = ProjectSettings.GetObject<SceneCameraViewSettings>(ViewSettingsKey);
  181. MoveSettings = ProjectSettings.GetObject<SceneCameraMoveSettings>(MoveSettingsKey);
  182. RenderSettings = ProjectSettings.GetObject<RenderSettings>(RenderSettingsKey);
  183. if (RenderSettings == null)
  184. RenderSettings = SceneCameraSettingsWindow.GetDefaultRenderSettings();
  185. moveForwardBtn = new VirtualButton(MoveForwardBinding);
  186. moveLeftBtn = new VirtualButton(MoveLeftBinding);
  187. moveRightBtn = new VirtualButton(MoveRightBinding);
  188. moveBackwardBtn = new VirtualButton(MoveBackBinding);
  189. moveUpBtn = new VirtualButton(MoveUpBinding);
  190. moveDownBtn = new VirtualButton(MoveDownBinding);
  191. fastMoveBtn = new VirtualButton(FastMoveBinding);
  192. activeBtn = new VirtualButton(RotateBinding);
  193. panBtn = new VirtualButton(PanBinding);
  194. horizontalAxis = new VirtualAxis(HorizontalAxisBinding);
  195. verticalAxis = new VirtualAxis(VerticalAxisBinding);
  196. scrollAxis = new VirtualAxis(ScrollAxisBinding);
  197. NotifyNeedsRedraw();
  198. }
  199. private void OnUpdate()
  200. {
  201. bool isOrthographic = camera.ProjectionType == ProjectionType.Orthographic;
  202. float frameDelta = Time.FrameDelta;
  203. bool updated = false;
  204. if (inputEnabled)
  205. {
  206. bool goingForward = VirtualInput.IsButtonHeld(moveForwardBtn);
  207. bool goingBack = VirtualInput.IsButtonHeld(moveBackwardBtn);
  208. bool goingLeft = VirtualInput.IsButtonHeld(moveLeftBtn);
  209. bool goingRight = VirtualInput.IsButtonHeld(moveRightBtn);
  210. bool goingUp = VirtualInput.IsButtonHeld(moveUpBtn);
  211. bool goingDown = VirtualInput.IsButtonHeld(moveDownBtn);
  212. bool fastMove = VirtualInput.IsButtonHeld(fastMoveBtn);
  213. bool camActive = VirtualInput.IsButtonHeld(activeBtn);
  214. bool isPanning = VirtualInput.IsButtonHeld(panBtn);
  215. bool hideCursor = camActive || isPanning;
  216. if (hideCursor != lastHideCursorState)
  217. {
  218. if (hideCursor)
  219. {
  220. Cursor.Hide();
  221. Rect2I clipRect;
  222. clipRect.x = Input.PointerPosition.x - 2;
  223. clipRect.y = Input.PointerPosition.y - 2;
  224. clipRect.width = 4;
  225. clipRect.height = 4;
  226. Cursor.ClipToRect(clipRect);
  227. }
  228. else
  229. {
  230. Cursor.Show();
  231. Cursor.ClipDisable();
  232. }
  233. lastHideCursorState = hideCursor;
  234. }
  235. if (camActive)
  236. {
  237. float horzValue = VirtualInput.GetAxisValue(horizontalAxis);
  238. float vertValue = VirtualInput.GetAxisValue(verticalAxis);
  239. float rotationAmount = MoveSettings.rotationalSpeed * EditorSettings.MouseSensitivity;
  240. yaw += new Degree(horzValue * rotationAmount);
  241. pitch += new Degree(vertValue * rotationAmount);
  242. yaw = MathEx.WrapAngle(yaw);
  243. pitch = MathEx.WrapAngle(pitch);
  244. Quaternion yRot = Quaternion.FromAxisAngle(Vector3.YAxis, yaw);
  245. Quaternion xRot = Quaternion.FromAxisAngle(Vector3.XAxis, pitch);
  246. Quaternion camRot = yRot * xRot;
  247. camRot.Normalize();
  248. SceneObject.Rotation = camRot;
  249. // Handle movement using movement keys
  250. Vector3 direction = Vector3.Zero;
  251. if (goingForward) direction += SceneObject.Forward;
  252. if (goingBack) direction -= SceneObject.Forward;
  253. if (goingRight) direction += SceneObject.Right;
  254. if (goingLeft) direction -= SceneObject.Right;
  255. if (goingUp) direction += SceneObject.Up;
  256. if (goingDown) direction -= SceneObject.Up;
  257. if (direction.SqrdLength != 0)
  258. {
  259. direction.Normalize();
  260. float multiplier = 1.0f;
  261. if (fastMove)
  262. multiplier = MoveSettings.fastModeMultiplier;
  263. currentSpeed = MathEx.Clamp(currentSpeed + MoveSettings.acceleration * frameDelta, StartSpeed, TopSpeed);
  264. currentSpeed *= multiplier;
  265. }
  266. else
  267. {
  268. currentSpeed = 0.0f;
  269. }
  270. const float tooSmall = 0.0001f;
  271. if (currentSpeed > tooSmall)
  272. {
  273. Vector3 velocity = direction * currentSpeed;
  274. SceneObject.Move(velocity * frameDelta);
  275. }
  276. updated = true;
  277. }
  278. // Pan
  279. if (isPanning)
  280. {
  281. float horzValue = VirtualInput.GetAxisValue(horizontalAxis);
  282. float vertValue = VirtualInput.GetAxisValue(verticalAxis);
  283. Vector3 direction = new Vector3(horzValue, -vertValue, 0.0f);
  284. direction = camera.SceneObject.Rotation.Rotate(direction);
  285. SceneObject.Move(direction * MoveSettings.panSpeed * frameDelta);
  286. updated = true;
  287. }
  288. }
  289. else
  290. {
  291. if (lastHideCursorState)
  292. {
  293. Cursor.Show();
  294. Cursor.ClipDisable();
  295. lastHideCursorState = false;
  296. }
  297. }
  298. SceneWindow sceneWindow = EditorWindow.GetWindow<SceneWindow>();
  299. if ((sceneWindow.Active && sceneWindow.HasFocus) || sceneWindow.IsPointerHovering)
  300. {
  301. Rect2I bounds = sceneWindow.Bounds;
  302. // Move using scroll wheel
  303. if (bounds.Contains(Input.PointerPosition))
  304. {
  305. float scrollAmount = VirtualInput.GetAxisValue(scrollAxis);
  306. if(scrollAmount != 0)
  307. {
  308. if (!isOrthographic)
  309. {
  310. SceneObject.Move(SceneObject.Forward * scrollAmount * MoveSettings.scrollSpeed * frameDelta);
  311. }
  312. else
  313. {
  314. float oldOrthoHeight = camera.OrthoHeight;
  315. float orthoHeight = MathEx.Max(1.0f, oldOrthoHeight - scrollAmount * frameDelta);
  316. if (oldOrthoHeight != orthoHeight)
  317. camera.OrthoHeight = orthoHeight;
  318. }
  319. updated = true;
  320. }
  321. }
  322. }
  323. UpdateAnim();
  324. if (updated)
  325. {
  326. NotifyNeedsRedraw();
  327. UpdateCount++;
  328. }
  329. }
  330. /// <summary>
  331. /// Moves and orients a camera so that the provided bounds end covering the camera's viewport.
  332. /// </summary>
  333. /// <param name="bounds">Bounds to frame in camera's view.</param>
  334. /// <param name="padding">Amount of padding to leave on the borders of the viewport, in percent [0, 1].</param>
  335. private void FrameBounds(AABox bounds, float padding = 0.0f)
  336. {
  337. // TODO - Use AABox bounds directly instead of a sphere to be more accurate
  338. float worldWidth = bounds.Size.Length;
  339. float worldHeight = worldWidth;
  340. if (worldWidth == 0.0f)
  341. worldWidth = 1.0f;
  342. if (worldHeight == 0.0f)
  343. worldHeight = 1.0f;
  344. float boundsAspect = worldWidth / worldHeight;
  345. float paddingScale = MathEx.Clamp01(padding) + 1.0f;
  346. float frustumWidth;
  347. // If camera has wider aspect than bounds then height will be the limiting dimension
  348. if (camera.AspectRatio > boundsAspect)
  349. frustumWidth = worldHeight * camera.AspectRatio * paddingScale;
  350. else // Otherwise width
  351. frustumWidth = worldWidth * paddingScale;
  352. float distance = CalcDistanceForFrustumWidth(frustumWidth);
  353. Vector3 forward = bounds.Center - SceneObject.Position;
  354. forward.Normalize();
  355. GetNearFarForDistance(distance, out var near, out var far);
  356. viewSettings.nearClipPlane = near;
  357. viewSettings.farClipPlane = far;
  358. ProjectSettings.SetObject(ViewSettingsKey, viewSettings);
  359. CameraState state = new CameraState();
  360. state.Position = bounds.Center - forward * distance;
  361. state.Rotation = Quaternion.LookRotation(forward, Vector3.YAxis);
  362. state.Orthographic = camera.ProjectionType == ProjectionType.Orthographic;
  363. state.FrustumWidth = frustumWidth;
  364. SetState(state);
  365. }
  366. /// <summary>
  367. /// Changes the state of the camera, either instantly or animated over several frames. The state includes
  368. /// camera position, rotation, type and possibly other parameters.
  369. /// </summary>
  370. /// <param name="state">New state of the camera.</param>
  371. /// <param name="animated">Should the state be linearly interpolated over a course of several frames.</param>
  372. private void SetState(CameraState state, bool animated = true)
  373. {
  374. CameraState startState = new CameraState();
  375. startState.Position = SceneObject.Position;
  376. startState.Rotation = SceneObject.Rotation;
  377. startState.Orthographic = camera.ProjectionType == ProjectionType.Orthographic;
  378. startState.FrustumWidth = frustumWidth;
  379. animation.Start(startState, state);
  380. if (!animated)
  381. {
  382. ApplyState(1.0f);
  383. isAnimating = false;
  384. }
  385. else
  386. {
  387. isAnimating = true;
  388. lerp = 0.0f;
  389. }
  390. }
  391. /// <summary>
  392. /// Applies the animation target state depending on the interpolation parameter. <see cref="SetState"/>.
  393. /// </summary>
  394. /// <param name="t">Interpolation parameter ranging [0, 1] that interpolated between the start state and the
  395. /// target state.</param>
  396. private void ApplyState(float t)
  397. {
  398. animation.Update(t);
  399. SceneObject.Position = animation.State.Position;
  400. SceneObject.Rotation = animation.State.Rotation;
  401. frustumWidth = animation.State.FrustumWidth;
  402. Vector3 eulerAngles = SceneObject.Rotation.ToEuler();
  403. pitch = (Degree)eulerAngles.x;
  404. yaw = (Degree)eulerAngles.y;
  405. Degree FOV = (Degree)(1.0f - animation.State.OrthographicPct) * viewSettings.fieldOfView;
  406. if (FOV < (Degree)5.0f)
  407. {
  408. camera.ProjectionType = ProjectionType.Orthographic;
  409. camera.OrthoHeight = frustumWidth * 0.5f / camera.AspectRatio;
  410. }
  411. else
  412. {
  413. camera.ProjectionType = ProjectionType.Perspective;
  414. camera.FieldOfView = FOV;
  415. }
  416. // Note: Consider having a global setting for near/far planes as changing it here might confuse the user
  417. float distance = CalcDistanceForFrustumWidth(frustumWidth);
  418. GetNearFarForDistance(distance, out var near, out var far);
  419. camera.NearClipPlane = near;
  420. camera.FarClipPlane = far;
  421. NotifyNeedsRedraw();
  422. UpdateCount++;
  423. }
  424. /// <summary>
  425. /// Calculates distance at which the camera's frustum width is equal to the provided width.
  426. /// </summary>
  427. /// <param name="frustumWidth">Frustum width to find the distance for, in world units.</param>
  428. /// <returns>Distance at which the camera's frustum is the specified width, in world units.</returns>
  429. private float CalcDistanceForFrustumWidth(float frustumWidth)
  430. {
  431. if (camera.ProjectionType == ProjectionType.Perspective)
  432. return (frustumWidth * 0.5f) / MathEx.Tan(camera.FieldOfView * 0.5f);
  433. else
  434. return frustumWidth * 2.0f;
  435. }
  436. /// <summary>
  437. /// Updates camera state transition animation. Should be called every frame.
  438. /// </summary>
  439. private void UpdateAnim()
  440. {
  441. if (!isAnimating)
  442. return;
  443. const float ANIM_TIME = 0.5f; // 0.5f seconds
  444. lerp += Time.FrameDelta * (1.0f / ANIM_TIME);
  445. if (lerp >= 1.0f)
  446. {
  447. lerp = 1.0f;
  448. isAnimating = false;
  449. }
  450. ApplyState(lerp);
  451. }
  452. /// <summary>
  453. /// Calculates the camera near and far plane distances used for looking at an object certain distance from the
  454. /// camera.
  455. /// </summary>
  456. /// <param name="distance">Distance of the object from the camera.</param>
  457. /// <param name="near">Output near plane distance.</param>
  458. /// <param name="far">Output far plane distance.</param>
  459. private static void GetNearFarForDistance(float distance, out float near, out float far)
  460. {
  461. if (distance < 1)
  462. {
  463. near = 0.005f;
  464. far = 1000f;
  465. }
  466. if (distance < 100)
  467. {
  468. near = 0.05f;
  469. far = 2500f;
  470. }
  471. else if (distance < 1000)
  472. {
  473. near = 0.5f;
  474. far = 10000f;
  475. }
  476. else
  477. {
  478. near = 5.0f;
  479. far = 1000000f;
  480. }
  481. }
  482. /// <summary>
  483. /// Contains data for a possible camera state. Camera states can be interpolated between each other as needed.
  484. /// </summary>
  485. private struct CameraState
  486. {
  487. private float _orthographic;
  488. public Vector3 Position { get; set; }
  489. public Quaternion Rotation { get; set; }
  490. public float FrustumWidth { get; set; }
  491. public bool Orthographic
  492. {
  493. get { return _orthographic > 0.5; }
  494. set { _orthographic = value ? 1.0f : 0.0f; }
  495. }
  496. public float OrthographicPct
  497. {
  498. get { return _orthographic; }
  499. set { _orthographic = value; }
  500. }
  501. }
  502. /// <summary>
  503. /// Helper class that performs linear interpolation between two camera states.
  504. /// </summary>
  505. private struct CameraAnimation
  506. {
  507. private CameraState start;
  508. private CameraState target;
  509. private CameraState interpolated;
  510. /// <summary>
  511. /// Returns currently interpolated animation state.
  512. /// </summary>
  513. public CameraState State
  514. {
  515. get { return interpolated; }
  516. }
  517. /// <summary>
  518. /// Initializes the animation with initial and target states.
  519. /// </summary>
  520. /// <param name="start">Initial state to animate from.</param>
  521. /// <param name="target">Target state to animate towards.</param>
  522. public void Start(CameraState start, CameraState target)
  523. {
  524. this.start = start;
  525. this.target = target;
  526. }
  527. /// <summary>
  528. /// Updates the animation by interpolating between the start and target states.
  529. /// </summary>
  530. /// <param name="t">Interpolation parameter in range [0, 1] that determines how much to interpolate between
  531. /// start and target states.</param>
  532. public void Update(float t)
  533. {
  534. interpolated = new CameraState();
  535. interpolated.Position = start.Position * (1.0f - t) + target.Position * t;
  536. interpolated.Rotation = Quaternion.Slerp(start.Rotation, target.Rotation, t);
  537. interpolated.OrthographicPct = start.OrthographicPct * (1.0f - t) + target.OrthographicPct * t;
  538. interpolated.FrustumWidth = start.FrustumWidth * (1.0f - t) + target.FrustumWidth * t;
  539. }
  540. };
  541. #endregion
  542. }
  543. /// <summary>
  544. /// Contains properties used for controlling scene camera movement.
  545. /// </summary>
  546. [SerializeObject]
  547. internal class SceneCameraMoveSettings
  548. {
  549. [Range(0.1f, 10.0f)]
  550. public float acceleration = 1.0f;
  551. [Range(1.0f, 10.0f)]
  552. public float fastModeMultiplier = 2.0f;
  553. [Range(0.1f, 10.0f)]
  554. public float panSpeed = 3.0f;
  555. [Range(0.1f, 3.0f)]
  556. public float scrollSpeed = 3.0f;
  557. [Range(0.1f, 10.0f)]
  558. public float rotationalSpeed = 3.0f;
  559. }
  560. /// <summary>
  561. /// Contains properties used for controlling scene camera view.
  562. /// </summary>
  563. [SerializeObject]
  564. internal class SceneCameraViewSettings
  565. {
  566. public ProjectionType projectionType = ProjectionType.Perspective;
  567. [Range(10.0f, 170.0f, false)]
  568. public Degree fieldOfView = new Degree(90.0f);
  569. [Range(0.001f, 10000.0f, false)]
  570. public float orthographicSize = 10.0f;
  571. [Range(0.0001f, 10, false)]
  572. public float nearClipPlane = 0.05f;
  573. [Range(1.0f, 100000.0f, false)]
  574. public float farClipPlane = 2500.0f;
  575. public Color backgroundColor = new Color(0.282f, 0.341f, 0.478f);
  576. }
  577. /** @} */
  578. }