HOWTO simple bouncing sphere (rus)

From ODE Wiki
Jump to: navigation, search

Введение

Статья описывает создание подпрыгивающей на плоскости сферы. Задание простое, но оно показывает общую структуру динамического моделирования с использованием ODE.

Пример кода

Для отображения симуляции используется drawstuff.

Для начала объявим объекты. Вы должны объявить мир (world), пространство (space) для содержания всех объектов, тело (body) с соответствующей геометрией (geom) и массой (m), и совместную группу для хранения контактных соединений, которые создаются во время столкновения. (contactgroup)

#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
// динамические объекты,  и объекты для столкновений
static dWorldID world;
static dSpaceID space;
static dBodyID body;	
static dGeomID geom;	
static dMass m;
static dJointGroupID contactgroup;

Когда система обнаружит столкновение двух объектов, она вызовет код, который определит точки соприкосновения и создаст временные контакты. Параметры контактов (трение, упругость, и тд), также устанавливаются здесь.

// вызывается из dSpaceCollide когда два объекта в пространстве 
// потенциально могут столкнуться.
static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
    dBodyID b1 = dGeomGetBody(o1);
    dBodyID b2 = dGeomGetBody(o2);
    dContact contact;  
    contact.surface.mode = dContactBounce | dContactSoftCFM;
    // параметры трения
    contact.surface.mu = dInfinity;
    // параметры упругости
    contact.surface.bounce = 0.9;
    // bounce_vel - Минимальная скорость необходимая для упругости (в м/с).
    contact.surface.bounce_vel = 0.1;
    // ограничение силы "смешивания" (степень погружения одного объекта в другой при столкновении)
    contact.surface.soft_cfm = 0.001;  
    if (int numc = dCollide (o1,o2,1,&contact.geom,sizeof(dContact))) {
        dJointID c = dJointCreateContact (world,contactgroup,&contact);
        dJointAttach (c,b1,b2);
    }
}

Вызывается в начале симуляции, для создания точки установки камеры в пространстве.

// старт симуляции - установка точки обзора (xyz) и направления камеры (hpr)
static void start()
{
    static float xyz[3] = {2.0f,-2.0f,1.7600f};
    static float hpr[3] = {140.000f,-17.0000f,0.0000f};
    dsSetViewpoint (xyz,hpr);
}

Основной цикл. Он вызывает функцию обнаружения столкновений, является шагом симуляции, а так-же сбрасывает временные точки контактов и перерисовывает объекты на их новой позиции.

// simulation loop
static void simLoop (int pause)
{
    const dReal *pos;
    const dReal *R;
    // обнаруживает столкновение и добавляет точку контакта
    dSpaceCollide (space,0,&nearCallback);
    // сам шаг симуляции
    dWorldQuickStep (world,0.01);  
    // удаляет все точки контакта
    dJointGroupEmpty (contactgroup);
    // перерисовывает сферу на новой позиции
    pos = dGeomGetPosition (geom);
    R = dGeomGetRotation (geom);
    dsDrawSphere (pos,R,dGeomSphereGetRadius (geom));
}

При запуске программы вызывается инициализация, а затем начинается симуляция.

int main (int argc, char **argv)
{
    // // установка указателей на drawstuff
    dsFunctions fn;
    fn.version = DS_VERSION;
    fn.start = &start;
    fn.step = &simLoop;
    fn.stop = 0;
    fn.path_to_textures = "../../drawstuff/textures";
 
    dInitODE ();
    // создание мира
    world = dWorldCreate ();
    space = dHashSpaceCreate (0);
    dWorldSetGravity (world,0,0,-0.2);
    dWorldSetCFM (world,1e-5);
    dCreatePlane (space,0,0,1,0);
    contactgroup = dJointGroupCreate (0);
    // создание объектов
    body = dBodyCreate (world);
    geom = dCreateSphere (space,0.5);
    dMassSetSphere (&m,1,0.5);
    dBodySetMass (body,&m);
    dGeomSetBody (geom,body);
    // установка начальной позиции
    dBodySetPosition (body,0,0,3);
    // запуск симуляции
    dsSimulationLoop (argc,argv,352,288,&fn);
    // очистка
    dJointGroupDestroy (contactgroup);
    dSpaceDestroy (space);
    dWorldDestroy (world);
    dCloseODE();
    return 0;
}