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); }
所有配對的幾何物件可能的交互影響都會透過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.
沒有留言:
張貼留言