目前正在翻譯這篇,要轉載或幫忙翻譯請跟我說....
原文http://www.alsprogrammingresource.com/basic_ode.html
ODE是個物理的函數庫可以在虛擬世界模擬真實的物理現象,ODE的全名是Open Dynamics Engine而作者是Russell Smith,
是個開放程式碼的計畫,在此的ODE範例將會用免費的Dev-cpp來編譯。
這是個簡單的一個物件-一個盒子掉在一個平坦的表面,我們晚點再來講關節的部份,先來講ode include的部份。
ODE是個物理的函數庫可以在虛擬世界模擬真實的物理現象,ODE的全名是Open Dynamics Engine而作者是Russell Smith,
是個開放程式碼的計畫,在此的ODE範例將會用免費的Dev-cpp來編譯。
這是個簡單的一個物件-一個盒子掉在一個平坦的表面,我們晚點再來講關節的部份,先來講ode include的部份。
#inlcude <ode/ode.h>
// 我們需要的global variables.
MATRIX GeomMatrix; MyObject Object; dWorldID World; dSpaceID Space; dJointGroupID contactgroup;
第一個變數叫作GeomMatrix是個陣列將3x3 rotation matrix和position vector用來給OpenGL成像。 在這邊是用一個1x12的float陣列,在之後會講轉換函數。
第二個變數型態是MyObject,簡單的結構包含兩個物件ID, 這些獨特的物件ID是用來給ODE library的reference用來在模擬時區分不同的物件。
#define GEOMSPERBODY 1 // maximum number of geometries per body struct MyObject { dBodyID Body; // the dynamics body dGeomID Geom[GEOMSPERBODY]; // geometries representing this body };
在結構中第一個物件ID是物件dynamics body的identifier,物件的dynamics body包含物件的位置、速度等資訊。 在結構中第二個物件ID是指標到一個陣列包含基本的幾何形狀,像是矩形、球形等來組成物件。 在這個範例中只有一個'幾何(geom)',在這個盒子群組中,但是通常的一個物件是由一堆不同形狀的幾何所組成的 在模擬中的body則是結合dynamics body和他的幾何所組成。
最後三個變數也是物件ID給下列的物件型態:
- dWorld物件包含所有的body跟其節點
- dSpace物件類似world container不過他應用了碰撞而非dynamics.
- dJointGroup物件則是包含了一系列的節點
ODE初始化
在講完global variables之後,接著講ODE模擬初始化,建立一個InitODE函數,
void InitODE() { // 產生一個新的、空的world然後指定他的ID,大部分的程式只需要一個world. World = dWorldCreate(); // 產生一個新的碰撞空間並指定ID,傳入0或是現有的dSpaceID。 // 根據物件數量有三種不同碰撞空間,dSimpleSpaceCreate用於少量的物件, // 如果有很多物件,則考慮用dHashSpaceCreate或dQuadTreeSpaceCreate(參照ODE文件) Space = dSimpleSpaceCreate(0); // 產生一個碰撞群組並指定ID. dJointGroupCreate需要一個 // max_size參數,但我們沒有使用時就傳入0 contactgroup = dJointGroupCreate(0); // 在碰撞空間中產生一個平坦地面,在dCreatePlane中傳入我們的碰撞空間space參數 // 接下來四個參數則是平面的法向量 (a, b, c) 和距離(d) 根據平面公式 // a*x+b*y+c*z=d並且長度必須為1 dCreatePlane(Space, 0, 1, 0, 0); // 現在我們可以設定world的地心引力,在dWorldSetGravity傳入world參數 // 地球地心引力(0, -9.81, 0)假設+Y向上,不過我覺得輕一點引力在這個範例中看起來更真實 dWorldSetGravity(World, 0, -1.0, 0); //接下來兩個函數用來控制多少的error correcting和constraint force混合發生在這個world。 // 現在先別管這些,暫時就用預設就對了,如果需要更精確的控制物件碰撞時,建議參照ODE文件 dWorldSetERP(World, 0.2); dWorldSetCFM(World, 1e-5); // 這個函數會設定兩個物體交互作用分離時的速度,預設是無窮大 dWorldSetContactMaxCorrectingVel(World, 0.9);
// 這個函數會設定world物件的平面深度,接觸的物件可以陷入所設定的深度 // 設定一個小的數值可以減低兩個物件接觸時的不穩定狀態,預設是0 dWorldSetContactSurfaceLayer(World, 0.001); // 爲了節省CPU運算時間,我們將自動停用旗標設為1,這代表當物件停止後(根據物件的線性與角速度), // 將不會在參與模擬運算,直到有新的動作外加於物件使之移動才會重新啟用運算 // 如果不想啟用這個功能的話,可以將旗標設定為 0 ,也可以手動啟用或停用物件(使用dBodyEnable 和 // dBodyDisable),參閱文件關於更多這方面的資料 dWorldSetAutoDisableFlag(World, 1);
// 以上的設定完成了我們虛擬世界所需要設定,接著我們必須對物件進行初始化 // 在我們的虛擬世界中建立一個新的物體並且取得ID Object.Body = dBodyCreate(World); // 接著設定新物體的位置 dBodySetPosition(Object.Body, 0, 10, -5); // 接著設定初始的線性速度為固定不動,讓地心引力作功, // 但妳可以試著改變速度向量來改變一開始的物體行為, //妳也可以用一樣的參數為新物體設定角速度(dBodySetAngularVel) VECTOR tempVect(0.0, 0.0, 0.0); dBodySetLinearVel(Object.Body, tempVect.x, tempVect.y, tempVect.z); // 為了讓每次執行程式,物件一開始時有不同的旋轉方向,我們建立一個新的矩陣叫做 R 並且用 // dRFromAxisAndAngle這個函數來產生隨機參數 R ,之後將 R 傳入dBodySetRotation來產生隨機的
//初始旋轉方向 dMatrix3 R; dRFromAxisAndAngle(R, dRandReal() * 2.0 - 1.0, dRandReal() * 2.0 - 1.0, dRandReal() * 2.0 - 1.0, dRandReal() * 10.0 - 5.0); dBodySetRotation(Object.Body, R); // 在此我們可以用dBodySetData來新增相關的資料,不過在這個範例中並未使用 size_t i = 0; dBodySetData(Object.Body, (void*)i); // 現在我們必須建立一個四方體的質量來結合他的幾何,首先我們先建立一個新的dMass 結構(其 // 中的構造目前並不重要) 然後建立一個3個浮點數(dReal)的陣列,並且設定四方體的長寬高(分別對 // 應於x,y,z軸)然後我們兩這兩個參數傳入dMassSetBox中並且用預先定義的密度(DENSITY) 0.5來設定 dMass m; dReal sides[3]; sides[0] = 2.0; sides[1] = 2.0; sides[2] = 2.0; dMassSetBox(&m, DENSITY, sides[0], sides[1], sides[2]);
// 現在我們可以將這個質量套用到我們的物體上 dBodySetMass(Object.Body, &m); // 在此我們用dCreateBox建立一個真正的幾何物件,注意這也把這個幾何物件加入到我們的碰撞空間中 // 並且將這個幾何大小設定為我們所設定的質量 Object.Geom[0] = dCreateBox(Space, sides[0], sides[1], sides[2]);
// 最後我們需要用dGeomSetBody連結物體和他的幾何在一起,在幾何物件上設定物體會自動結合 // 他的位置向量和旋轉矩陣,所以當我們改變物體(body)和幾何(geom)其中一個的位置或方向,會同時 // 作用到兩者ODE文件對於幾何函數有更詳細的說明
dGeomSetBody(Object.Geom[0], Object.Body); }
沒有留言:
張貼留言