Kemudi penghindaran dinding

8

Saya membuat simulator kemudi kecil menggunakan algoritma Reynolds boid. Sekarang saya ingin menambahkan fitur penghindaran dinding. Dinding saya dalam 3D dan didefinisikan menggunakan dua titik seperti itu:

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

Agen saya memiliki kecepatan, posisi, dll ...

Bisakah Anda memberi tahu saya cara menghindar dengan agen saya?

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

Kemudian saya menggunakan semua kekuatan yang dikembalikan oleh fungsi boid saya dan saya menerapkannya pada agen saya.

Saya hanya perlu tahu bagaimana melakukannya dengan dinding saya.

Terima kasih atas bantuan Anda.

Vodemki
sumber
2
apakah Anda melihat kertas Reynold asli? Jika saya ingat dengan benar itu memiliki info tentang cara melakukan penghindaran rintangan dan penghindaran dinding. Saya pikir ini adalah doc: red3d.com/cwr/steer/gdc99
krolth
1
Terima kasih tetapi itu menjelaskan bagaimana menghindari rintangan melingkar, bukan persegi panjang.
Vodemki
2
Gunakan jarak radial dari agen ke pusat lingkaran ( minus jari-jari dinding lingkaran ).
bobobobo

Jawaban:

14

Biarkan setiap dinding memberi pengaruh pada kecepatan.

Cobalah sesuatu seperti menggunakan jarak invers (atau kuadrat jarak kuadrat) dari dinding untuk menentukan besarnya gaya yang setiap dinding "berikan", dan normal dinding untuk menentukan arah gaya yang dinding "berikan".

masukkan deskripsi gambar di sini

Jadi di sini boid berinteraksi dengan 4 dinding. Karena produk titik dari vektor merah (boid-to-wall-center) lebih besar dari 0 untuk 3 dari 4 dinding, dinding tersebut tidak akan memberikan gaya pada boid.

Hanya dinding dengan vektor biru (produk titik negatif) yang memiliki kekuatan.

Besarnya gaya harus besar dengan boid terlalu dekat ke dinding, dan arah gaya harus ke arah panah hitam di dinding (menunjuk langsung menjauh dari dinding).

masukkan deskripsi gambar di sini

Jika Anda menggunakan 1 / (t+1)untuk besarnya gaya, di mana tjarak dari dinding, maka gaya akan benar-benar kuat ketika mendekati 0, tetapi memudar menjadi nol ketika t semakin tinggi (perhatikan skala sumbu pada diagram, itu adalah tidak 0 ketika t = 5, itu adalah 0,2). (T + 1 adalah agar Anda tidak mendapatkan kekuatan tak terbatas / bagi dengan 0 jika boid kebetulan memasuki dinding).

Jika Anda menggunakan 1/(t^2+1), maka kekuatannya jauh lebih tajam di dekat dinding, dan jatuh lebih cepat / lebih halus.

masukkan deskripsi gambar di sini

Percobaan dengan itu dan lihat apa yang Anda suka.

bobobobo
sumber
Terima kasih tetapi bagaimana menangani dinding 3D. Sebagai contoh, dinding saya memiliki 4 tepi, jadi saya percaya saya hanya perlu maksimal 2 kekuatan (jika arah agen diagonal).
Vodemki
Dalam 2D, setiap 2 poin adalah "tembok." Jika itu adalah pilar persegi di tengah ruangan, maka Anda memiliki 4 dinding di sana. Anda dapat "menyisihkan" dinding backfacing (sehingga dinding backfacing tidak "menyedot" pemain) jika vektor dari boid ke wall-center memiliki produk titik positif dengan dinding normal.
bobobobo
Jadi, apakah Anda pikir ini akan berhasil? Jarak Vector2D (wallsList [i] -> center (), pos); double dotProduct = distance * wallsList [i] -> normal (); if (dotProduct> 0) {force + = wallsList [i] -> normal () / distance.length (); }
Vodemki
Itu terlihat masuk akal, coba saja!
bobobobo
Kelemahan dari pendekatan ini adalah bahwa kemudi dimodelkan sebagai gaya tolak yang tidak tergantung pada gerakan agen. Itu memperlakukan agen sebagai partikel bermuatan dalam medan elektrostatik. Pertimbangkan kasus di mana agen "terbang" sejajar dengan dinding atas (biru) dan sedikit di atasnya (di halaman). Dalam hal ini, tidak diperlukan penghindaran kemudi atau rintangan. Agen hanya lewat, dan tidak harus didorong menjauh dari dinding. Lihat misalnya “penahanan” dalam makalah GDC 99 ini .
Craig Reynolds
8

Jika seseorang membutuhkan kode, ini dia, jangan ragu untuk mendistribusikannya kembali. Saya sudah mencoba berkomentar agar lebih dimengerti. Berdasarkan solusi 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
sumber