2013年10月27日 星期日

ODE教學<二>模擬迴圈simLoop

The simulation loop

要更新每個模擬畫面的函數我們叫做SimLoop,簡單來說,他負責計算幾何物件的碰撞然後重新顯示目前的幾何形狀 

void SimLoop()
{
    // dSpaceCollide負責計算空間中兩個幾何物件的可能的碰撞,
    // 我們必須提供callback函數的位置讓他來計算這些資料。
    // callback函數負責在加入碰撞節點前,評估可能的交互作用,碰撞節點的群組叫做contactgroup
    // 這讓我們在把碰撞節點加入到群組前,可以設定其可能行為
    // 第二個參數則是個指標指向任何我們想傳入callback函數的資料。
    // 下個章節我們會講到nearCallback。
    dSpaceCollide(Space, 0, &nearCallback);

    // 現在我們使用dWorldQuickStep來進行進階的模擬,這是dWorldStep的快速版本,但精確度會稍低。
    // 除了World物件ID之外,我們也將step size傳入,每個 step 會根據一個固定的數字的最小step或迭代來
    //更新模擬。
    // 預設次數為 20 但妳可以用dWorldSetQuickStepNumIterations來改變數值
    dWorldQuickStep(World, 0.05);

    //移除所有world中已發生過的暫時性的碰撞節點
    dJointGroupEmpty(contactgroup);

    // 當我們呼掉 DrawGeom 時,會根據物件的幾何形狀來繪出畫面
    DrawGeom(Object.Geom[0], 0, 0, 0);
}

Callback函數

所有配對的幾何物件可能的交互影響都會透過dSpaceCollide傳送到這個函數,加入這些節點到節點群組中前,我們可以決定哪個物件真正發生碰撞藉由呼叫 dCollide 來改變其節點行為 , 第一個參數會是使用者資料指標傳送到 dSpaceCollide(如果我們提供的話),第二個和第三個參數則是兩個可能交互作用的幾何物件 

static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
    // 每個接觸的暫時的索引
    int i;

    // 取得動態幾何物件的物體
    dBodyID b1 = dGeomGetBody(o1);
    dBodyID b2 = dGeomGetBody(o2);

    // 建立一個dContact陣列來存放碰撞節點
    dContact contact[MAX_CONTACTS];

    // Now we set the joint properties of each contact. Going into the full details here would require a
    // tutorial of its own. I'll just say that the members of the dContact structure control the joint
    // behaviour, such as friction, velocity and bounciness. See section 7.3.7
    //  of the ODE manual and have fun experimenting to learn more.
    for (i = 0; i < MAX_CONTACTS; i++)
    {
        contact[i].surface.mode = dContactBounce|dContactSoftCFM;
        contact[i].surface.mu = dInfinity;
        contact[i].surface.mu2 = 0;
        contact[i].surface.bounce = 0.01;
        contact[i].surface.bounce_vel = 0.1;
        contact[i].surface.soft_cfm = 0.01;
    }

    // Here we do the actual collision test by calling dCollide. It returns the number of actual contact
    // points or zero if there were none. As well as the geom IDs, max number of contacts we also pass
    //  the address of a dContactGeom as the fourth parameter. dContactGeom is a substructure of 
    // a dContact object so we simply pass the address of the first dContactGeom from our array of
    //  dContact objects and then pass the offset to the next dContactGeom
    // as the fifth paramater, which is the size of a dContact structure. That made sense didn't it?
    if(int numc = dCollide(o1, o2, MAX_CONTACTS, &contact[0].geom,
        sizeof(dContact)))
    {
        // To add each contact point found to our joint group we call dJointCreateContact 
        // which is just one of the manydifferent joint types available.
        for (i = 0; i < numc; i++)
        {
            // dJointCreateContact needs to know which world and joint group to work with
            // as well as the dContact object itself. It returns a new dJointID which we
            //  then use with dJointAttach to finally create the
            // temporary contact joint between the two geom bodies.
            dJointID c = dJointCreateContact(World, contactgroup,                                   contact + i);
            dJointAttach(c, b1, b2);
        }
    }
}

An important thing to remember about the callback function is that you are not allowed to modify a collision space while that collision space is being processed with dSpaceCollide. For example, you can not add or remove geoms from a space, and you can not reposition the geoms within a space. Doing so will trigger a runtime error. 

沒有留言:

張貼留言