Direction d'évitement de mur

8

Je fais un petit simulateur de direction en utilisant l'algorithme Boid de Reynolds. Maintenant, je veux ajouter une fonction d'évitement de mur. Mes murs sont en 3D et définis à l'aide de deux points comme ça:

   ---------. P2
   |        |
P1 .---------

Mes agents ont une vitesse, une position, etc ...

Pourriez-vous me dire comment éviter avec mes agents?

Vector2D ReynoldsSteeringModel::repulsionFromWalls()
{
    Vector2D force;
    vector<Wall *> wallsList = walls();
    Point2D pos = self()->position();
    Vector2D velocity = self()->velocity();

    for (unsigned i=0; i<wallsList.size(); i++)
    {
        //TODO
    }

    return force;
}

Ensuite, j'utilise toutes les forces renvoyées par mes fonctions boid et je l'applique à mon agent.

J'ai juste besoin de savoir comment faire ça avec mes murs.

Merci de votre aide.

Vodemki
la source
2
avez-vous regardé le papier original de Reynold? Si je me souviens bien, il contient des informations sur la façon d'éviter les obstacles et les murs. Je pense que c'est le doc: red3d.com/cwr/steer/gdc99
krolth
1
Merci mais ça explique comment éviter les obstacles circulaires, pas rectangulaires.
Vodemki
2
Utilisez la distance radiale de l'agent au centre du cercle ( moins le rayon de la paroi du cercle ).
bobobobo

Réponses:

14

Laissez chaque mur exercer une influence sur la vitesse.

Essayez quelque chose comme utiliser la distance inverse (ou la distance au carré inverse) du mur pour déterminer l'amplitude de la force que chaque mur "exerce" et la normale du mur pour déterminer la direction de la force que le mur "exerce".

entrez la description de l'image ici

Alors ici, le boid interagit avec 4 murs. Étant donné que le produit scalaire des vecteurs rouges (boid-to-wall-center) est supérieur à 0 pour 3 des 4 murs, ces murs n'exerceront pas de force sur le boid.

Seul le mur avec un vecteur bleu (produit scalaire négatif) aura une force.

L'amplitude de la force doit être grande avec le boid trop proche du mur, et la direction de la force doit être dans le sens de la flèche noire sur le mur (pointant directement loin du mur).

entrez la description de l'image ici

Si vous utilisez 1 / (t+1)pour la magnitude de la force, où test la distance du mur, alors la force sera vraiment forte lorsqu'elle sera proche de 0, mais disparaîtra à zéro lorsque t sera plus élevé (notez l'échelle des axes dans le diagramme, il n'est pas 0 quand t = 5, c'est 0,2). (Le t + 1 est tel que vous n'obtenez pas une force / division infinie par 0 si le boid arrive dans le mur).

Si vous utilisez 1/(t^2+1), alors la force est beaucoup plus forte près du mur et tombe plus rapidement / plus doucement.

entrez la description de l'image ici

Expérimentez avec et voyez ce que vous aimez.

bobobobo
la source
Merci mais comment gérer un mur 3D. Par exemple, mon mur a 4 bords, donc je crois que je n'ai besoin que d'un maximum de 2 forces (si la direction de l'agent est en diagonale).
Vodemki
En 2D, tous les 2 points sont un «mur». Si c'est un pilier carré au milieu d'une pièce, alors vous avez 4 murs là-bas. Vous pouvez "éliminer" les murs de backfacing (de sorte que les murs de backfacing ne "sucent" pas le joueur) si le vecteur du boid au centre du mur a un produit scalaire positif avec le mur normal.
bobobobo
Alors, pensez-vous que cela ferait l'affaire? Distance Vector2D (wallList [i] -> centre (), pos); double dotProduct = distance * mursListe [i] -> normal (); if (dotProduct> 0) {force + = mursListe [i] -> normal () / distance.length (); }
Vodemki
Cela semble raisonnable, testez-le!
bobobobo
Un inconvénient de cette approche est que la direction est modélisée comme une force répulsive indépendante du mouvement de l'agent. C'est-à-dire qu'il traite l'agent comme une particule chargée dans un champ électrostatique. Considérons le cas où l'agent «vole» parallèlement à ce mur supérieur (bleu) et légèrement au-dessus (sur la page). Dans ce cas, aucune direction ni évitement d'obstacles n'est nécessaire. L'agent ne fait que passer et ne doit pas être éloigné du mur. Voir par exemple «confinement» dans ce document GDC 99 .
Craig Reynolds
8

Si quelqu'un a besoin du code, le voici, n'hésitez pas à le redistribuer. J'ai essayé de le commenter pour être plus compréhensible. Basé sur la solution de bobobobo .

Vector2D ReynoldsSteeringModel::repulsionFromWalls(vector<Vector2D *> walls)
{
    Vector2D force; // My force will be stored here
    Point2D pos = self()->position(); // Position of the agent

    // For each wall
    for (unsigned j=0; j<walls->size(); j++)
    {
        // Get the center point of the wall
        Real coordX = (walls[j]->p1().x() + walls[j]->p1().y()) / 2.0;
        Real coordY = (walls[j]->p2().x() + walls[j]->p2().y()) / 2.0;
        Point2D center(coordX, coordY);

        // Create a new vector between my agent and the center of the current wall
        Vector2D distance(center, pos);

        // If the wall is visible, calculate the force to apply
        double dotProduct = distance * partsList[j]->normal();
        if (dotProduct < 0)
        {
            force +=  partsList[j]->normal() / (distance.length() * distance.length() + 1);
        }
    }

    // Returned the calculated force
    return force;
}
Vodemki
la source