1. 程式人生 > >ODE手冊(5)剛體函式

ODE手冊(5)剛體函式

這一部分主要是介紹一些在ODE中,跟剛體相關的函式

5.1 剛體的建立和銷燬

dBodyID dBodyCreate (dWorldID);

  在一個指定的world的原點(0,0,0)處建立一個質量引數預設的剛體,並且返回其ID(dBodyID)。

void dBodyDestroy (dBodyID);

  銷燬一個指定的剛體,同時與其相連線的所有關節都會被遣送到“地獄邊境”(也就是說,它們跟模擬的物件不再保持連線,也不會影響到模擬物件,但並不是說會刪除掉)。

5.2 位置和姿態

void dBodySetPosition (dBodyID, dReal x, dReal y, dReal z);
void dBodySetRotation (dBodyID, const dMatrix3 R);
void dBodySetQuaternion (dBodyID, const dQuaternion q);
void dBodySetLinearVel (dBodyID, dReal x, dReal y, dReal z);
void dBodySetAngularVel (dBodyID, dReal x, dReal y, dReal z);
const dReal * dBodyGetPosition (dBodyID);
const dReal * dBodyGetRotation (dBodyID);
const dReal * dBodyGetQuaternion (dBodyID);
const dReal * dBodyGetLinearVel (dBodyID);
const dReal * dBodyGetAngularVel (dBodyID);

  上面這些函式分別是用來設定和獲取剛體的位置,旋轉角度,線速度和角速度。在設定了一組剛體之後,如果新的配置引數跟當前的關節/約束不一致的話,模擬的輸出就為undefined。當獲取某一個屬性的值時,返回的值指向內部的資料結構,因此表示這些值的向量在有任何改變作用到剛體的系統結構之前都是有效的。

  dBodyGetRotation () 返回一個4x3的旋轉矩陣。

5.3 質量和力

void dBodySetMass (dBodyID, const dMass *mass);
void dBodyGetMass (dBodyID, dMass *mass);

  在ODE中,我們通過下面兩個函式來設定和獲取剛體的質量。

void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz);
void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz);
void dBodyAddRelForce (dBodyID, dReal fx, dReal fy, dReal fz);
void dBodyAddRelTorque (dBodyID, dReal fx, dReal fy, dReal fz);
void dBodyAddForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);
void dBodyAddForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);
void dBodyAddRelForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);
void dBodyAddRelForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);

  上面的這些函式用來給系統中的剛體施加力(以相對的或者絕對的座標)。這些力被累加到每一個剛體上,並且在每一個時間步結束後累加器會被清零。

  ***RelForce和***RelTorque函式施加一個相對於其自身座標系的力向量到剛體上。

  ***ForceAtPos和***ForceAtRelPos函式通過一個額外的位置向量(分別以全域性和相對於剛體自身的座標)施加力到剛體上一個指定的點(即受力點)。

  其它的函式施加力到剛體的質心上。

const dReal * dBodyGetForce (dBodyID);
const dReal * dBodyGetTorque (dBodyID);

  在ODE中,如果要獲取施加在指定剛體上的合力和扭矩的話,可以通過上面的兩個函式分別得到,它們返回一個指向含有3個值的dReal型陣列的指標。

void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z);
void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z);

  前面我們介紹了怎樣獲取施加在剛體上的合力和扭矩,上面的兩個函式則是用來設定施加在剛體上的合力和扭矩的累積向量的。它們主要用於對處於無效狀態的剛體再一次被啟用之前進行力和扭矩的清零,當然在這種情況下也可以通過呼叫施加力的函式給處於無效狀態的剛體施加力和扭矩。

5.4 運動學的狀態

void dBodySetDynamic (dBodyID);
void dBodySetKinematic (dBodyID);
int dBodyIsKinematic (dBodyID);

  處於“運動學”狀態(代替預設的“動力學”狀態)的剛體是不會自動停止的,就像是它們擁有無限的質量。這就意味著它們不會對任何力(例如:重力、約束或使用者施加的力)做出任何反應,只是簡單地隨著速度到達下一個位置。它們的目的是控制剛體不要受到其他剛體的作用,而是通過施加在剛體之上的關節(不只是接觸關節)相互作用。跟阻礙剛體間相互移動的接觸關節相比,在一個連線到world(null body)的關節上使用接觸的移動引數相對比較高效。處於運動學狀態的兩個剛體之間的約束,或者阻礙一個處於運動學狀態的剛體和world的約束可以被完全忽略掉。

  注:給一個處於運動學狀態的剛體設定重量將會讓它再一次進入動力學狀態,我們可以通過呼叫dBodySetDynamic函式恢復剛體的源重量。因此要獲取剛體的重量,在使用dBodySetMass之後隨即呼叫dBodyGetMass是比較划算的。

5.5 功能函式(例項函式)

void dBodyGetRelPointPos (dBodyID, dReal px, dReal py, dReal pz, dVector3 result);
void dBodyGetRelPointVel (dBodyID, dReal px, dReal py, dReal pz, dVector3 result);
void dBodyGetPointVel (dBodyID, dReal px, dReal py. dReal pz, dVector3 result);

  上面的功能函式可以通過指定剛體(dBodyID)上一點(px,py,pz)獲取這一點的在全域性座標系中的位置或速度(返回值在result中)。dBodyGetRelPoint***函式的引數(px,py,pz)在剛體的相對座標系中,而dBodyGetPointVel函式的引數(px,py,pz)是一個全域性座標。

void dBodyGetPosRelPoint (dBodyID, dReal px, dReal py, dReal pz, dVector3 result);

  這個函式的功能跟dBodyGetRelPointPos相反,它需要給定一個全域性座標系(x,y,z)中的位置,然其返回值(儲存在result中)是一個相對於剛體自身座標系中的位置座標。

void dBodyVectorToWorld (dBodyID, dReal px, dReal py, dReal pz, dVector3 result);
void dBodyVectorFromWorld (dBodyID, dReal px, dReal py, dReal pz, dVector3 result);

  如果我們需要在body的座標系統和world的座標系統之間進行座標轉換時,可以通過上面的兩個函式實現,轉換後的座標儲存在result中。

5.6 自動化的啟用和禁用

  在ODE中,每個剛體都可以被啟用和禁用。啟用剛體會使它參與到模擬過程中,而禁用的話剛體就會被關閉並且在一個模擬步期間不再更新和它相關的資料。新建立的剛體通常處於啟用狀態。

  如果一個已被禁用的剛體通過關節和一個處於啟用狀態的剛體相連的話,在下一個模擬步開始時它就會被再次啟用。被禁用的剛體不會花費CPU時間,因此如果想要加快模擬速度的話,可以在剛體空閒的時候禁用它們。而且,如果auto-disable處於啟動狀態的話,這個功能就可以被自動執行。

  如果一個剛體的auto-disable標誌已被開啟,它會在發生下面的情況時自動關閉:

  • 剛體在給定的模擬步之內一直處於空閒狀態
  • 剛體在給定的模擬時間之內一直處於空閒狀態
  如果剛體的線速度和角速度的值都低於相應的閾值的話,剛體就會被認為是空閒的。因此,每一個剛體都擁有5個不同的auto-disable引數:一個使能標誌、一個空閒步計數器、一個空閒時間計數器和線/角速度閾值。新建立的剛體會從它們所處的world中獲取這些引數。   以下的這些函式被用來設定和獲取指定剛體的enable/disable引數:

void dBodyEnable (dBodyID);
void dBodyDisable (dBodyID);

  上面的這兩個函式用來手動地啟用和禁用指定剛體。注意:如果一個被禁用的剛體通過關節和一個處於啟用狀態的剛體相連的話,在下一個模擬步開始的時候,它就會被再次啟用。

int dBodyIsEnabled (dBodyID);

  返回剛體的狀態。如果處於啟用狀態,返回 1,否則返回 0

void dBodySetAutoDisableFlag (dBodyID, int do_auto_disable);
int dBodyGetAutoDisableFlag (dBodyID);

  設定或獲取剛體的auto-disable標誌。如果do_auto_disable是一個非0值的話,剛體就會在空閒了足夠長的時間之後自動關閉。

void dBodySetAutoDisableLinearThreshold (dBodyID, dReal linear_threshold);
dReal dBodyGetAutoDisableLinearThreshold (dBodyID);

  設定或獲取用於自動禁用剛體的線速度閾值。如果剛體的線速度低於這個閾值的話,它就會被認定為處於空閒狀態。當然,如果將閾值設為dInfinity時,就不用再考慮它的線速度了。

void dBodySetAutoDisableAngularThreshold (dBodyId, dReal angular_threshold);
dReal dBodyGetAutoDisableAngularThreshold (dBodyID);

  這兩個函式和上面介紹的設定和獲取線速度閾值的函式類似,用於設定或獲取用於自用禁用剛體的角速度閾值。同樣,如果剛體的角速度低於這個閾值的話,它就會被認定為處於空閒狀態。要是將閾值設為dInfinity,也就不用再考慮它的角速度了。

void dBodySetAutoDisableSteps (dBodyID, int steps);
int dBodyGetAutoDisableSteps (dBodyID);

  設定和獲取用於自動禁用剛體的空閒步計數器的值,如果設為0的話,自動禁用函式就不會考慮模擬步了。

void dBodySetAutoDisableTime (dBodyID, dReal time);
dReal dBodyGetAutoDisableTime (dBodyID);

  設定和獲取用於自動禁用剛體的空閒時間計數器的值,如果設為0的話,自動禁用函式也就不用考慮剛體已經空閒的時間了。

void dBodySetAutoDisableAverageSampleCount (dBodyID, unsigned int average_samples_count);
int dBodyGetAutoDisableAverageSampleCount (dBodyID);

  還未寫入。。。

void dBodySetAutoDisableDefaults (dBodyID);

  設定剛體的auto-disable引數,預設採用其所在的world引數。

void dBodySetMovedCallback (dBodyID, void (*callback) (dBodyID));

  上面這個函式用來給指定剛體註冊一個回撥函式,只要該剛體一移動它就會被呼叫(如果剛體沒有被禁用的話)。這個函式在將ODE和3D引擎整合起來時非常有用,因為只要任何一個ODE剛體以移動,與之關聯的所有3D場景也都會變化。另外,回撥函式必須得是符合void callback(dBodyID)的模式。

5.7 阻尼

  在ODE中,阻尼主要服務於兩個目的:降低模擬的不穩定性、允許剛體轉為空閒狀態(使自動禁止剛體成為可能)。剛體被建立時會採用它所處world的當前阻尼係數,如果將係數(scale)設為0的話阻尼就被禁用了。下面介紹它是怎樣被實現的:

  在每一個時間步長結束時,通過測量線速度和角速度跟相應閾值的大小關係,如果都大於其閾值的哈,就給它們乘以1-scale。所以如果scale取負值的話,實際上就會使速度增大,並且如果速度的值大到一定程度的話,就會使剛體在每個模擬步中處於振盪狀態,進而使系統變得不穩定。

  注意:剛體的速度只會在stepper函式將其移除之後發生衰減。只有在stepper(用於移動剛體)函式生成關節約束之後,才可以應用阻尼到剛體上,否則就可能會在約束之間引進新的誤差。

  另外需要注意的一點:只有在剛體移動的回撥函式被呼叫之後,阻尼才會起到作用,因為在這一步仍然可能會用到剛體在模擬步中獲得的精確速度。你甚至可以使用回撥函式建立你自己定製的阻尼函式。

dReal dBodyGetLinearDamping (dBodyID);
dReal dBodyGetAngularDamping (dBodyID);
void dBodySetLinearDamping (dBodyID, dReal scale);
void dBodySetAngularDamping (dBodyID, dReal scale);

  設定和獲取剛體的阻尼係數。在給剛體設定阻尼係數之後,剛體就會忽略掉其所在world的阻尼係數知道的BodySetDampingDefaults()函式被呼叫。如果沒有設定剛體的阻尼係數,獲取函式就會返回其所在world的阻尼係數。

void dBodySetDamping (dBodyID, dReal linear_scale, dReal angular_scale);

  這個函式可以用來一次性同時設定剛體的線阻尼係數和角阻尼係數。

dReal dBodyGetLinearDampingThreshold (dBodyID);
dReal dBodyGetAngularDampingThreshold (dBodyID);
void dBodySetLinearDampingThreshold (dBodyID, dReal threshold);
void dBodySetAngularDampingThreshold (dBodyID, dReal threshold);

  設定/獲取剛體的阻尼生效閾值,只有在線/角速度大於該閾值的時候才生效。

void dBodySetDampingDefaults (dBodyID);

  重置阻尼設定到當前的world設定。

dReal dBodyGetMaxAngularSpeed (dBodyID);
void dBodySetMaxAngularSpeed (dBodyID, dReal max_speed);

  你也可以限制角速度的最大值。跟阻尼函式不同的是,角速度是在剛體移動之前生效的。也就是說,這樣做會在關節時間引進新的誤差以使剛體旋轉的過快(想想汽車的車輪吧),所以你或許會願意給它們指定一個非常高的限制(預設採用dInfinity)。

5.8 其它一些剛體函式

void dBodySetData (dBodyID, void *data);
void *dBodyGetData (dBodyID);

   用於設定和獲取剛體的user-data指標。

void dBodySetFiniteRotationMode (dBodyID, int mode);

  這個函式用來控制在每一個時間步長之內剛體的姿態更新方式。其中mode引數可以是:

  • 0:採用“無限”的姿態更新方式。雖然利於計算,但可能會在剛體高速旋轉時引起錯誤,特別是當這些剛體還聯接著其它剛體。新建立的剛體預設都使用0。
  • 1:一種“有限”的姿態更新方式。這種方式雖然較耗費計算機資源,但是對高速旋轉的剛體來說就更為精確。要注意的是,儘管高速旋轉的剛體會引起許多不用型別的錯誤,但是這種模式只會修正其中一個錯誤的源頭。

int dBodyGetFiniteRotationMode (dBodyID);

  返回一個指定剛體當前的有限旋轉模式(0 or 1)。

void dBodySetFiniteRotationAxis (dBodyID, dReal x, dReal y, dReal z);

  給指定剛體設定有限旋轉軸,這個軸只有在剛體的有限旋轉模式被設定之後才有意義。如果設為原點(0,0,0),剛體就會展現出完整的有限旋轉;如果是一個非零值,剛體的旋轉只會在軸線方向表現出部分有限旋轉,同時在其正交方向表現出無限旋轉。

  這樣做可以緩和一定程度上由剛體的高速自旋引起的誤差來源。例如,對一個高速旋轉的汽車車輪而言,你就可以通過呼叫這個函式,以車輪的鉸接軸為引數來改善它的行為。

void dBodyGetFiniteRotationAxis(dBodyID, dVector3 result);

  返回一個指定剛體當前的有限旋轉軸。

int dBodyGetNumJoints (dBodyID);

  返回聯接到一個指定剛體上的關節數。

dJointID dBodyGetJoint (dBodyID, int index);

  通過給定一個index引數來獲取聯接到剛體上的一個關節。有效的index取值範圍為[0,n),其中n是dBodyGetNumJoints函式的一個返回值。

dWorldID dBOdyGetWorld (dBodyID);

  獲取聯接到一個指定剛體的world。

void dBodySetGravityMode (dBodyID b, int mode);
int dBodyGetGravityMode (dBodyID b);

  設定/獲取剛體是否受其所在world重力影響的資訊。如果mode為一個非零值,則表示受其影響;如果是0,則表示不受其影響。新建立的剛體預設會受到其所在環境的重力影響。

dGeomID dBodyGetFirstGeom (dBodyID);
dGeomiD dBodyGetNextGeom (dGeomID);

  獲取跟一個指定剛體相關的所有幾何體的訪問權。通過呼叫dBodyGetFirstGeom()來獲取對第一個幾何體的訪問權,然後以前一個幾何體為引數呼叫dBodyGetNextGeom()函式來獲取對緊接著的下一個幾何體的訪問權。