Faire pivoter un vecteur

8

Je veux que mon appareil photo à la première personne change doucement sa direction de vision de la direction d1 à la direction d2. Cette dernière direction est indiquée par une position cible t2.

Jusqu'à présent, j'ai mis en œuvre une rotation qui fonctionne bien, mais la vitesse de la rotation ralentit à mesure que la direction actuelle se rapproche de la direction souhaitée. Voilà ce que je veux éviter.

Voici les deux méthodes très simples que j'ai écrites jusqu'à présent:

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

Encore une fois, la rotation fonctionne bien; la caméra atteint la direction souhaitée. Mais la vitesse n'est pas égale au cours du mouvement -> elle ralentit.

Comment réaliser une rotation à vitesse constante?

marc wellman
la source

Réponses:

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

Comme Direction& _desiredDirectionchange pour pointer dans presque la même direction (au fur et à mesure qu'ils convergent), plus l'amplitude de _rotationAxissera petite . Il pointera toujours dans la bonne direction pour être l'axe mais sera d'une longueur plus courte. Telle est la nature du calcul croisé.

Les entrailles de la CreateFromAxisAngleméthode utilisent la longueur de l'axe comme un facteur dans la quantité de rotation qu'il en résulte. Lorsque l'axe a une longueur de 1, il en résulte la quantité correcte de rotation.

Donc, si vous deviez normaliser _rotationAxisentre les deux lignes que j'ai citées ci-dessus, vous obtiendriez un taux de rotation constant.

Steve H
la source
6

Je suggère de laisser le cadre faire tout le travail pour vous. Commencez par calculer une matrice de rotation pour vos orientations de début et de fin, et convertissez-les toutes les deux en quaternions. Vous ne faites cela qu'une seule fois au début du mouvement et enregistrez les valeurs.

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

Maintenant, interpolez entre ces deux orientations en utilisant une interpolation linéaire sphérique. Il existe une méthode pour que vous n'ayez rien à implémenter vous-même:

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

Enfin, recalculez votre direction à l'aide du quaternion ci-dessus ou convertissez-la à nouveau en matrice de rotation. Quelque chose comme ça par exemple:

Vector3 direction = Vector3.Transform(Vector3.Forward, currentQ);
David Gouveia
la source
Merci beaucoup pour vos conseils détaillés! Je vais essayer ça après le déjeuner;)
Marc Wellman
Quaternion.SlerpEst-ce juste moi ou cela ressemble-t-il à un nom dans un roman fantastique vraiment mauvais ou vraiment bon? Moins le point, bien sûr.
Fund Monica's Lawsuit