我正在将植绒算法实现到更大的系统中。 OGRE用于渲染,luabind用于能够与LUA,yatta yatta进行通信,这些东西不应该太重要。

我基本上按照雷诺兹的boids模型实现了该算法。这意味着,一个Boid(例如“一群鱼”)会根据其邻居在一定半径范围内移动。实际上,它的基本复杂度是O(n²),因为每个小鸟都必须检查所有的队友是否在范围内,然后考虑一些因素来计算自己的运动。

该算法本身已实现且运行平稳。它接受所有不同尺寸的模型,可在2D和3D空间中工作,效果很好,等等,我已经在研究了一段时间。

我的问题是,一旦我碰到了一个大约200-250甚至不同的伯德数“障碍”,该算法就会在运行时崩溃。现在,如果它变得越来越慢直到我被破坏到1 fps,我就可以理解,简单地执行算法就是问题所在。但是,例如199个boid可以正常工作,而201个bob则完全不工作,并且在运行时崩溃。这对我来说是非常令人惊讶的。

我实现了两个类:“Swarm”和“Boid”。虫群用于保持指向虫群所有体的指针,但计算不多,移动发生在Boid中。

swarm.h:

#ifndef __SWARM_H__
#define __SWARM_H__

#include <vector>
#include "boid.h"

namespace Core {

    class swarm {

    public:
    swarm();
    ~swarm();
    bool move(float timeSinceLastFrame);
    bool addBoid(boid *thisBoid);
    bool removeBoidByName(std::string boidName);
    bool writeAllBoidNames();
    std::vector<boid*> getFlockMates();

private:
    std::vector<boid*> flock;
    float timePassed;

};

}


#endif

boid.h:
#ifndef __BOID_H__
#define __BOID_H__

#include "Ogre.h"
#include <vector>
#include <stdlib.h>

namespace Core {

class swarm;

class boid {

    public:
        boid(Ogre::SceneNode *thisNode, Ogre::String orientation, swarm *thisSwarm);            // Constructor - direkter Node-Zugriff
        boid(Ogre::MovableObject *thisObject, Ogre::String orientation, swarm *thisSwarm);      // Constructor - Node-Zugriff über das Objekt
        ~boid();                                                                                // Destructor
        Ogre::Vector3 getBoidPosition();                                                        // gibt die derzeitige Position des Boids zurück - nötig für Cohesion und Separation
        Ogre::Vector3 getBoidVelocity();                                                        // gibt die derzeitige Geschwindigkeit und Richtung des Boids zurück - nötig für Alignement
        std::string getBoidName();                                                              // gibt den Namen eines Boids zurück
        bool move(float timeSinceLastFrame);                                                    // bewegt das Boid

    private:
        swarm *flockMates;                                                                      // pointer auf den Schwarm
        float boidSize;                                                                         // die Größe des Boids
        Ogre::Vector3 boidOrientation;                                                          // Grundlegende Orientierung des Meshes eines Boids
        Ogre::SceneNode *boidNode;                                                              // Pointer auf die SceneNode des Boids - das Objekt, das tatsächlich bewegt wird
        Ogre::Vector3 velocity;                                                                 // derzeitige, bzw. letzte Geschwindigkeit

};
}

#endif

如您所见,我正在使用一个指针 vector 来编排swarm中的对象。在运行时,将调用swarm::move(),它会循环访问 vector 并为每个boid调用boid::move()。
bool swarm::move(float timeSinceLastFrame) {
    std::vector<boid*>::iterator iter;
    for ( iter = flock.begin(); iter != flock.end(); iter++ ) {
        (*iter)->move(timeSinceLastFrame);
    }
    return true;
}

boid::move非常复杂,因为它基于很多东西来计算运动。我将要指出的一点是-imo-在这里实际上很重要,而不是每个乘法都不重要,因为我不想让您厌倦不必要的东西。编辑:好的,现在您在这里有了大部分代码。
bool boid::move(float timeSinceLastFrame) {

    Ogre::Vector3 cohesion = Ogre::Vector3(0, 0, 0);
    Ogre::Vector3 alignement = Ogre::Vector3(0, 0, 0);
    Ogre::Vector3 separation = Ogre::Vector3(0, 0, 0);

    int cohesionCount = 0;
    int alignementCount = 0;
    int separationCount = 0;

    std::vector<boid*>::iterator iter;
    std::vector<boid*> temp = flockMates->getFlockMates();

        for ( iter = temp.begin(); iter != temp.end(); iter++ ) {

        if ( (*iter) != this ) {

            Ogre::Vector3 p1 = boidNode->getPosition();
            Ogre::Vector3 p2 = (*iter)->getBoidPosition();
            Ogre::Real distance = p1.distance(p2);


            if ( distance <= 10*boidSize ) {

                //cohesion
                cohesionCount++;
                cohesion += (*iter)->getBoidPosition();

                //alignement
                alignementCount++;
                alignement += (*iter)->getBoidVelocity();

            }

            if ( distance <= 2.5*boidSize ) {

                //separation
                separationCount++;

                Ogre::Vector3 away = boidNode->getPosition() - (*iter)->getBoidPosition();
                away.normalise();
                away*=boidSize;

                away/=(distance/2);
                separation += away;

            }
        }
    }

    /* do some more stuff */

    /* actually move the boid */
    return true;
};

因此,正如您所看到的,基本算法相当繁重,可以接受。我遍历boid的 vector ,调用每个boid的方法,然后再次遍历该 vector 。其他计算是基本的,只是将变量抛出周围,以使一切看起来都不错,没有任何东西以指数方式增加了复杂性。

现在,如前所述,我希望渲染大量的物体时渲染速度会变慢。我希望帧速率下降等等,但是那根本不会发生。取而代之的是,该算法在高且流畅的帧速率下运行良好,直到我大约达到200 boid +/-,然后在调用swarm::move()时立即崩溃。

我已经检查了几个松散的末端。 vector 容器具有足够的空间来容纳超过10亿个元素,因此并非如此。我还可以使用10000、20000个boid初始化所有内容,因此这也不是基本的内存分配问题。只要调用swarm::move()它就会崩溃。

那么,为什么会因为200个和几个伯德而崩溃呢?为什么帧率不会随时间下降?感谢您对此的任何帮助。我想我提供了所有必要的信息,但是,如果您需要其他代码(或其他任何代码),请随时提出。

通过编辑的其他信息:
如果我通过点击而不是通过帧速率手动触发swarm::move,它不会改变。它仍然适用于
编辑²:
编辑了boid::move()方法,并指出了调试器捕获崩溃的位置。但是,它并没有捕获第1号投标的崩溃,这对我来说是有意义的,而是第314号投标(在这种情况下)。因此,该算法在相同的 vector 上运行313次完全正确,然后在第314次崩溃。这有任何意义吗?

编辑³:
足够有趣的是,调试东西比实际指出问题的根源更使我感到困惑。我再次更新了boid::move(),我将输入swarm::getFlockMates的代码,稍后我将解释原因。
std::vector<boid*> swarm::getFlockMates() {
    return flock;
}

让我感到困惑的是以下内容。在将距离的计算更改为Ben voigt建议的值之后,代码在最终移动时使用值崩溃了,这不应该崩溃。相反,我的cohesionCount为1.x百万,而alignementCount和splittingCount仍为0。这又对我完全没有意义。 cohesionCount不能大于boid的总数,该总数目前为1000(因此崩溃)。即使所有Boid都位于内聚范围内(距离
这只蜜蜂说,我如何迭代羊群有问题吗?

最佳答案

事实证明,我在这里提出的算法没有任何导致此问题的缺陷。内存泄漏发生在我不得不使用的Lua文件之一中,因为通过该引擎(因此也使用了该算法)。尽管如此,还是感谢大家的帮助!

10-08 07:07