Simple Bouncing Sphere (rus)

From ODE
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()
{
   float xyz[3] = {2.0f,-2.0f,1.7600f};
   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;
}