#region File Description //----------------------------------------------------------------------------- // A class containing all the basic transformations a renderable object can have. // This include: Translation, Rotation, and Scale. // // Author: Ronen Ness. // Since: 2017. //----------------------------------------------------------------------------- #endregion using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace MonoGameSceneGraph { /// /// MonoGameSceneGraph is the main namespace that contains all the MonoGame-SceneGraph entities. /// [System.Runtime.CompilerServices.CompilerGenerated] class NamespaceDoc { } /// /// How to apply rotation (euler vs quaternion). /// public enum RotationType { /// /// Euler rotation. /// Euler, /// /// Quaternion rotation. /// Quaternion, } /// /// Different way to build matrix from transformations. /// public enum TransformOrder { /// /// Apply position, then rotation, then scale. /// PositionRotationScale, /// /// Apply position, then scale, then rotation. /// PositionScaleRotation, /// /// Apply scale, then position, then rotation. /// ScalePositionRotation, /// /// Apply scale, then rotation, then position. /// ScaleRotationPosition, /// /// Apply rotation, then scale, then position. /// RotationScalePosition, /// /// Apply rotation, then position, then scale. /// RotationPositionScale, } /// /// Different ways to apply rotation (order in which we rotate the different axis). /// public enum RotationOrder { /// /// Rotate by axis order X, Y, Z. /// RotateXYZ, /// /// Rotate by axis order X, Z, Y. /// RotateXZY, /// /// Rotate by axis order Y, X, Z. /// RotateYXZ, /// /// Rotate by axis order Y, Z, X. /// RotateYZX, /// /// Rotate by axis order Z, X, Y. /// RotateZXY, /// /// Rotate by axis order Z, Y, X. /// RotateZYX, } /// /// Contain all the possible node transformations. /// public class Transformations { /// /// Node position / translation. /// public Vector3 Position; /// /// Node rotation. /// public Vector3 Rotation; /// /// Node scale. /// public Vector3 Scale; /// /// Order to apply different transformations to create the final matrix. /// public TransformOrder TransformOrder = TransformOrder.ScaleRotationPosition; /// /// Axis order to apply rotation. /// public RotationOrder RotationOrder = RotationOrder.RotateYXZ; /// /// What type of rotation to use. /// public RotationType RotationType = RotationType.Quaternion; /// /// Create new default transformations. /// public Transformations() { Position = Vector3.Zero; Rotation = Vector3.Zero; Scale = Vector3.One; } /// /// Clone transformations. /// public Transformations(Transformations other) { Position = other.Position; Rotation = other.Rotation; Scale = other.Scale; TransformOrder = other.TransformOrder; RotationOrder = other.RotationOrder; RotationType = other.RotationType; } /// /// Clone transformations. /// /// Copy of this transformations. public Transformations Clone() { return new Transformations(this); } /// /// Build and return just the rotation matrix for this treansformations. /// /// Rotation matrix. public Matrix BuildRotationMatrix() { // handle euler rotation if (RotationType == RotationType.Euler) { switch (RotationOrder) { case RotationOrder.RotateXYZ: return Matrix.CreateRotationX(Rotation.X) * Matrix.CreateRotationY(Rotation.Y) * Matrix.CreateRotationZ(Rotation.Z); case RotationOrder.RotateXZY: return Matrix.CreateRotationX(Rotation.X) * Matrix.CreateRotationZ(Rotation.Z) * Matrix.CreateRotationY(Rotation.Y); case RotationOrder.RotateYXZ: return Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z); case RotationOrder.RotateYZX: return Matrix.CreateRotationY(Rotation.Y) * Matrix.CreateRotationZ(Rotation.Z) * Matrix.CreateRotationX(Rotation.X); case RotationOrder.RotateZXY: return Matrix.CreateRotationZ(Rotation.Z) * Matrix.CreateRotationX(Rotation.X) * Matrix.CreateRotationY(Rotation.Y); case RotationOrder.RotateZYX: return Matrix.CreateRotationZ(Rotation.Z) * Matrix.CreateRotationY(Rotation.Y) * Matrix.CreateRotationX(Rotation.X); default: throw new System.Exception("Unknown rotation order!"); } } // handle quaternion rotation else if (RotationType == RotationType.Quaternion) { // quaternion to use Quaternion quat; // build quaternion based on rotation order switch (RotationOrder) { case RotationOrder.RotateXYZ: quat = Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z); break; case RotationOrder.RotateXZY: quat = Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y); break; case RotationOrder.RotateYXZ: quat = Quaternion.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z); break; case RotationOrder.RotateYZX: quat = Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X); break; case RotationOrder.RotateZXY: quat = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y); break; case RotationOrder.RotateZYX: quat = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, Rotation.Z) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, Rotation.Y) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, Rotation.X); break; default: throw new System.Exception("Unknown rotation order!"); } // convert to a matrix and return return Matrix.CreateFromQuaternion(quat); } // should never happen. else { throw new System.Exception("Unknown rotation type!"); } } /// /// Build and return a matrix from current transformations. /// /// Matrix with all transformations applied. public Matrix BuildMatrix() { // create the matrix parts Matrix pos = Matrix.CreateTranslation(Position); Matrix rot = BuildRotationMatrix(); Matrix scale = Matrix.CreateScale(Scale); // build and return matrix based on order switch (TransformOrder) { case TransformOrder.PositionRotationScale: return pos * rot * scale; case TransformOrder.PositionScaleRotation: return pos * scale * rot; case TransformOrder.ScalePositionRotation: return scale * pos * rot; case TransformOrder.ScaleRotationPosition: return scale * rot * pos; case TransformOrder.RotationScalePosition: return rot * scale * pos; case TransformOrder.RotationPositionScale: return rot * pos * scale; default: throw new System.Exception("Unknown build matrix order!"); } } } }