ChaseCamera.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // ChaseCamera.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.Collections.Generic;
  12. using Microsoft.Xna.Framework;
  13. #endregion
  14. namespace ChaseCameraSample
  15. {
  16. public class ChaseCamera
  17. {
  18. #region Chased object properties (set externally each frame)
  19. /// <summary>
  20. /// Position of object being chased.
  21. /// </summary>
  22. public Vector3 ChasePosition
  23. {
  24. get { return chasePosition; }
  25. set { chasePosition = value; }
  26. }
  27. private Vector3 chasePosition;
  28. /// <summary>
  29. /// Direction the chased object is facing.
  30. /// </summary>
  31. public Vector3 ChaseDirection
  32. {
  33. get { return chaseDirection; }
  34. set { chaseDirection = value; }
  35. }
  36. private Vector3 chaseDirection;
  37. /// <summary>
  38. /// Chased object's Up vector.
  39. /// </summary>
  40. public Vector3 Up
  41. {
  42. get { return up; }
  43. set { up = value; }
  44. }
  45. private Vector3 up = Vector3.Up;
  46. #endregion
  47. #region Desired camera positioning (set when creating camera or changing view)
  48. /// <summary>
  49. /// Desired camera position in the chased object's coordinate system.
  50. /// </summary>
  51. public Vector3 DesiredPositionOffset
  52. {
  53. get { return desiredPositionOffset; }
  54. set { desiredPositionOffset = value; }
  55. }
  56. private Vector3 desiredPositionOffset = new Vector3(0, 2.0f, 2.0f);
  57. /// <summary>
  58. /// Desired camera position in world space.
  59. /// </summary>
  60. public Vector3 DesiredPosition
  61. {
  62. get
  63. {
  64. // Ensure correct value even if update has not been called this frame
  65. UpdateWorldPositions();
  66. return desiredPosition;
  67. }
  68. }
  69. private Vector3 desiredPosition;
  70. /// <summary>
  71. /// Look at point in the chased object's coordinate system.
  72. /// </summary>
  73. public Vector3 LookAtOffset
  74. {
  75. get { return lookAtOffset; }
  76. set { lookAtOffset = value; }
  77. }
  78. private Vector3 lookAtOffset = new Vector3(0, 2.8f, 0);
  79. /// <summary>
  80. /// Look at point in world space.
  81. /// </summary>
  82. public Vector3 LookAt
  83. {
  84. get
  85. {
  86. // Ensure correct value even if update has not been called this frame
  87. UpdateWorldPositions();
  88. return lookAt;
  89. }
  90. }
  91. private Vector3 lookAt;
  92. #endregion
  93. #region Camera physics (typically set when creating camera)
  94. /// <summary>
  95. /// Physics coefficient which controls the influence of the camera's position
  96. /// over the spring force. The stiffer the spring, the closer it will stay to
  97. /// the chased object.
  98. /// </summary>
  99. public float Stiffness
  100. {
  101. get { return stiffness; }
  102. set { stiffness = value; }
  103. }
  104. private float stiffness = 1800.0f;
  105. /// <summary>
  106. /// Physics coefficient which approximates internal friction of the spring.
  107. /// Sufficient damping will prevent the spring from oscillating infinitely.
  108. /// </summary>
  109. public float Damping
  110. {
  111. get { return damping; }
  112. set { damping = value; }
  113. }
  114. private float damping = 600.0f;
  115. /// <summary>
  116. /// Mass of the camera body. Heaver objects require stiffer springs with less
  117. /// damping to move at the same rate as lighter objects.
  118. /// </summary>
  119. public float Mass
  120. {
  121. get { return mass; }
  122. set { mass = value; }
  123. }
  124. private float mass = 50.0f;
  125. #endregion
  126. #region Current camera properties (updated by camera physics)
  127. /// <summary>
  128. /// Position of camera in world space.
  129. /// </summary>
  130. public Vector3 Position
  131. {
  132. get { return position; }
  133. }
  134. private Vector3 position;
  135. /// <summary>
  136. /// Velocity of camera.
  137. /// </summary>
  138. public Vector3 Velocity
  139. {
  140. get { return velocity; }
  141. }
  142. private Vector3 velocity;
  143. #endregion
  144. #region Perspective properties
  145. /// <summary>
  146. /// Perspective aspect ratio. Default value should be overriden by application.
  147. /// </summary>
  148. public float AspectRatio
  149. {
  150. get { return aspectRatio; }
  151. set { aspectRatio = value; }
  152. }
  153. private float aspectRatio = 4.0f / 3.0f;
  154. /// <summary>
  155. /// Perspective field of view.
  156. /// </summary>
  157. public float FieldOfView
  158. {
  159. get { return fieldOfView; }
  160. set { fieldOfView = value; }
  161. }
  162. private float fieldOfView = MathHelper.ToRadians(45.0f);
  163. /// <summary>
  164. /// Distance to the near clipping plane.
  165. /// </summary>
  166. public float NearPlaneDistance
  167. {
  168. get { return nearPlaneDistance; }
  169. set { nearPlaneDistance = value; }
  170. }
  171. private float nearPlaneDistance = 1.0f;
  172. /// <summary>
  173. /// Distance to the far clipping plane.
  174. /// </summary>
  175. public float FarPlaneDistance
  176. {
  177. get { return farPlaneDistance; }
  178. set { farPlaneDistance = value; }
  179. }
  180. private float farPlaneDistance = 100000.0f;
  181. #endregion
  182. #region Matrix properties
  183. /// <summary>
  184. /// View transform matrix.
  185. /// </summary>
  186. public Matrix View
  187. {
  188. get { return view; }
  189. }
  190. private Matrix view;
  191. /// <summary>
  192. /// Projecton transform matrix.
  193. /// </summary>
  194. public Matrix Projection
  195. {
  196. get { return projection; }
  197. }
  198. private Matrix projection;
  199. #endregion
  200. #region Methods
  201. /// <summary>
  202. /// Rebuilds object space values in world space. Invoke before publicly
  203. /// returning or privately accessing world space values.
  204. /// </summary>
  205. private void UpdateWorldPositions()
  206. {
  207. // Construct a matrix to transform from object space to worldspace
  208. Matrix transform = Matrix.Identity;
  209. transform.Forward = ChaseDirection;
  210. transform.Up = Up;
  211. transform.Right = Vector3.Cross(Up, ChaseDirection);
  212. // Calculate desired camera properties in world space
  213. desiredPosition = ChasePosition +
  214. Vector3.TransformNormal(DesiredPositionOffset, transform);
  215. lookAt = ChasePosition +
  216. Vector3.TransformNormal(LookAtOffset, transform);
  217. }
  218. /// <summary>
  219. /// Rebuilds camera's view and projection matricies.
  220. /// </summary>
  221. private void UpdateMatrices()
  222. {
  223. view = Matrix.CreateLookAt(this.Position, this.LookAt, this.Up);
  224. projection = Matrix.CreatePerspectiveFieldOfView(FieldOfView,
  225. AspectRatio, NearPlaneDistance, FarPlaneDistance);
  226. }
  227. /// <summary>
  228. /// Forces camera to be at desired position and to stop moving. The is useful
  229. /// when the chased object is first created or after it has been teleported.
  230. /// Failing to call this after a large change to the chased object's position
  231. /// will result in the camera quickly flying across the world.
  232. /// </summary>
  233. public void Reset()
  234. {
  235. UpdateWorldPositions();
  236. // Stop motion
  237. velocity = Vector3.Zero;
  238. // Force desired position
  239. position = desiredPosition;
  240. UpdateMatrices();
  241. }
  242. /// <summary>
  243. /// Animates the camera from its current position towards the desired offset
  244. /// behind the chased object. The camera's animation is controlled by a simple
  245. /// physical spring attached to the camera and anchored to the desired position.
  246. /// </summary>
  247. public void Update(GameTime gameTime)
  248. {
  249. if (gameTime == null)
  250. throw new ArgumentNullException("gameTime");
  251. UpdateWorldPositions();
  252. float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
  253. // Calculate spring force
  254. Vector3 stretch = position - desiredPosition;
  255. Vector3 force = -stiffness * stretch - damping * velocity;
  256. // Apply acceleration
  257. Vector3 acceleration = force / mass;
  258. velocity += acceleration * elapsed;
  259. // Apply velocity
  260. position += velocity * elapsed;
  261. UpdateMatrices();
  262. }
  263. #endregion
  264. }
  265. }