Simple Bouncing Sphere (rus)
Введение
Статья описывает создание подпрыгивающей на плоскости сферы. Задание простое, но оно показывает общую структуру динамического моделирования с использованием 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; }