Transformations.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // A class containing all the basic transformations a renderable object can have.
  4. // This include: Translation, Rotation, and Scale.
  5. //
  6. // Author: Ronen Ness.
  7. // Since: 2017.
  8. //-----------------------------------------------------------------------------
  9. #endregion
  10. using Microsoft.Xna.Framework;
  11. using Microsoft.Xna.Framework.Graphics;
  12. namespace MonoGameSceneGraph
  13. {
  14. /// <summary>
  15. /// MonoGameSceneGraph is the main namespace that contains all the MonoGame-SceneGraph entities.
  16. /// </summary>
  17. [System.Runtime.CompilerServices.CompilerGenerated]
  18. class NamespaceDoc
  19. {
  20. }
  21. /// <summary>
  22. /// How to apply rotation (euler vs quaternion).
  23. /// </summary>
  24. public enum RotationType
  25. {
  26. /// <summary>
  27. /// Euler rotation.
  28. /// </summary>
  29. Euler,
  30. /// <summary>
  31. /// Quaternion rotation.
  32. /// </summary>
  33. Quaternion,
  34. }
  35. /// <summary>
  36. /// Different way to build matrix from transformations.
  37. /// </summary>
  38. public enum TransformOrder
  39. {
  40. /// <summary>
  41. /// Apply position, then rotation, then scale.
  42. /// </summary>
  43. PositionRotationScale,
  44. /// <summary>
  45. /// Apply position, then scale, then rotation.
  46. /// </summary>
  47. PositionScaleRotation,
  48. /// <summary>
  49. /// Apply scale, then position, then rotation.
  50. /// </summary>
  51. ScalePositionRotation,
  52. /// <summary>
  53. /// Apply scale, then rotation, then position.
  54. /// </summary>
  55. ScaleRotationPosition,
  56. /// <summary>
  57. /// Apply rotation, then scale, then position.
  58. /// </summary>
  59. RotationScalePosition,
  60. /// <summary>
  61. /// Apply rotation, then position, then scale.
  62. /// </summary>
  63. RotationPositionScale,
  64. }
  65. /// <summary>
  66. /// Different ways to apply rotation (order in which we rotate the different axis).
  67. /// </summary>
  68. public enum RotationOrder
  69. {
  70. /// <summary>
  71. /// Rotate by axis order X, Y, Z.
  72. /// </summary>
  73. RotateXYZ,
  74. /// <summary>
  75. /// Rotate by axis order X, Z, Y.
  76. /// </summary>
  77. RotateXZY,
  78. /// <summary>
  79. /// Rotate by axis order Y, X, Z.
  80. /// </summary>
  81. RotateYXZ,
  82. /// <summary>
  83. /// Rotate by axis order Y, Z, X.
  84. /// </summary>
  85. RotateYZX,
  86. /// <summary>
  87. /// Rotate by axis order Z, X, Y.
  88. /// </summary>
  89. RotateZXY,
  90. /// <summary>
  91. /// Rotate by axis order Z, Y, X.
  92. /// </summary>
  93. RotateZYX,
  94. }
  95. /// <summary>
  96. /// Contain all the possible node transformations.
  97. /// </summary>
  98. public class Transformations
  99. {
  100. /// <summary>
  101. /// Node position / translation.
  102. /// </summary>
  103. public Vector3 Position;
  104. /// <summary>
  105. /// Node rotation.
  106. /// </summary>
  107. public Vector3 Rotation;
  108. /// <summary>
  109. /// Node scale.
  110. /// </summary>
  111. public Vector3 Scale;
  112. /// <summary>
  113. /// Order to apply different transformations to create the final matrix.
  114. /// </summary>
  115. public TransformOrder TransformOrder = TransformOrder.ScaleRotationPosition;
  116. /// <summary>
  117. /// Axis order to apply rotation.
  118. /// </summary>
  119. public RotationOrder RotationOrder = RotationOrder.RotateYXZ;
  120. /// <summary>
  121. /// What type of rotation to use.
  122. /// </summary>
  123. public RotationType RotationType = RotationType.Quaternion;
  124. /// <summary>
  125. /// Create new default transformations.
  126. /// </summary>
  127. public Transformations()
  128. {
  129. Position = Vector3.Zero;
  130. Rotation = Vector3.Zero;
  131. Scale = Vector3.One;
  132. }
  133. /// <summary>
  134. /// Clone transformations.
  135. /// </summary>
  136. public Transformations(Transformations other)
  137. {
  138. Position = other.Position;
  139. Rotation = other.Rotation;
  140. Scale = other.Scale;
  141. TransformOrder = other.TransformOrder;
  142. RotationOrder = other.RotationOrder;
  143. RotationType = other.RotationType;
  144. }
  145. /// <summary>
  146. /// Clone transformations.
  147. /// </summary>
  148. /// <returns>Copy of this transformations.</returns>
  149. public Transformations Clone()
  150. {
  151. return new Transformations(this);
  152. }
  153. /// <summary>
  154. /// Build and return just the rotation matrix for this treansformations.
  155. /// </summary>
  156. /// <returns>Rotation matrix.</returns>
  157. public Matrix BuildRotationMatrix()
  158. {
  159. // handle euler rotation
  160. if (RotationType == RotationType.Euler)
  161. {
  162. switch (RotationOrder)
  163. {
  164. case RotationOrder.RotateXYZ:
  165. return Matrix.CreateRotationX(Rotation.X) * Matrix.CreateRotationY(Rotation.Y) * Matrix.CreateRotationZ(Rotation.Z);
  166. case RotationOrder.RotateXZY:
  167. return Matrix.CreateRotationX(Rotation.X) * Matrix.CreateRotationZ(Rotation.Z) * Matrix.CreateRotationY(Rotation.Y);
  168. case RotationOrder.RotateYXZ:
  169. return Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z);
  170. case RotationOrder.RotateYZX:
  171. return Matrix.CreateRotationY(Rotation.Y) * Matrix.CreateRotationZ(Rotation.Z) * Matrix.CreateRotationX(Rotation.X);
  172. case RotationOrder.RotateZXY:
  173. return Matrix.CreateRotationZ(Rotation.Z) * Matrix.CreateRotationX(Rotation.X) * Matrix.CreateRotationY(Rotation.Y);
  174. case RotationOrder.RotateZYX:
  175. return Matrix.CreateRotationZ(Rotation.Z) * Matrix.CreateRotationY(Rotation.Y) * Matrix.CreateRotationX(Rotation.X);
  176. default:
  177. throw new System.Exception("Unknown rotation order!");
  178. }
  179. }
  180. // handle quaternion rotation
  181. else if (RotationType == RotationType.Quaternion)
  182. {
  183. // quaternion to use
  184. Quaternion quat;
  185. // build quaternion based on rotation order
  186. switch (RotationOrder)
  187. {
  188. case RotationOrder.RotateXYZ:
  189. quat = Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z);
  190. break;
  191. case RotationOrder.RotateXZY:
  192. quat = Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y);
  193. break;
  194. case RotationOrder.RotateYXZ:
  195. quat = Quaternion.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z);
  196. break;
  197. case RotationOrder.RotateYZX:
  198. quat = Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X);
  199. break;
  200. case RotationOrder.RotateZXY:
  201. quat = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y);
  202. break;
  203. case RotationOrder.RotateZYX:
  204. quat = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X);
  205. break;
  206. default:
  207. throw new System.Exception("Unknown rotation order!");
  208. }
  209. // convert to a matrix and return
  210. return Matrix.CreateFromQuaternion(quat);
  211. }
  212. // should never happen.
  213. else
  214. {
  215. throw new System.Exception("Unknown rotation type!");
  216. }
  217. }
  218. /// <summary>
  219. /// Build and return a matrix from current transformations.
  220. /// </summary>
  221. /// <returns>Matrix with all transformations applied.</returns>
  222. public Matrix BuildMatrix()
  223. {
  224. // create the matrix parts
  225. Matrix pos = Matrix.CreateTranslation(Position);
  226. Matrix rot = BuildRotationMatrix();
  227. Matrix scale = Matrix.CreateScale(Scale);
  228. // build and return matrix based on order
  229. switch (TransformOrder)
  230. {
  231. case TransformOrder.PositionRotationScale:
  232. return pos * rot * scale;
  233. case TransformOrder.PositionScaleRotation:
  234. return pos * scale * rot;
  235. case TransformOrder.ScalePositionRotation:
  236. return scale * pos * rot;
  237. case TransformOrder.ScaleRotationPosition:
  238. return scale * rot * pos;
  239. case TransformOrder.RotationScalePosition:
  240. return rot * scale * pos;
  241. case TransformOrder.RotationPositionScale:
  242. return rot * pos * scale;
  243. default:
  244. throw new System.Exception("Unknown build matrix order!");
  245. }
  246. }
  247. }
  248. }