Rotazione di un modello in base alla sua direzione

Ci capiterà spesso di dover affrontare questo dilemma. Se abbiamo imparato a spostare i modelli nello spazio 3D, vorremo anche che essi siano sempre orientati nella direzione in cui stanno muovendo. In particolare dovremmo affrontare questa necessità nel caso di personaggi guidati dal computer o magari personaggi player che si muovono con un "punta e clicca" dipo RPG, STR ecc...
Nel caso di un personaggio, per esempio, esso dovrà avere sempre il viso rivolto verso il punto in cui sta camminando. Per fare questo dovremmo avere il Vector3 verso il quale si sta muovendo il modello.
Ci appoggeremo su due metodi TurnToFace e WrapAngle ma in realtà noi invocheremo solo il primo (che chiamerà il secondo automaticamente) per trovare l'angolo di rotazione (in radianti) che andremo ad inserire nella matrice di rotazione Y (ovvero la rotazione del modello sull'asse Y):

Matrix.CreateRotationY(il_nostro_angolo_in_radianti);

Mettiamo di avere la matrice di rotazione, avremo una World così:

effect.World = rotation_Matrix * Matrix.CreateTranslation(posizione_modello);

Ovvero, prima la matrice di rotazione, poi moltiplicata con la matrice di posizione.

La matrice di rotazione la troviamo con queste due righe:

//Invochiamo prima il metodo TurnToFace per trovare l'angolo
Rotazione = TurnToFace(Posizione, target_pos, Rotazione, vel_rotazione);
//Troviamo la nostra matrice di rotazione in base all'angolo trovato sulla riga precedente
rotation_Matrix = Matrix.CreateRotationY(-Rotazione + angolo);

dove Rotazione è un float (che ovviamente va dichirato) e TurnToFace è il metodo che tra poco scriveremo e che richiede i seguenti parametri:

Posizione: di tipo Vector3 , rappresenta la posizione del modello.
target_pos: di tipo Vector3, ovvero il punto in cui si dirige il modello.
Rotazione: il float trovato la riga precedente.
vel_rotazione: è un float che imposta la velocità con cui ruota il modello.

Inoltre avremo bisogno della variabile "angolo" che andrà dichiarata nel LoadContet (o nell'Inizialize) semplicemente così:

angolo = MathHelper.ToRadians(90);


Ed ecco il metodo (anzi i metodi) che calcolano l'angolo di rotazione in base alla direzione del modello e gli altri parametri che gli andremo ad inviare:


       
//Metodo che richiamiamo manualmente per trovare "Rotazione"
       private static float TurnToFace(Vector3 position, Vector3 faceThis, float currentAngle, float turnSpeed)
        {

            float x = faceThis.X - position.X;
            float y = faceThis.Z - position.Z;

            float desiredAngle = (float)Math.Atan2(y, x);

            float difference = WrapAngle(desiredAngle - currentAngle);

            difference = MathHelper.Clamp(difference, -turnSpeed, turnSpeed);


            return WrapAngle(currentAngle + difference);
        }

//Secondo metodo che viene chiamato automaticamente dal metodo precedente
        private static float WrapAngle(float radians)
        {
            while (radians < -MathHelper.Pi)
            {
                radians += MathHelper.TwoPi;
            }
            while (radians > MathHelper.Pi)
            {
                radians -= MathHelper.TwoPi;
            }
            return radians;
        }

.
Buone rotazioni a tutti!