Girar um vetor

8

Quero que minha câmera em primeira pessoa mude suavemente sua direção de visualização da direção d1 para a direção d2. A última direção é indicada por uma posição alvo t2.

Até agora, implementei uma rotação que funciona bem, mas a velocidade da rotação diminui quanto mais perto a direção atual chegar da desejada. É isso que eu quero evitar.

Aqui estão os dois métodos muito simples que escrevi até agora:

// 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;
        }
    }

Mais uma vez, a rotação funciona bem; a câmera atinge a direção desejada. Mas a velocidade não é igual no decorrer do movimento -> diminui.

Como conseguir uma rotação com velocidade constante?

Marc Wellman
fonte

Respostas:

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

Como Direction& _desiredDirectionmuda para apontar quase na mesma direção (à medida que convergem), menor será a magnitude de _rotationAxis. Ele ainda estará apontando na direção correta para ser o eixo, mas terá um comprimento menor. Essa é a natureza do cálculo cruzado.

As entranhas do CreateFromAxisAnglemétodo usam o comprimento do eixo como um fator na quantidade de rotação em que resulta. Quando o eixo tem um comprimento de 1, resulta na quantidade correta de rotação.

Portanto, se você normalizar _rotationAxisentre as duas linhas que citei acima, obterá uma taxa rotacional constante.

Steve H
fonte
6

Eu sugiro deixar a estrutura fazer todo o trabalho para você. Comece calculando uma matriz de rotação para suas orientações de início e fim e converta-as em quaterniões. Você só faz isso uma vez no início do movimento e armazena os valores.

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

Agora interpole entre essas duas orientações usando interpolação linear esférica. Existe um método para isso, para que você não precise implementar nada:

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

Finalmente, recalcule sua direção usando o quaternion acima ou converta-o novamente em uma matriz de rotação. Algo assim, por exemplo:

Vector3 direction = Vector3.Transform(Vector3.Forward, currentQ);
David Gouveia
fonte
Muito obrigado pelo seu aconselhamento detalhado! Vou tentar que depois do almoço;)
marc wellman
Quaternion.SlerpSou apenas eu, ou isso soa como um nome em um romance de fantasia muito ruim ou muito bom? Menos o ponto, é claro.
Fund Monica's Lawsuit