/// /// A billboarding transform node that tracks an arbitrary transformable node position. /// The primary use of this class is for creating 3D sprites. /// public class BillboardTransform : TransformNode { /// /// the default up direction to use when /// calculating the billboard facing direction /// public static Vector3 DEFAULT_UP = Vector3.UnitY; /// /// the up direction to use if forward axis == DEFAULT_UP /// public static Vector3 ALTERNATE_UP = Vector3.UnitX; /* * CLASS PROPERTIES */ // the target the billboard will track protected SceneItem mTrackTarget; // the position of the tracker the last // time the billboard matrix was updated private Vector3 lastTrackerPosition; // the position of this transform node // the last time the billboard matrix was updated private Vector3 lastBillboardPosition; // a rotation matrix that can rotate // the billboard around its forward axis protected Matrix axisRotationMat; // the amoutn of rotation to apply around the forward axis protected float axisRotation; // the constraining up vector that orients the billboard protected Vector3 upVector; /* * CONSTRUCTOR */ /// /// Basic constructor for a new billboard transform. /// /// The new target the billboard /// transform should track. Typically this is the camera. public BillboardTransform(TransformNode newTrackTarget) : base(EulerRotateOrder.XYZ) { mTrackTarget = newTrackTarget; init(); } private void init() { upVector = BillboardTransform.DEFAULT_UP; axisRotationMat = Matrix.Identity; lastTrackerPosition = Vector3.Zero; lastBillboardPosition = Vector3.Zero; axisRotation = 0; } /* * UPDATE ROTATION MATRIX */ /// /// updates the rotation matrix to /// apply the current billboarding transform /// protected override void updateRotation() { if (mTrackTarget == null) { rotateMat = Matrix.Identity; return; } lastTrackerPosition = mTrackTarget.WorldPosition; lastBillboardPosition = this.WorldPosition; //determine billboard matrix Matrix lookAt = Matrix.Identity; lookAt.Forward = Vector3.Normalize(lastTrackerPosition - lastBillboardPosition); Vector3 up = upVector; if (up == lookAt.Forward) up = BillboardTransform.ALTERNATE_UP; lookAt.Right = Vector3.Normalize(Vector3.Cross(lookAt.Forward, up)); lookAt.Up = Vector3.Cross(lookAt.Forward, lookAt.Right); //add axis rotation rotateMat = axisRotationMat * lookAt; base.updateTranformation(); } /* * ENCAPSULATORS */ /// /// The target which the billboard will track. Typically /// this will be the camera object though any transform /// node can be tracked. /// public SceneItem TrackTarget { get { return mTrackTarget; } set { mTrackTarget = value; lastTrackerPosition = Vector3.Zero; UpdateBillboard(); } } /// /// the up direction to use in orienting the billboard /// public Vector3 UpVector { get { return upVector; } set { upVector = value; } } /// /// the rotation of the billboard around /// its forward axis measured in radians /// public virtual float AxisRotation { get { return axisRotation; } set { axisRotation = value; axisRotationMat = Matrix.CreateRotationZ(axisRotation); updateRotation(); } } /* * UPDATE */ /// /// updates the billboard transform if its position or /// its tracking target's position has changed /// public void UpdateBillboard() { if (mTrackTarget != null) { if (mTrackTarget.WorldPosition != lastTrackerPosition || this.WorldPosition != lastBillboardPosition) { updateRotation(); } } } public override void Update(Matrix viewMatrix, Matrix projMatrix) { base.Update(viewMatrix, projMatrix); UpdateBillboard(); } /* * ROTATIONS OVERRIDE */ /// /// invalid for a billboard transformation /// public override void Rotate(Vector3 deg) { throw new Exception("Cannot set the rotation of a billboard transform"); } /// /// invalid for a billboard transformation /// public override void RotateX(float deg) { throw new Exception("Cannot set the rotation of a billboard transform"); } /// /// invalid for a billboard transformation /// public override void RotateY(float deg) { throw new Exception("Cannot set the rotation of a billboard transform"); } /// /// invalid for a billboard transformation /// public override void RotateZ(float deg) { throw new Exception("Cannot set the rotation of a billboard transform"); } /// /// invalid for a billboard transformation /// public override Vector3 Rotation { get { return Vector3.Zero; } set { throw new Exception("Cannot set the rotation of a billboard transform"); } } /// /// invalid for a billboard transformation /// public override float RotationX { get { return 0; } set { throw new Exception("Cannot set the rotation of a billboard transform"); } } /// /// invalid for a billboard transformation /// public override float RotationY { get { return 0; } set { throw new Exception("Cannot set the rotation of a billboard transform"); } } /// /// invalid for a billboard transformation /// public override float RotationZ { get { return 0; } set { throw new Exception("Cannot set the rotation of a billboard transform"); } } /// /// invalid for a billboard transformation /// public override void RotateAxis(Vector3 axis, float deg) { throw new Exception("Cannot set the rotation of a billboard transform"); } }