/// /// Euler rotation axis order. /// public enum EulerRotateOrder { XYZ, XZY, YXZ, YZX, ZXY, ZYX } /// /// The transform node uses the XNA matrix struct to create /// cumulative similarity transforms. This class provides a /// variety of encapsulators to manipulate these transforms. /// public class TransformNode : SceneItem { /// /// the ratio that converts radians to degrees /// public const float RADIANS_TO_DEGREES = 57.2957795f; /// /// the ratio that converts degrees to radians /// public const float DEGREES_TO_RADIANS = 0.0174532925f; /// /// the transformation matrix added in the /// hierarchy by this TransformNode /// protected Matrix mTransformation; /// /// the transformation added by the /// parent of this node /// protected Matrix mParentMatrix; //current translation protected EulerRotateOrder rotateOrder; //euler rotaion order protected Vector3 curRotation; //current rotation protected Vector3 curScale; //current scale //individual transformations protected Matrix translateMat; //translation matrix protected Matrix rotateMat; //rotation matrix protected Matrix scaleMat; //scale matrix /// /// constructor to initialze the transform node with /// the given name and rotation order /// /// the euler rotation order public TransformNode(EulerRotateOrder newOrder) : base() { rotateOrder = newOrder; init(); } /// /// constructor to initialze the transform node with the /// given name and the specified transformation /// /// new translate offset /// new rotation (X,Y,Z indicate offset from 0 measured in radians) /// new scale factor (no scale is (1,1,1) /// new euler rotation order public TransformNode(Vector3 newTranslate, Vector3 newRotate, Vector3 newScale, EulerRotateOrder newOrder) : base() { rotateOrder = newOrder; curRotation = newRotate; curScale = newScale; translateMat = Matrix.CreateTranslation(newTranslate); scaleMat = Matrix.CreateScale(curScale); mTransformation = Matrix.Identity; //local transform updateRotation(); } /// /// sets this transformation matrix to be the identity matrix /// private void init() { curRotation = Vector3.Zero; curScale = Vector3.One; //initialize to having no transformation mTransformation = Matrix.Identity; translateMat = Matrix.Identity; rotateMat = Matrix.Identity; scaleMat = Matrix.Identity; } /* * UPDATE TRANSFORMATIONS */ /// /// update rotation using the Euler transforms /// protected virtual void updateRotation() { switch (rotateOrder) { case EulerRotateOrder.XYZ: rotateMat = Matrix.CreateRotationX(curRotation.X) * Matrix.CreateRotationY(curRotation.Y) * Matrix.CreateRotationZ(curRotation.Z); break; case EulerRotateOrder.XZY: rotateMat = Matrix.CreateRotationX(curRotation.X) * Matrix.CreateRotationZ(curRotation.Z) * Matrix.CreateRotationY(curRotation.Y); break; case EulerRotateOrder.YXZ: rotateMat = Matrix.CreateRotationY(curRotation.Y) * Matrix.CreateRotationX(curRotation.X) * Matrix.CreateRotationZ(curRotation.Z); break; case EulerRotateOrder.YZX: rotateMat = Matrix.CreateRotationY(curRotation.Y) * Matrix.CreateRotationZ(curRotation.Z) * Matrix.CreateRotationX(curRotation.X); break; case EulerRotateOrder.ZXY: rotateMat = Matrix.CreateRotationZ(curRotation.Z) * Matrix.CreateRotationX(curRotation.X) * Matrix.CreateRotationY(curRotation.Y); break; case EulerRotateOrder.ZYX: rotateMat = Matrix.CreateRotationZ(curRotation.Z) * Matrix.CreateRotationY(curRotation.Y) * Matrix.CreateRotationX(curRotation.X); break; } updateTranformation(); } /// /// update the local transform matrix by combining the scale, rotation and translation matrices /// protected void updateTranformation() { //remove identity matrix from transformation product mTransformation = scaleMat * rotateMat * translateMat; updateCumulative(); } /// /// gets the cumulative transformation matrix /// for this transform node /// public Matrix Transformation { get { return mTransformation; } } /// /// sets the world matrix of all child nodes to be /// Transformation * ParentMatrix /// private void updateCumulative() { base.WorldMatrix = mTransformation * mParentMatrix; } /// /// gets / sets the world transformation matrix /// /// set the world matrix is really only setting /// the ParentMatrix property of the TransformNode. Children /// of this node will receive the cumulative world matrix of /// Transformation * ParentMatrix public override Matrix WorldMatrix { get { return base.WorldMatrix; } set { mParentMatrix = value; updateCumulative(); } } /* * RESET TRANSFORMATIONS */ /// /// reset to no translation /// public void resetTranslate() { translateMat = Matrix.Identity; updateTranformation(); } /// /// reset to no rotation /// public void resetRotate() { curRotation = Vector3.Zero; rotateMat = Matrix.Identity; updateTranformation(); } /// /// reset to no scaling /// public void resetScale() { curScale = Vector3.One; scaleMat = Matrix.Identity; updateTranformation(); } /* * TRANSLATION */ /// /// offset translation by specified vector /// /// amout to translate the transformation public void Translate(Vector3 translate) { translateMat = Matrix.CreateTranslation(translateMat.Translation + translate); updateTranformation(); } /// /// alternate name for position /// public Vector3 Translation { get { return this.Position; } set { this.Position = value; } } /// /// get / sets the position from /// the origin of this node /// /// public Vector3 Position { get { return translateMat.Translation; } set { translateMat = Matrix.CreateTranslation(value); updateTranformation(); } } /// /// gets or sets the X translation of /// this transform node /// public float X { get { return translateMat.Translation.X; } set { translateMat = Matrix.CreateTranslation(new Vector3(value, translateMat.Translation.Y, translateMat.Translation.Z)); updateTranformation(); } } /// /// gets or sets the Y translation of this transform node /// public float Y { get { return translateMat.Translation.Y; } set { translateMat = Matrix.CreateTranslation(new Vector3(translateMat.Translation.X, value, translateMat.Translation.Z)); updateTranformation(); } } /// /// gets or sets the Z translation of this transform node /// public float Z { get { return translateMat.Translation.Z; } set { translateMat = Matrix.CreateTranslation(new Vector3(translateMat.Translation.X, translateMat.Translation.Y, value)); updateTranformation(); } } /* * ROTATIONS */ /// /// offset rotation of node around X,Y, and Z axis /// using a standard Euler transformation /// /// public virtual void Rotate(Vector3 rad) { curRotation = curRotation + rad; updateRotation(); } /// /// rotates around the X axis by the /// specified number of radians /// /// public virtual void RotateX(float rad) { curRotation.X += rad; updateRotation(); } /// /// rotates around the Y axis by the /// specified number of radians /// /// public virtual void RotateY(float rad) { curRotation.Y += rad; updateRotation(); } /// /// rotates around the Z axis by the /// specified number of radians /// /// public virtual void RotateZ(float rad) { curRotation.Z += rad; updateRotation(); } /// /// get / sets the amount of rotation for the /// transform as Euler rotations in radians /// public virtual Vector3 Rotation { get { return curRotation; } set { curRotation = value; updateRotation(); } } /// /// get / sets the amount of rotation for the /// transform as Euler rotations in degrees /// public virtual Vector3 RotationDegrees { get { Vector3 degRotation; degRotation.X = TransformNode.RADIANS_TO_DEGREES * curRotation.X; degRotation.Y = TransformNode.RADIANS_TO_DEGREES * curRotation.Y; degRotation.Z = TransformNode.RADIANS_TO_DEGREES * curRotation.Z; return degRotation; } set { curRotation.X = TransformNode.DEGREES_TO_RADIANS * value.X; curRotation.Y = TransformNode.DEGREES_TO_RADIANS * value.Y; curRotation.Z = TransformNode.DEGREES_TO_RADIANS * value.Z; updateRotation(); } } /// /// get / sets the current rotation for the /// node around the X axis in radians /// public virtual float RotationX { get { return curRotation.X; } set { curRotation.X = value; updateRotation(); } } /// /// get / sets the current rotation for the /// node around the Y axis in radians /// public virtual float RotationY { get { return curRotation.Y; } set { curRotation.Y = value; updateRotation(); } } /// /// get / sets the current rotation for the /// node around the Z axis in radians /// public virtual float RotationZ { get { return curRotation.Z; } set { curRotation.Z = value; updateRotation(); } } /// /// rotates around an arbitrary axis, /// WARNING: using this method will invalidate the /// use of other rotation methods /// /// the axis to rotate around /// the angle in radians to rotate public virtual void RotateAxis(Vector3 axis, float deg) { rotateMat = Matrix.Identity * Matrix.CreateFromAxisAngle(axis, deg) * rotateMat; updateTranformation(); } /* * SCALING */ /// /// modify scale factor by specified amount /// /// public void Scale(Vector3 scale) { curScale.X = scale.X * curScale.X; curScale.Y = scale.Y * curScale.Y; curScale.Z = scale.Z * curScale.Z; scaleMat = Matrix.CreateScale(curScale); updateTranformation(); } /// /// get / sets the scale vector for the node /// /// public Vector3 CurrentScale { get { return curScale; } set { curScale = value; scaleMat = Matrix.Identity * Matrix.CreateScale(curScale); updateTranformation(); } } /* * ENCAPSULATORS */ /// /// gets / sets the euler rotation order /// public EulerRotateOrder RotateOrder { get { return rotateOrder; } set { rotateOrder = value; updateRotation(); } } /// /// the translation part of the transformation matrix /// public Matrix TranslationMatrix { get { return translateMat; } } /// /// the scale part of the transformation matrix /// public Matrix ScaleMatrix { get { return scaleMat; } } /// /// the rotation part of the transformation matrix /// public Matrix RotationMatrix { get { return rotateMat; } } }