Rotar un vector

8

Quiero que mi cámara en primera persona cambie suavemente su dirección de visualización de la dirección d1 a la dirección d2. La última dirección se indica mediante una posición objetivo t2.

Hasta ahora he implementado una rotación que funciona bien, pero la velocidad de la rotación se ralentiza cuanto más se acerca la dirección actual a la deseada. Esto es lo que quiero evitar.

Aquí están los dos métodos muy simples que he escrito hasta ahora:

// this method initiates the direction change and sets the parameter
public void LookAt(Vector3 target) {

        _desiredDirection = target - _cameraPosition;
        _desiredDirection.Normalize();

        _rotation = new Matrix();

        _rotationAxis = Vector3.Cross(Direction, _desiredDirection);

        _isLooking = true;
    }


// this method gets execute by the Update()-method if _isLooking flag is up.
private void _lookingAt() {

        dist = Vector3.Distance(Direction, _desiredDirection);

        // check whether the current direction has reached the desired one.
        if (dist >= 0.00001f) {

            _rotationAxis = Vector3.Cross(Direction, _desiredDirection);
            _rotation = Matrix.CreateFromAxisAngle(_rotationAxis, MathHelper.ToRadians(1));


            Direction = Vector3.TransformNormal(Direction, _rotation);
        } else {

            _onDirectionReached();
            _isLooking = false;
        }
    }

De nuevo, la rotación funciona bien; La cámara alcanza la dirección deseada. Pero la velocidad no es igual en el curso del movimiento -> se ralentiza.

¿Cómo lograr una rotación con velocidad constante?

Marc Wellman
fuente

Respuestas:

3
_rotationAxis = Vector3.Cross(Direction, _desiredDirection);
_rotation = Matrix.CreateFromAxisAngle(_rotationAxis, MathHelper.ToRadians(1));

A medida que Direction& _desiredDirectioncambia para apuntar en casi la misma dirección (a medida que convergen), menor _rotationAxisserá la magnitud de . Seguirá apuntando en la dirección correcta para ser el eje, pero tendrá una longitud más corta. Esa es la naturaleza del cálculo cruzado.

Las tripas del CreateFromAxisAnglemétodo usan la longitud del eje como un factor en la cantidad de rotación que produce. Cuando el eje tiene una longitud de 1, resulta en la cantidad correcta de rotación.

Entonces, si se normalizara _rotationAxisentre las dos líneas que cité anteriormente, obtendría una tasa de rotación constante.

Steve H
fuente
6

Sugeriría dejar que el marco haga todo el trabajo por usted. Comience calculando una matriz de rotación para sus orientaciones de inicio y fin, y conviértalas en cuaterniones. Solo hace esto una vez al comienzo del movimiento y almacena los valores.

Matrix start = /* calculate current rotation matrix */;
Matrix end = /* calculate desired rotation matrix */;
Quaternion startQ = Quaternion.CreateFromRotationMatrix(start);
Quaternion endQ = Quaternion.CreateFromRotationMatrix(end);

Ahora interpola entre estas dos orientaciones usando interpolación lineal esférica. Hay un método para que no tenga que implementar nada usted mismo:

// Animate the progress parameter between 0 and 1
Quaternion currentQ = Quaternion.Slerp(startQ, endQ, progress);

Finalmente recalcule su dirección usando el cuaternión anterior, o conviértalo de nuevo a una matriz de rotación. Algo como esto, por ejemplo:

Vector3 direction = Vector3.Transform(Vector3.Forward, currentQ);
David Gouveia
fuente
¡Muchas gracias por tu detallado asesoramiento! Lo intentaré después del almuerzo;)
marc wellman
Quaternion.Slerp¿Soy solo yo, o suena como un nombre en una novela de fantasía realmente mala o muy buena? Menos el punto, por supuesto.
Financia la demanda de Mónica el