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