SceneCamera.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  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. camera.Flags = enabled ? CameraFlag.OnDemand : new CameraFlag();
  171. }
  172. #endregion
  173. #region Private methods
  174. private void OnReset()
  175. {
  176. camera = SceneObject.GetComponent<Camera>();
  177. ViewSettings = ProjectSettings.GetObject<SceneCameraViewSettings>(ViewSettingsKey);
  178. MoveSettings = ProjectSettings.GetObject<SceneCameraMoveSettings>(MoveSettingsKey);
  179. RenderSettings = ProjectSettings.GetObject<RenderSettings>(RenderSettingsKey);
  180. moveForwardBtn = new VirtualButton(MoveForwardBinding);
  181. moveLeftBtn = new VirtualButton(MoveLeftBinding);
  182. moveRightBtn = new VirtualButton(MoveRightBinding);
  183. moveBackwardBtn = new VirtualButton(MoveBackBinding);
  184. moveUpBtn = new VirtualButton(MoveUpBinding);
  185. moveDownBtn = new VirtualButton(MoveDownBinding);
  186. fastMoveBtn = new VirtualButton(FastMoveBinding);
  187. activeBtn = new VirtualButton(RotateBinding);
  188. panBtn = new VirtualButton(PanBinding);
  189. horizontalAxis = new VirtualAxis(HorizontalAxisBinding);
  190. verticalAxis = new VirtualAxis(VerticalAxisBinding);
  191. scrollAxis = new VirtualAxis(ScrollAxisBinding);
  192. NotifyNeedsRedraw();
  193. }
  194. private void OnUpdate()
  195. {
  196. bool isOrthographic = camera.ProjectionType == ProjectionType.Orthographic;
  197. float frameDelta = Time.FrameDelta;
  198. bool updated = false;
  199. if (inputEnabled)
  200. {
  201. bool goingForward = VirtualInput.IsButtonHeld(moveForwardBtn);
  202. bool goingBack = VirtualInput.IsButtonHeld(moveBackwardBtn);
  203. bool goingLeft = VirtualInput.IsButtonHeld(moveLeftBtn);
  204. bool goingRight = VirtualInput.IsButtonHeld(moveRightBtn);
  205. bool goingUp = VirtualInput.IsButtonHeld(moveUpBtn);
  206. bool goingDown = VirtualInput.IsButtonHeld(moveDownBtn);
  207. bool fastMove = VirtualInput.IsButtonHeld(fastMoveBtn);
  208. bool camActive = VirtualInput.IsButtonHeld(activeBtn);
  209. bool isPanning = VirtualInput.IsButtonHeld(panBtn);
  210. bool hideCursor = camActive || isPanning;
  211. if (hideCursor != lastHideCursorState)
  212. {
  213. if (hideCursor)
  214. {
  215. Cursor.Hide();
  216. Rect2I clipRect;
  217. clipRect.x = Input.PointerPosition.x - 2;
  218. clipRect.y = Input.PointerPosition.y - 2;
  219. clipRect.width = 4;
  220. clipRect.height = 4;
  221. Cursor.ClipToRect(clipRect);
  222. }
  223. else
  224. {
  225. Cursor.Show();
  226. Cursor.ClipDisable();
  227. }
  228. lastHideCursorState = hideCursor;
  229. }
  230. if (camActive)
  231. {
  232. float horzValue = VirtualInput.GetAxisValue(horizontalAxis);
  233. float vertValue = VirtualInput.GetAxisValue(verticalAxis);
  234. float rotationAmount = MoveSettings.rotationalSpeed * EditorSettings.MouseSensitivity;
  235. yaw += new Degree(horzValue * rotationAmount);
  236. pitch += new Degree(vertValue * rotationAmount);
  237. yaw = MathEx.WrapAngle(yaw);
  238. pitch = MathEx.WrapAngle(pitch);
  239. Quaternion yRot = Quaternion.FromAxisAngle(Vector3.YAxis, yaw);
  240. Quaternion xRot = Quaternion.FromAxisAngle(Vector3.XAxis, pitch);
  241. Quaternion camRot = yRot * xRot;
  242. camRot.Normalize();
  243. SceneObject.Rotation = camRot;
  244. // Handle movement using movement keys
  245. Vector3 direction = Vector3.Zero;
  246. if (goingForward) direction += SceneObject.Forward;
  247. if (goingBack) direction -= SceneObject.Forward;
  248. if (goingRight) direction += SceneObject.Right;
  249. if (goingLeft) direction -= SceneObject.Right;
  250. if (goingUp) direction += SceneObject.Up;
  251. if (goingDown) direction -= SceneObject.Up;
  252. if (direction.SqrdLength != 0)
  253. {
  254. direction.Normalize();
  255. float multiplier = 1.0f;
  256. if (fastMove)
  257. multiplier = MoveSettings.fastModeMultiplier;
  258. currentSpeed = MathEx.Clamp(currentSpeed + MoveSettings.acceleration * frameDelta, StartSpeed, TopSpeed);
  259. currentSpeed *= multiplier;
  260. }
  261. else
  262. {
  263. currentSpeed = 0.0f;
  264. }
  265. const float tooSmall = 0.0001f;
  266. if (currentSpeed > tooSmall)
  267. {
  268. Vector3 velocity = direction * currentSpeed;
  269. SceneObject.Move(velocity * frameDelta);
  270. }
  271. updated = true;
  272. }
  273. // Pan
  274. if (isPanning)
  275. {
  276. float horzValue = VirtualInput.GetAxisValue(horizontalAxis);
  277. float vertValue = VirtualInput.GetAxisValue(verticalAxis);
  278. Vector3 direction = new Vector3(horzValue, -vertValue, 0.0f);
  279. direction = camera.SceneObject.Rotation.Rotate(direction);
  280. SceneObject.Move(direction * MoveSettings.panSpeed * frameDelta);
  281. updated = true;
  282. }
  283. }
  284. else
  285. {
  286. if (lastHideCursorState)
  287. {
  288. Cursor.Show();
  289. Cursor.ClipDisable();
  290. lastHideCursorState = false;
  291. }
  292. }
  293. SceneWindow sceneWindow = EditorWindow.GetWindow<SceneWindow>();
  294. if ((sceneWindow.Active && sceneWindow.HasFocus) || sceneWindow.IsPointerHovering)
  295. {
  296. Rect2I bounds = sceneWindow.Bounds;
  297. // Move using scroll wheel
  298. if (bounds.Contains(Input.PointerPosition))
  299. {
  300. float scrollAmount = VirtualInput.GetAxisValue(scrollAxis);
  301. if(scrollAmount != 0)
  302. {
  303. if (!isOrthographic)
  304. {
  305. SceneObject.Move(SceneObject.Forward * scrollAmount * MoveSettings.scrollSpeed * frameDelta);
  306. }
  307. else
  308. {
  309. float oldOrthoHeight = camera.OrthoHeight;
  310. float orthoHeight = MathEx.Max(1.0f, oldOrthoHeight - scrollAmount * frameDelta);
  311. if (oldOrthoHeight != orthoHeight)
  312. camera.OrthoHeight = orthoHeight;
  313. }
  314. updated = true;
  315. }
  316. }
  317. }
  318. UpdateAnim();
  319. if (updated)
  320. {
  321. NotifyNeedsRedraw();
  322. UpdateCount++;
  323. }
  324. }
  325. /// <summary>
  326. /// Moves and orients a camera so that the provided bounds end covering the camera's viewport.
  327. /// </summary>
  328. /// <param name="bounds">Bounds to frame in camera's view.</param>
  329. /// <param name="padding">Amount of padding to leave on the borders of the viewport, in percent [0, 1].</param>
  330. private void FrameBounds(AABox bounds, float padding = 0.0f)
  331. {
  332. // TODO - Use AABox bounds directly instead of a sphere to be more accurate
  333. float worldWidth = bounds.Size.Length;
  334. float worldHeight = worldWidth;
  335. if (worldWidth == 0.0f)
  336. worldWidth = 1.0f;
  337. if (worldHeight == 0.0f)
  338. worldHeight = 1.0f;
  339. float boundsAspect = worldWidth / worldHeight;
  340. float paddingScale = MathEx.Clamp01(padding) + 1.0f;
  341. float frustumWidth;
  342. // If camera has wider aspect than bounds then height will be the limiting dimension
  343. if (camera.AspectRatio > boundsAspect)
  344. frustumWidth = worldHeight * camera.AspectRatio * paddingScale;
  345. else // Otherwise width
  346. frustumWidth = worldWidth * paddingScale;
  347. float distance = CalcDistanceForFrustumWidth(frustumWidth);
  348. Vector3 forward = bounds.Center - SceneObject.Position;
  349. forward.Normalize();
  350. GetNearFarForDistance(distance, out var near, out var far);
  351. viewSettings.nearClipPlane = near;
  352. viewSettings.farClipPlane = far;
  353. ProjectSettings.SetObject(ViewSettingsKey, viewSettings);
  354. CameraState state = new CameraState();
  355. state.Position = bounds.Center - forward * distance;
  356. state.Rotation = Quaternion.LookRotation(forward, Vector3.YAxis);
  357. state.Orthographic = camera.ProjectionType == ProjectionType.Orthographic;
  358. state.FrustumWidth = frustumWidth;
  359. SetState(state);
  360. }
  361. /// <summary>
  362. /// Changes the state of the camera, either instantly or animated over several frames. The state includes
  363. /// camera position, rotation, type and possibly other parameters.
  364. /// </summary>
  365. /// <param name="state">New state of the camera.</param>
  366. /// <param name="animated">Should the state be linearly interpolated over a course of several frames.</param>
  367. private void SetState(CameraState state, bool animated = true)
  368. {
  369. CameraState startState = new CameraState();
  370. startState.Position = SceneObject.Position;
  371. startState.Rotation = SceneObject.Rotation;
  372. startState.Orthographic = camera.ProjectionType == ProjectionType.Orthographic;
  373. startState.FrustumWidth = frustumWidth;
  374. animation.Start(startState, state);
  375. if (!animated)
  376. {
  377. ApplyState(1.0f);
  378. isAnimating = false;
  379. }
  380. else
  381. {
  382. isAnimating = true;
  383. lerp = 0.0f;
  384. }
  385. }
  386. /// <summary>
  387. /// Applies the animation target state depending on the interpolation parameter. <see cref="SetState"/>.
  388. /// </summary>
  389. /// <param name="t">Interpolation parameter ranging [0, 1] that interpolated between the start state and the
  390. /// target state.</param>
  391. private void ApplyState(float t)
  392. {
  393. animation.Update(t);
  394. SceneObject.Position = animation.State.Position;
  395. SceneObject.Rotation = animation.State.Rotation;
  396. frustumWidth = animation.State.FrustumWidth;
  397. Vector3 eulerAngles = SceneObject.Rotation.ToEuler();
  398. pitch = (Degree)eulerAngles.x;
  399. yaw = (Degree)eulerAngles.y;
  400. Degree FOV = (Degree)(1.0f - animation.State.OrthographicPct) * viewSettings.fieldOfView;
  401. if (FOV < (Degree)5.0f)
  402. {
  403. camera.ProjectionType = ProjectionType.Orthographic;
  404. camera.OrthoHeight = frustumWidth * 0.5f / camera.AspectRatio;
  405. }
  406. else
  407. {
  408. camera.ProjectionType = ProjectionType.Perspective;
  409. camera.FieldOfView = FOV;
  410. }
  411. // Note: Consider having a global setting for near/far planes as changing it here might confuse the user
  412. float distance = CalcDistanceForFrustumWidth(frustumWidth);
  413. GetNearFarForDistance(distance, out var near, out var far);
  414. camera.NearClipPlane = near;
  415. camera.FarClipPlane = far;
  416. NotifyNeedsRedraw();
  417. UpdateCount++;
  418. }
  419. /// <summary>
  420. /// Calculates distance at which the camera's frustum width is equal to the provided width.
  421. /// </summary>
  422. /// <param name="frustumWidth">Frustum width to find the distance for, in world units.</param>
  423. /// <returns>Distance at which the camera's frustum is the specified width, in world units.</returns>
  424. private float CalcDistanceForFrustumWidth(float frustumWidth)
  425. {
  426. if (camera.ProjectionType == ProjectionType.Perspective)
  427. return (frustumWidth * 0.5f) / MathEx.Tan(camera.FieldOfView * 0.5f);
  428. else
  429. return frustumWidth * 2.0f;
  430. }
  431. /// <summary>
  432. /// Updates camera state transition animation. Should be called every frame.
  433. /// </summary>
  434. private void UpdateAnim()
  435. {
  436. if (!isAnimating)
  437. return;
  438. const float ANIM_TIME = 0.5f; // 0.5f seconds
  439. lerp += Time.FrameDelta * (1.0f / ANIM_TIME);
  440. if (lerp >= 1.0f)
  441. {
  442. lerp = 1.0f;
  443. isAnimating = false;
  444. }
  445. ApplyState(lerp);
  446. }
  447. /// <summary>
  448. /// Calculates the camera near and far plane distances used for looking at an object certain distance from the
  449. /// camera.
  450. /// </summary>
  451. /// <param name="distance">Distance of the object from the camera.</param>
  452. /// <param name="near">Output near plane distance.</param>
  453. /// <param name="far">Output far plane distance.</param>
  454. private static void GetNearFarForDistance(float distance, out float near, out float far)
  455. {
  456. if (distance < 1)
  457. {
  458. near = 0.005f;
  459. far = 1000f;
  460. }
  461. if (distance < 100)
  462. {
  463. near = 0.05f;
  464. far = 2500f;
  465. }
  466. else if (distance < 1000)
  467. {
  468. near = 0.5f;
  469. far = 10000f;
  470. }
  471. else
  472. {
  473. near = 5.0f;
  474. far = 1000000f;
  475. }
  476. }
  477. /// <summary>
  478. /// Contains data for a possible camera state. Camera states can be interpolated between each other as needed.
  479. /// </summary>
  480. private struct CameraState
  481. {
  482. private float _orthographic;
  483. public Vector3 Position { get; set; }
  484. public Quaternion Rotation { get; set; }
  485. public float FrustumWidth { get; set; }
  486. public bool Orthographic
  487. {
  488. get { return _orthographic > 0.5; }
  489. set { _orthographic = value ? 1.0f : 0.0f; }
  490. }
  491. public float OrthographicPct
  492. {
  493. get { return _orthographic; }
  494. set { _orthographic = value; }
  495. }
  496. }
  497. /// <summary>
  498. /// Helper class that performs linear interpolation between two camera states.
  499. /// </summary>
  500. private struct CameraAnimation
  501. {
  502. private CameraState start;
  503. private CameraState target;
  504. private CameraState interpolated;
  505. /// <summary>
  506. /// Returns currently interpolated animation state.
  507. /// </summary>
  508. public CameraState State
  509. {
  510. get { return interpolated; }
  511. }
  512. /// <summary>
  513. /// Initializes the animation with initial and target states.
  514. /// </summary>
  515. /// <param name="start">Initial state to animate from.</param>
  516. /// <param name="target">Target state to animate towards.</param>
  517. public void Start(CameraState start, CameraState target)
  518. {
  519. this.start = start;
  520. this.target = target;
  521. }
  522. /// <summary>
  523. /// Updates the animation by interpolating between the start and target states.
  524. /// </summary>
  525. /// <param name="t">Interpolation parameter in range [0, 1] that determines how much to interpolate between
  526. /// start and target states.</param>
  527. public void Update(float t)
  528. {
  529. interpolated = new CameraState();
  530. interpolated.Position = start.Position * (1.0f - t) + target.Position * t;
  531. interpolated.Rotation = Quaternion.Slerp(start.Rotation, target.Rotation, t);
  532. interpolated.OrthographicPct = start.OrthographicPct * (1.0f - t) + target.OrthographicPct * t;
  533. interpolated.FrustumWidth = start.FrustumWidth * (1.0f - t) + target.FrustumWidth * t;
  534. }
  535. };
  536. #endregion
  537. }
  538. /// <summary>
  539. /// Contains properties used for controlling scene camera movement.
  540. /// </summary>
  541. [SerializeObject]
  542. internal class SceneCameraMoveSettings
  543. {
  544. [Range(0.1f, 10.0f)]
  545. public float acceleration = 1.0f;
  546. [Range(1.0f, 10.0f)]
  547. public float fastModeMultiplier = 2.0f;
  548. [Range(0.1f, 10.0f)]
  549. public float panSpeed = 3.0f;
  550. [Range(0.1f, 3.0f)]
  551. public float scrollSpeed = 3.0f;
  552. [Range(0.1f, 10.0f)]
  553. public float rotationalSpeed = 3.0f;
  554. }
  555. /// <summary>
  556. /// Contains properties used for controlling scene camera view.
  557. /// </summary>
  558. [SerializeObject]
  559. internal class SceneCameraViewSettings
  560. {
  561. public ProjectionType projectionType = ProjectionType.Perspective;
  562. [Range(10.0f, 170.0f, false)]
  563. public Degree fieldOfView = new Degree(90.0f);
  564. [Range(0.001f, 10000.0f, false)]
  565. public float orthographicSize = 10.0f;
  566. [Range(0.0001f, 10, false)]
  567. public float nearClipPlane = 0.05f;
  568. [Range(1.0f, 100000.0f, false)]
  569. public float farClipPlane = 2500.0f;
  570. public Color backgroundColor = new Color(0.282f, 0.341f, 0.478f);
  571. }
  572. /** @} */
  573. }