Dirección de evitación de pared

8

Estoy haciendo un pequeño simulador de dirección usando el algoritmo de boid de Reynolds. Ahora quiero agregar una función para evitar la pared. Mis paredes están en 3D y se definen usando dos puntos como ese:

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

Mis agentes tienen una velocidad, una posición, etc.

¿Podría decirme cómo evitar con mis agentes?

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

Luego uso todas las fuerzas devueltas por mis funciones boid y lo aplico a mi agente.

Solo necesito saber cómo hacer eso con mis paredes.

Gracias por tu ayuda.

Vodemki
fuente
2
¿Viste el artículo original de Reynold? Si recuerdo correctamente, tiene información sobre cómo evitar obstáculos y evitar los muros. Creo que este es el documento: red3d.com/cwr/steer/gdc99
krolth
1
Gracias pero explica cómo evitar obstáculos circulares, no rectangulares.
Vodemki
2
Use la distancia radial desde el agente hasta el centro del círculo ( menos el radio de la pared del círculo ).
bobobobo

Respuestas:

14

Deje que cada pared ejerza una influencia sobre la velocidad.

Pruebe algo como usar la distancia inversa (o la distancia al cuadrado inversa) desde la pared para determinar la magnitud de la fuerza que cada pared "ejerce", y la normalidad de la pared para determinar la dirección de la fuerza que la pared "ejerce".

ingrese la descripción de la imagen aquí

Entonces aquí el boid interactúa con 4 paredes. Dado que el producto escalar de los vectores rojos (de centro a pared) es mayor que 0 para 3 de las 4 paredes, esas paredes no ejercerán una fuerza sobre la estructura.

Solo la pared con un vector azul (producto de punto negativo) tendrá una fuerza.

La magnitud de la fuerza debe ser grande con el boid se acerca demasiado a la pared, y la dirección de la fuerza debe estar en la dirección de la flecha negra en la pared (apuntando directamente lejos de la pared).

ingrese la descripción de la imagen aquí

Si usa 1 / (t+1)la magnitud de la fuerza, donde testá la distancia desde la pared, entonces la fuerza será realmente fuerte cuando se acerque a 0, pero se desvanecerá a nada cuando t aumente (observe la escala del eje en el diagrama, no es 0 cuando t = 5, es 0.2). (El t + 1 es para que no obtenga una fuerza / división infinita entre 0 si el boid entra en la pared).

Si usa 1/(t^2+1), entonces la fuerza es mucho más aguda cerca de la pared, y cae más rápido / más suave.

ingrese la descripción de la imagen aquí

Experimente con él y vea lo que le gusta.

bobobobo
fuente
Gracias pero cómo lidiar con un muro 3D. Por ejemplo, mi muro tiene 4 bordes, por lo que creo que solo necesito un máximo de 2 fuerzas (si la dirección del agente está en diagonal).
Vodemki
En 2D, cada 2 puntos es un "muro". Si es un pilar cuadrado en el medio de una habitación, entonces tienes 4 paredes allí. Puede "eliminar" las paredes de la cara posterior (para que las paredes de la cara posterior no "chupen" al jugador) si el vector desde el boid al centro de la pared tiene un producto de puntos positivo con la pared normal.
bobobobo
Entonces, ¿crees que esto haría el trabajo? Distancia Vector2D (paredesListada [i] -> centro (), pos); double dotProduct = distance * wallsList [i] -> normal (); if (dotProduct> 0) {force + = wallsList [i] -> normal () / distance.length (); }
Vodemki
Parece razonable, ¡pruébalo!
bobobobo
Una deficiencia de este enfoque es que la dirección se modela como una fuerza repulsiva que es independiente del movimiento del agente. Es decir, trata al agente como una partícula cargada en un campo electrostático. Considere el caso en el que el agente está "volando" paralelo a esa pared superior (azul) y ligeramente por encima (en la página). En este caso, no se necesita dirección ni evasión de obstáculos. El agente simplemente está pasando y no debe alejarse de la pared. Véase, por ejemplo, "contención" en este documento GDC 99 .
Craig Reynolds
8

Si alguien necesita el código, aquí está, no dude en redistribuirlo. He tratado de comentarlo para que sea más comprensible. Basado en la solución 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
fuente