Nvidia PhysX 學習文檔10: Rigid Body Dynamics

                                                  爲什麼地球上有各種週期規律,誰能真正理解量子力學?


official site:    https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/RigidBodyDynamics.html

紅色代表需要弄懂的。
————————————————----

Rigid Body Dynamics

In this chapter we cover a number of topics that are also important to understand once you are comfortable with setting up a basic rigid body simulation world.

Velocity

A rigid body's motion is separated into linear and angular velocity components. During simulation, PhysX will modify the velocity of an object in accordance with gravity, other applied forces and torques and as a result of various constraints, such as collisions or joints.

剛體的運動分爲線性運動和旋轉運動。 在仿真過程中,physx會根據剛體受到的重力,其他外力以及力矩,以及各種約束來更新剛體的速度。

A body's linear and angular velocities can be read using the following methods: 讀取剛體的線性速度和旋轉角速度:

PxVec3 PxRigidBody::getLinearVelocity();
PxVec3 PxRigidBody::getAngularVelocity();

A body's linear and angular velocities can be set using the following methods:設置剛體的速度

void PxRigidBody::setLinearVelocity(const PxVec3& linVel, bool autowake);
void PxRigidBody::setAngularVelocity(const PxVec3& angVel, bool autowake);

Mass Properties

A dynamic actor needs mass properties: the mass, moment of inertia, and the center of mass frame which specifies the position of the actor's center of mass and its principal inertia axes. The easiest way to calculate mass properties is to use the PxRigidBodyExt::updateMassAndInertia() helper function, which will set all three properties based on the actor's shapes and a uniform density value.  Variants of this function allow combinations of per-shape densities and manual specification of some mass properties. See the reference for PxRigidBodyExt for more details.
dynamic 類型的actor需要mass屬性:質量、轉動慣量、以及一個質量座標系的原點,該座標系用於指定actor的質心位置以及其principle inertia axes. 最簡單的計算mass屬性的方法是調用PxRigidBodyExt::updateMassAndInertia() 函數,該函數會根據actor的shape和uniform density value去設置上面提的三個mass 屬性,, 該函數可以接受一些入參,用於設置per-shape density 以及 一些質量屬性值,具體請參考reference.

The Wobbly Snowmen in the North Pole Sample illustrate the use of different mass properties. The snowmen act like roly-poly toys, which are usually just an empty shell with the bottom filled with some heavy material. The low centers of mass cause them to move back to an upright position after they have been tilted. They come in different flavors, depending on how the mass properties are set:

North Pole例子中的wobbly(搖擺的) snowmen解釋了各個mass property的使用方法。這個snowmen就像一個質量集中在底部的不倒翁玩具。由於質心很低,導致它們會恢復到直立狀態。 They come in different flavors, depending on how the mass properties are set:

The first is basically massless. There is just a little sphere with a relatively high mass at the bottom of the Actor. This results in a quite rapid movement due to the small resulting moments of inertia. The snowman feels light.

第一種: 質量很輕, 一個小的球,球的質量集中到actor的底部。 轉動慣量會很小,導致rapid movement 。

The second uses the mass of the bottom snowball only, resulting in a bigger inertia. Later on, the center of mass is moved to the bottom of the actor. This approximation is by no means physically correct, but the resulting snowman feels a bit more filled.
第二種僅僅使用the mass of the bottom snowball,這導致了更大的慣性Later on, the center of mass is moved to the bottom of the actor. This approximation is by no means physically correct, but the resulting snowman feels a bit more filled.

The third and fourth snowman use shapes to calculate the mass. The difference is that one calculates the moments of inertia first (from the real center of mass) and then the center of mass is moved to the bottom. The other calculates the moments of inertia about the low center of mass that we pass to the calculation routine. Note how much slower the wobbling is for the second case although both have the same mass. This is because the head accounts for much more in the moment of inertia (the distance from the center of mass squared).
第三種和第四種使用shape去計算質量。 與前面的區別在於:is that one calculates the moments of inertia first (from the real center of mass) and then the center of mass is moved to the bottom. The other calculates the moments of inertia about the low center of mass that we pass to the calculation routine. Note how much slower the wobbling is for the second case although both have the same mass. This is because the head accounts for much more in the moment of inertia (the distance from the center of mass squared).

The last snowman's mass properties are set up manually. The sample uses rough values for the moment of inertia to create a specific desired behavior. The diagonal tensor has a low value in X, and high values in Y and Z, producing a low resistance to rotation around the X-axis and high resistance around Y and Z. As a consequence, the snowman will wobble back and forth only around the X axis.

最後一種snowman的mass屬性是手動設置的, 該例子使用了粗略的轉動慣量值來創建一些所需的動作。 diagonal tensosr的x值較小,y和z值較大,這導致了繞x軸的轉動很容易,繞y z軸的轉動困難。 結果, snowman 會只繞着x軸擺動。

If you have a 3x3 inertia matrix (for example, you have real-life inertia tensors for your objects) use the PxDiagonalize() function to obtain principal axes and diagonal inertia tensors to initialize PxRigidDynamic actors.
如果你有一個3*3的慣量矩陣(例如,對於你的一個物體,你有它的真正的inertia tensor值), use the PxDiagonalize() function to obtain principal axes and diagonal inertia tensors to initialize PxRigidDynamic actors.

When manually setting the mass/inertia tensor of bodies, PhysX requires positive values for the mass and each principal axis of inertia. However, it is legal to provide 0s in these values. When provided with a 0 mass or inertia value, PhysX interprets this to mean infinite mass or inertia around that principal axis. This can be used to create bodies that resist all linear motion or that resist all or some angular motion. Examples of the effects that could be achieved using this approach are:
當手動設置物體的 mass/inertia tensor時,Physx要求mass和principle axis of inertia是正數,然而,設置成0也是可以的。 當把mass 或 inertia值設置爲0時, Physx會認爲這對應着無限大的質量或轉動慣量, 可以藉此去創建一個body,該body resist所有的線性運動或者旋轉運動。 可以實現的效果:

  • Bodies that behave as if they were kinematic
  • Bodies whose translation behaves kinematically but whose rotation is dynamic.
  • Bodies whose translation is dynamic but whose rotation is kinematic.
  • Bodies which can only rotate around a specific axis.

Some examples of what could be achieved are detailed below. First, let's assume that we are creating a common structure - a windmill. The code to construct the bodies that would be part of the windmill are provided below:
下面的例子展示了可以被實現的一些東東。首先,讓我們假設我們正在創建一個常見的結構--風車。 構造該body的代碼:

PxRigidDynamic* dyn = physics.createRigidDynamic(PxTransform(PxVec3(0.f, 2.5f, 0.f)));
PxRigidActorExt::createExclusiveShape(*dyn, PxBoxGeometry(2.f, 0.2f, 0.1f), material);
PxRigidActorExt::createExclusiveShape(*dyn, PxBoxGeometry(0.2f, 2.f, 0.1f), material);
dyn->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true);
dyn->setAngularVelocity(PxVec3(0.f, 0.f, 5.f));
dyn->setAngularDamping(0.f);
PxRigidStatic* st = mPhysics.createRigidStatic(PxTransform(PxVec3(0.f, 1.5f, -1.f)));
PxRigidActorExt::createExclusiveShape(*st, PxBoxGeometry(0.5f, 1.5f, 0.8f), material);
scene.addActor(dyn);
scene.addActor(st);

The above code creates a static box frame for the windmill and a cross to represent the blades of the turbine. We turn off gravity and angular damping on the windmill blade and give it an initial angular velocity. As a result, this turbine blade will rotate at a constant angular velocity indefinitely. However, if another object collided with the turbine, our windmill would cease to function correctly because the turbine blade would be knocked out of place. There are several options to make the turbine blade stay in the correct position when other bodies interact with it. One such approach might be to make the turbine have infinite mass and inertia. In this case, any interactions with bodies would not affect the turbine at all:
上面的代碼創建了一個static box,一個代表風車輪子的叉。 該代碼關閉了重力和風車輪的angular damping,這使得風車可以以恆定的角速度來不停息第轉動。 然而, 如果其他的object與風車相撞,風車將會cease to function correctly,因爲, 風車輪子會被koncked out of space.  當被撞時,有幾個辦法可以使得風車輪子保持正確的位置,其中之一時讓風車具有無限大的質量和慣量, 以保證任何撞擊都不會對其產生頂點影響:

dyn->setMass(0.f);
dyn->setMassSpaceInertiaTensor(PxVec3(0.f));

This example retains the previous behavior of the turbine spinning at a constant angular velocity indefinitely. However, now the body's velocities cannot be affected by any constraints because the body has infinite mass and inertia. If a body collided with the turbine blade, the collision would behave as if the turbine blade was a kinematic body.

該例子保持了上面的風車特性:以固定角速度無休止轉動。這樣的話,風車的轉動不會被任何約束所限制。

Another alternative would be to make the turbine have infinite mass and limit its rotation to just around the body's local z-axis. This would provide the same effect as applying a revolute joint between the turbine and the static windmill frame:

另一個方法是:讓風車有無限的質量,並,限制其僅僅繞制z軸旋轉,這與“在葉片和static windmill之間加上一個旋轉副”的作用是一樣的:

dyn->setMass(0.f);
dyn->setMassSpaceInertiaTensor(PxVec3(0.f, 0.f, 10.f));

In both examples, the body's mass was set to 0, indicating that the body has infinite mass so its linear velocity cannot be changed by any constraints. However, in this example, the body's inertia is configured to permit the body's angular velocity to be affected by constraints around one principal axis or inertia. This provides a similar effect to introducing a revolute joint. The value of the inertia around the z-axis can be increased or decreased to make the turbines more/less resistive to motion.

在上面兩種方式中,質量都設置成數字0,意味着body具備無限大的質量以使得其不會被改變。  然而, 在後一方式中,body的轉動慣量被配置成(0,0,10),意味着其沿着z軸的角速度是可以被改變的,這與引入一個旋轉副是同樣的效果。
 


Applying Forces and Torques

 

The most physics-friendly way to interact with a body is to apply a force to it. In classical mechanics, most interactions between bodies are typically solved by using forces. Because of the law:
最physics-friendly的與body進行交互的方式是施加力。 在經典力學中,大部分的body之間的交互是通過力。

f = m*a (force = mass * acceleration)

Forces directly control a body's acceleration, but its velocity and position only indirectly. For this reason control by force may be inconvenient if you need immediate response. The advantage of forces is that regardless of what forces you apply to the bodies in the scene, the simulation will be able to keep all the defined constraints (joints and contacts) satisfied. For example gravity works by applying a force to bodies.
力直接導致物體加速度的變化,間接導致位置的變化。 因此,如果你需要immediate respose的話,通過力來控制可能不太方便。 對物體施加力 的優勢是: 無論你對scene中的物體施加上什麼樣的力, physics總有能力keep all the defined constraints(joints and contacts) satisfied.

Unfortunately applying large forces to articulated bodies at the resonant frequency of a system may lead to ever increasing velocities, and eventually to the failure of the solver to maintain the joint constraints. This is not unlike a real world system, where the joints would ultimately break.

不幸的是,對articulated(鉸接)body 以系統的共振頻率施加很大的力時,會導致速度的不斷增加,最終導致solver不能maintain the joint constraints. 在真實的世界中的話,關節會折斷。

The forces acting on a body are accumulated before each simulation frame, applied to the simulation, and then reset to zero in preparation for the next frame. The relevant methods of PxRigidBody and PxRigidBodyExt are listed below. Please refer to the API reference for more detail:

The forces acting on a body are accumulated before each simulation frame, applied to the simulation, and then reset to zero in preparation for the next frame. (意思是:在每個frame之前,力被累積? , 對物體施加力的api:

void PxRigidBody::addForce(const PxVec3& force, PxForceMode::Enum mode, bool autowake);
void PxRigidBody::addTorque(const PxVec3& torque, PxForceMode::Enum mode, bool autowake);

void PxRigidBodyExt::addForceAtPos(PxRigidBody& body, const PxVec3& force,
    const PxVec3& pos, PxForceMode::Enum mode, bool wakeup);
void PxRigidBodyExt::addForceAtLocalPos(PxRigidBody& body, const PxVec3& force,
    const PxVec3& pos, PxForceMode::Enum mode, bool wakeup);
void PxRigidBodyExt::addLocalForceAtPos(PxRigidBody& body, const PxVec3& force,
    const PxVec3& pos, PxForceMode::Enum mode, bool wakeup);
void PxRigidBodyExt::addLocalForceAtLocalPos(PxRigidBody& body, const PxVec3& force,
    const PxVec3& pos, PxForceMode::Enum mode, bool wakeup);

The PxForceMode member defaults to PxForceMode::eFORCE to apply simple forces. There are other possibilities. For example PxForceMode::eIMPULSE will apply an impulsive force. PxForceMode::eVELOCITY_CHANGE will do the same, but also ignore the mass of the body, effectively leading to an instantaneous velocity change. See the API documentation of PxForceMode for the other possibilities.

入參中的PxForceMode 參數的設置爲 PxForceMode::eFORCE時支持施加力, 該參數也可以爲PxForceMode::eIMPULSE以支持施加impluse force(衝量), 設置爲PxForceMode::eVELOCITY_CHANGE時可以達到ignore物體質量的效果,實現瞬間無延遲地速度變化。 其他值可參考API documentation of PxForceMode。

Note

The methods in PxRigidBodyExt support only the force modes eFORCE and eIMPULSE.

上面的屬於PxRigidBodyExt 的函數只支持force modes eFORCE and eIMPULSE。

There are further extension functions that compute the linear and angular velocity changes that would arise in the next simulation frame if an impulsive force or impulsive torque were to be applied:
還有其他函數可以用來計算線速度或者角速度的變換 that would arise in the next simulation frame if an impulsive force or impulsive torque were to be applied:

void PxRigidBodyExt::computeVelocityDeltaFromImpulse(const PxRigidBody& body,
    const PxVec3& impulsiveForce, const PxVec3& impulsiveTorque, PxVec3& deltaLinearVelocity,
    PxVec3& deltaAngularVelocity);

A use case for this function might be to predict an updated velocity for an object so that asset loading may be initiated in advance of the simulation frame if the body is likely to exceed a threshold velocity at the end of the frame. The impulsive force and torque are simply the force and torque that are to be applied to the body multiplied by the timestep of the simulation frame. Neglecting the effect of constraint and contact forces, the change in linear and angular velocity that are expected to arise in the next simulation frame are returned in deltaLinearVelocity and deltaAngularVelocity. The predicted linear velocity can then be computed with body.getLinearVelocity() + deltaLinearVelocity, while the predicted angular velocity can be computed with body.getAngularVelocity() + deltaAngularVelocity. If required, it is possible to immediately update the velocity of the body using body.setLinearVelocity(body.getLinearVelocity() + deltaLinearVelocity) and body.setAngularVelocity(body.getAngularVelocity() + deltaAngularVelocity).
該函數的一個用例: 預測物體的updated速度,從而可以實現: 如果該物體可能exceed a threshold velocity at the end of the frame的話,在simulation frame之前就開始asset loading。入參中的inpulse force和impulse torque是 "力(that are to be applied to the body) * timeStep".   兩個delta參數返回在Neglecting the effect of constraint and contact forces狀況下,下一個frame中預期的線速度和角速度的變化。從而可以得到預測線速度: body.getLinearVelocity() + deltaLinearVelocity, 得到預測角速度: body.getAngularVelocity() + deltaAngularVelocity。如果需要的話,可以立即update body的速度:body.setLinearVelocity(body.getLinearVelocity() + deltaLinearVelocity) 以及 body.setAngularVelocity(body.getAngularVelocity() + deltaAngularVelocity).



Gravity

Gravity is such a common force in simulations that PhysX makes it particularly simple to apply. For a scene-wide gravity effect, or any other uniform force field, set the PxScene class' gravity vector using PxScene::setGravity().

對於 scene-wide gravity effect, or any other uniform force field, 使用PxScene::setGravity()來設置力矢量,以使得場景中的所有的物體都會受到這個力矢量。

The parameter is the acceleration due to gravity. In meters and seconds, this works out to have a magnitude of about 9.8 on earth, and should point downwards. The force that will be applied at the center of mass of each body in the scene is this acceleration vector times the actor's mass.

函數的入參時加速度矢量,單位是m/s^2。 在地球上的話,加速度值是9.8,方向豎直向下。

Certain special effects can require that some dynamic actors are not influenced by gravity. To specify this set the flag:

可以設置dynamic actors不受重力:

PxActor::setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true);

Note

Be careful when changing gravity (or enabling/disabling it) during the simulation. For performance reasons the change will not wake up sleeping actors automatically. Thus it may be necessary to iterate through all actors and call PxRigidDynamic::wakeUp() manually.
在仿真運行的過程中間改變重力或者enable/disable重力的話,需要特別注意。 性能的原因,這種變化出現時physx不會自動wake up sleeping actor。 從而,需要用戶遍歷scene中所有的actors對其調用PxRigidDynamic::wakeUp() manually。

An alternative to PxActorFlag::eDISABLE_GRAVITY is to use a zero gravity vector for the whole scene, then apply your own gravity force to rigid bodies, each frame. This can be used to create radial gravity fields, as demonstrated in SampleCustomGravity.
另外一種技巧: 設置場景的重力矢量爲0, 然後,如果某個actor需要重力的話就each frame單獨施加給它,這種方法可以實現創建輻射狀的重力場,見例子:SampleCustomGravity。
 



Friction and Restitution

All physical objects have at least one material, which defines the friction and restitution properties used to resolve a collision with the objects.

每個物體至少有一個material屬性, 以定義摩擦和碰撞屬性。

To create a material, call PxPhysics::createMaterial():

PxMaterial* mMaterial;

mMaterial = mPhysics->createMaterial(0.5f, 0.5f, 0.1f); // static friction, dynamic friction,restitution
                                                        
if(!mMaterial)
    fatalError("createMaterial failed!");

Materials are owned by the PxPhysics object, and can be shared among objects in multiple scenes. The material properties of two objects involved in a collision may be combined in various ways. See the reference documentation for PxMaterial for more details.

創建出來的matetial變量會給object使用,即owned by objectg,  一個material 可以被不同場景的不同的object所共同使用。 當兩個obj碰撞時,它們的material屬性可以被以各種不同的方式使用,具體見PxMaterial文檔。

PhysX objects whose collision geometry is a triangle mesh or a heightfield (see Shapes) can have a material per triangle.

Collison geometry爲triangle或者heightfield的object,其每個三角片可以有不同的material, shape文檔講過。

Friction uses the coulomb friction model, which is based around the concepts of 2 coefficients: the static friction coefficient and the dynamic friction coefficient (sometimes called kinetic friction).  Friction resists relative lateral motion of two solid surfaces in contact. These two coefficients define a relationship between the normal force exerted by each surface on the other and the amount of friction force that is applied to resist lateral motion. Static friction defines the amount of friction that is applied between surfaces that are not moving lateral to each-other. Dynamic friction defines the amount of friction applied between surfaces that are moving relative to each-other.
摩擦使用的是庫倫摩擦模型, 該模型基於兩個係數: the static friction coefficient 以及 the dynamic friction coefficient (sometimes called kinetic friction)。 -- 基本的物理知識。

When using the default patch friction model, PhysX's friction model is, by default, stronger than analytical models. To achieve results much closer to analytical models, PhysX 4.0 introduced the PxMaterialFlag::eIMPROVED_PATCH_FRICTION flag. By default, this flag is not enabled to maintain legacy behavior.
當使用default patch摩擦模型時,PhysX的摩擦模型is stronger than analytical models. To achieve results much closer to analytical models, PhysX 4.0 introduced the PxMaterialFlag::eIMPROVED_PATCH_FRICTION flag. By default, this flag is not enabled to maintain legacy behavior.

The coefficient of restitution of two colliding objects is a fractional value representing the ratio of speeds after and before an impact, taken along the line of impact. A coefficient of restitution of 1 is said to collide elastically, while a coefficient of restitution < 1 is said to be inelastic.
兩個碰撞體的coefficient of restitution是一個小數,該數等於 "碰撞後的速度/碰撞前的速度",速度是指的沿着碰撞線方向的速度。



Sleeping

When an actor does not move for a period of time, it is assumed that it will not move in the future either until some external force acts on it that throws it out of equilibrium. Until then it is no longer simulated in order to save resources. This state is called sleeping. You can query an actor's sleep state with the following method:
如果一個actor在一段時間間隔內沒有動,Physx爲認爲其在以後也不會運動(即讓其進入sleeping狀態),除非有其他的力讓他動。 一下函數可以用來檢查一個actor是否處於sleeping狀態:

bool PxRigidDynamic::isSleeping() const;

It is however often more convenient to listen for events that the SDK sends when actors fall asleep or wake up. To receive the following events, PxActorFlag::eSEND_SLEEP_NOTIFIES must be set for the actor:
出來調用isSleeping之外,另一種知道actor是否sleep的方法是監聽skd發出的事件,即當actor進入或者跳出sleeping狀態的時候會自動觸發回調函數吧,使能監聽的方式是設置actor的PxActorFlag::eSEND_SLEEP_NOTIFIES

void PxSimulationEventCallback::onWake(PxActor** actors, PxU32 count) = 0;
void PxSimulationEventCallback::onSleep(PxActor** actors, PxU32 count) = 0;

--- 這兩個函數是許需要用戶自己實現內部功能吧。

See the section Callback Sequence and the subsection Sleep state change events for more information.
關於事件的回調在這裏(https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/Simulation.html?highlight=callback%20sequence#callback-sequence).

An actor goes to sleep when its kinetic energy is below a given threshold for a certain time. Basically, every dynamic rigid actor has a wake counter which gets decremented by the simulation time step when the kinetic energy of the actor is below the specified threshold. However, if the energy is above the threshold after a simulation step, the counter gets reset to a minimum default value and the whole process starts anew. Once the wake counter reaches zero, it does not get decremented any further and the actor is ready to go to sleep. Please note that a zero wake counter does not mean that the actor has to be asleep, it only indicates that it is ready to go to sleep. There are other factors that might keep an actor awake for a while longer.
當一個actor的動能低於給定的閾值且持續一段給定的時間後,該actor就進入sleep狀態。 每個dynamic actor都有一個自己的counter,當其動能小於閾值的時候,該counter在每個step都會減少timestep值。當actor的動能值大於閾值時,該值會被reset成一個默認值。 該counter的值等於0時,actor就sleep啦。  注意:當actor的counter的值爲0時,該actor不一定進入sleep,爲0僅僅意味着該actor is ready to sleep,還有其他的一些因素會keep actor awake for a while longer。(什麼因素?

The energy threshold as well as the minimum amount of time an actor will stay awake can be manipulated using the following methods:
可以用以下函數來設置動能閾值、 the minimum amount of time an actor will stay awake:

void PxRigidDynamic::setSleepThreshold(PxReal threshold);
PxReal PxRigidDynamic::getSleepThreshold() const;

void PxRigidDynamic::setWakeCounter(PxReal wakeCounterValue);
PxReal PxRigidDynamic::getWakeCounter() const;

Note

For kinematic actors, special sleep rules apply. A kinematic actor is asleep unless a target pose has been set (in which case it will stay awake until the end of the next simulation step where no target pose has been set anymore). As a consequence, it is not allowed to use setWakeCounter() for kinematic actors. The wake counter of a kinematic actor is solely defined based on whether a target pose has been set.

對於kenematic actor,有特殊的sleep rules。  一個kinematic actor會一直sleep除非給他設置了target pose. 因此,不能對kinematic actor使用setWakeCounter函數。 kinematic actor的wake counter會在這個時候設置: 當target pose被設置的時候。

If a dynamic rigid actor is sleeping, the following state is guaranteed: 當dynamic rigid actor在sleep狀態的時候:

  • The wake counter is zero.
  • The linear and angular velocity is zero.
  • There is no force update pending.

When an actor gets inserted into a scene, it will be considered asleep if all the points above hold, else it will be treated as awake.

當插入一個actor到scene的時候,如果其符合上面三條,physx會認爲其時sleep。

In general, a dynamic rigid actor is guaranteed to be awake if at least one of the following holds:

當一個dynamic rigid actor處於以下任何一個狀態時,physx保證其時wake的狀態:

  • The wake counter is positive.
  • The linear or angular velocity is non-zero.
  • A non-zero force or torque has been applied.

As a consequence, the following calls will wake the actor up automatically:
可以用以下函數可以wake一個actor:

  • PxRigidDynamic::setWakeCounter(), if the wake counter value is larger than zero.
  • PxRigidBody::setLinearVelocity(), ::setAngularVelocity(), if the velocity is non-zero.
  • PxRigidBody::addForce(), ::addTorque(), if the torque is non-zero.

In addition, the following calls and events wake an actor up:

另外,以下函數和事件可以wake 一個actor:

  • PxRigidDynamic::setKinematicTarget() in the case of a kinematic actor (because this also sets the wake counter to a positive value).
  • PxRigidActor::setGlobalPose(), if the autowake parameter is set to true (default).
  • Simulation gets disabled for a PxRigidActor by raising PxActorFlag::eDISABLE_SIMULATION.
  • PxScene::resetFiltering().
  • PxShape::setSimulationFilterData(), if the subsequent re-filtering causes the type of the shape pair to transition between suppressed, trigger and contact.
  • Touch with an actor that is awake.
  • A touching rigid actor gets removed from the scene (this is the default behavior but it can be specified by the user, see note further below).
  • Contact with a static rigid actor is lost.-- 突然失去了靠山,肯定會動
  • Contact with a dynamic rigid actor is lost and this actor is awake in the next simulation step.

Note

When removing a rigid actor from the scene or a shape from an actor, it is possible to specify whether to wake up the objects that were touching the removed object in the previous simulation step. See the API comments in PxScene::removeActor() and PxRigidActor::detachShape() for details.

從scene中remove一個rigid actor 或者 remove一個shape from an actor時,用戶可以指定是否去wake up 那些在上一個TimeStep與被移除東東相touch的objects. 具體可以看api documents的PxScene::removeActor() and PxRigidActor::detachShape().

(https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxapi/files/classPxScene.html#a6ba76326fc73e3c5b0361568caec9267:)

 

To explicitly wake up a sleeping object, or force an object to sleep, use:
強制sleep或者wakeup:

void PxRigidDynamic::wakeUp();
void PxRigidDynamic::putToSleep();

Note

It is not allowed to use these methods for kinematic actors. The sleep state of a kinematic actor is solely defined based on whether a target pose has been set.

不能對kinematic actors使用上面兩個函數。 因爲 The sleep state of a kinematic actor is solely defined based on whether a target pose has been set.。

The API reference documents exactly which methods cause an actor to be woken up.



Sleep state change events

As mentioned above, PhysX provides an event system that reports changes to the sleep state of dynamic rigid bodies during PxScene::fetchResults():

如上所述,Physx提供了一個event system,其可以報告PxScene::fetchResults()期間dynamic rigid body的sleep狀態的變化。

void PxSimulationEventCallback::onWake(PxActor** actors, PxU32 count) = 0;
void PxSimulationEventCallback::onSleep(PxActor** actors, PxU32 count) = 0;

It is important to understand the correct usage of these events, and their limitations:

這種event的正確使用方法和侷限性:

  • A body added since the previous fetchResults() or flushSimulation() will always generate an event, even if no sleep state transition occured.
     
  • If there have been multiple changes in a body's sleep state since the previous fetchResults() or flushSimulation(), PhysX will report only the most recent.
     

Sometimes it is desirable to detect transitions between awake and asleep, e.g. when keeping track of the number of awake bodies. Suppose a sleeping body B is woken by the application, the counter is incremented, and during the next simulation step B stays awake. Even though B's sleep state did not change during simulation, it has changed since the previous fetchResults(), and so an onWake() event will be generated for it. If the counter is incremented again in response to this event, its value will be incorrect.
有時需要檢測awake和asleep狀態之間的切換,例如, keep track the 處於awake狀態的物體數目.   假設處於sleep狀態的物體B被application awake, 計數器加一(在哪裏加一) 且 在下一個timeStep 物體B保持awake狀態, 即使,物體B的狀態沒有變化,相對於上一次fetchResults()來說其狀態已經變了,so, 會產生一個onWake信號, 如果在事件函數中再一次將計數器加一那就錯了。

解決方法:To use sleep state events to detect transitions, a record of the sleep state for objects of interest has to be kept, for example in a hash. When processing an event, this record can be used to check whether there has been a transition.




Kinematic Actors

Sometimes controlling an actor using forces or constraints is not sufficiently robust, precise or flexible. For example moving platforms or character controllers often need to manipulate an actor's position or have it exactly follow a specific path. Such a control scheme is provided by kinematic actors.
有時,使用力或者約束來控制一個actor是不夠robust、準確、靈活的。 例如,moving platforms or character controllers 經常需要控制actor的位置或者使其follow具體的軌跡。 kinematic則可以提供這種機制。

A kinematic actor is controlled using the PxRigidDynamic::setKinematicTarget() function. Each simulation step PhysX moves the actor to its target position, regardless of external forces, gravity, collision, etc. Thus one must continually call setKinematicTarget(), every time step, for each kinematic actor, to make them move along their desired paths. The movement of a kinematic actor affects dynamic actors with which it collides or to which it is constrained with a joint. The actor will appear to have infinite mass and will push regular dynamic actors out of the way.

用戶使用PxRigidDynamic::setKinematicTarget()函數來控制kinematic actor.  每一個step, 使用該函數可以將actor移動到目標位置,不受外力,重力,碰撞等影響。 因此,用戶必須不停地調用該函數。 kinematic actor的移動會對與其發生碰撞的dynamic actor或者與其有約束關係的actor產生影響,kinematic actor的質量就像是無限大,其會push regular dynamic actors out of the way.

To create a kinematic actor, simply create a regular dynamic actor then set its kinematic flag:

創建一個kinematic actor的方法是,創建一個regular dynamic actor,然後設置成kinematic flag:

 

PxRigidBody::setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);

Use the same function to transform a kinematic actor back to a regular dynamic actor. While you do need to provide a mass for the kinematic actor as for all dynamic actors, this mass will not actually be used for anything while the actor is in kinematic mode.
該函數也可以將一個kinematic轉回成reguLar dynamic actor. 用戶也可以給kinematic actor設置一個質量,只是該質量不會被用到。

Caveats:(警告)

  • It is important to understand the difference between PxRigidDynamic::setKinematicTarget() and PxRigidActor::setGlobalPose() here. While setGlobalPose() would also move the actor to the desired position, it would not make that actor properly interact with other objects. In particular, with setGlobalPose() the kinematic actor would not push away other dynamic actors in its path, instead it would go right through them. The setGlobalPose() function can still be used though, if one simply wants to teleport a kinematic actor to a new position.
  • A kinematic actor can push away dynamic objects, but nothing pushes it back. As a result, a kinematic can easily squish(擠壞) a dynamic actor against a static actor, or against another kinematic actor. As a result, the squished dynamic object can deeply penetrate the geometry it has been pushed into.
  • There is no interaction or collision between kinematic actors and static actors. However, it is possible to request contact information for these cases with the PxSceneDesc::kineKineFilteringMode and PxSceneDesc::staticKineFilteringMode.

Kinematic Surface Velocities

In addition to setting kinematic targets or the global pose of a kinematic actor, it is also possible to set a kinematic surface velocity using the method PxRigidDynamic::setKinematicSurfaceVelocity().    This method is only legal to call if the rigid body in question is set to be kinematic. This method sets a persistent velocity on the kinematic actor but flags the actor to bypass integration. This means that objects interacting with the kinematic actor through collisions will behave as if the kinematic actor is moving, although the actor's pose does not actually change. This mechanism can be used to create conveyor belts and rotating surfaces.

---- 給表面設置一個速度,但是位置不動。



Active Actors

------ physx提供了一個函數可以將位置變動的actor從scene中一下子查詢出來,返回的形式是一個數組。

The active actors API provides an efficient way to reflect actor transform changes in a PhysX scene to an associated external object such as a render mesh.

When a scene's fetchResults() method is called an array of active PxActor is generated. Because only actors that have moved will be included in the list this approach is potentially much more efficient than, for example, analyzing each actor in the scene individually.

The example below shows how to use active actors to update a render object:

// update scene
scene.simulate(dt);
scene.fetchResults();

// retrieve array of actors that moved
PxU32 nbActiveActors;
PxActor** activeActors = scene.getActiveActors(nbActiveActors);

// update each render object with the new transform
for (PxU32 i=0; i < nbActiveActors; ++i)
{
    MyRenderObject* renderObject = static_cast<MyRenderObject*>(activeActors[i]->userData);
    renderObject->setTransform(activeActors[i]->getGlobalPose());
}

Note

PxSceneFlag::eENABLE_ACTIVE_ACTORS must be set on the scene for the active actors array to be generated.

Note

Since the target transform for kinematic rigid bodies is set by the user, kinematics can be excluded from the list by setting the flag PxSceneFlag::eEXCLUDE_KINEMATICS_FROM_ACTIVE_ACTORS.



Dominance

---Dominance :支配, 控制

Dominance is a mechanism to enable dynamic bodies to dominate each-other.  Dominance effectively imbues(使充滿,灌溉) the dominant body in a pair with infinite mass(使一對pair中的兩個物體中的起支配作用的那個的質量變爲無窮).   This is a form of local mass modification within the constraint solver and, as such, can override the mass of one of the bodies in a pair.   Similar effects can be achieved through local mass modification in contact modification but dominance has the advantage of being handled automatically within the SDK so does not incur the additional memory and performance overhead of contact modification.
 

Each actor must be assigned a dominance group ID. This is a 5-bit value in the range [0, 31]. As such, you are restricted to at-most 32 dominance groups. By default, all bodies are placed in dominance group 0. An actor can be assigned to a dominance group using the following method on PxActor:

virtual void setDominanceGroup(PxDominanceGroup dominanceGroup) = 0;

Dominance is defined by 2 real numbers in the following struct:

struct PxDominanceGroupPair
{
    PxDominanceGroupPair(PxReal a, PxReal b)
        : dominance0(a), dominance1(b) {}
    PxReal dominance0;
    PxReal dominance1;
};

And dominance between two dominance groups can be configured using the following method on PxScene:

virtual void setDominanceGroupPair(PxDominanceGroup group1, PxDominanceGroup group2,
    const PxDominanceGroupPair& dominance) = 0; //用PxDominanceGroupPair入參設置兩個group誰支配誰。

The user can define 3 different states for a given PxDominanceGroupPair: * 1 : 1. This indicates that both bodies have equal dominance. This is the default behavior. * 1 : 0. This indicates that body B dominates body A. * 0 : 1. This indicates that body A dominates body B.---看來0代表着無限大的質量。

Any values other than 0 and 1 are not valid in a PxDominanceGroupPair. Assigning 0 to both sides of the PxDominanceGroupPair is also invalid. These values can be considered to be scales applied to the bodies' respective inverse mass and inverse inertia. A dominance value of 0 would therefore equate to an infinite mass body.

The following example sets two actors, actorA and actorB, into different dominance groups and configures the dominance group to make actorA dominate actorB: --- 先把兩個actor放到group裏面,然後配置兩個group誰支配誰。

PxRigidDynamic* actorA = mPhysics->createRigidDynamic(PxTransform(PxIdentity));
PxRigidDynamic* actorB = mPhysics->createRigidDynamic(PxTransform(PxIdentity));

actorA->setDominanceGroup(1);
actorB->setDominanceGroup(2);

mScene->setDominanceGroupPair(1, 2, PxDominanceGroupPair(0.f, 1.f));

Dominance values will not affect joints. Local mass modification on joints must be performed using the following methods on PxJoint:

virtual void setInvMassScale0(PxReal invMassScale) = 0;
virtual void setInvMassScale1(PxReal invMassScale) = 0;
virtual void setInvInertiaScale0(PxReal invInertiaScale) = 0;
virtual void setInvInertiaScale1(PxReal invInertiaScale) = 0;

As previously mentioned, dominance does not permit values other than 0 or 1 and any dominance values are applied uniformly to both the inverse mass and inverse inertia. 但是, Joints and contacts through contact modification permit defining separate inverse mass and inverse inertia scales, which accept any values within the range [0, PX_MAX_REAL] so can be used to achieve a wider range of effects than dominance can.  --- 對比了兩種修改質量大小的方法。

Dominance can produce some very peculiar results if misused. For example, given bodies A, B and C configured in the following way:

  • Body A dominates body B
  • Body B dominance body C
  • Body C dominates body A

In this situation, body A cannot push body C directly. However, it can push body C if it pushes body B into body C.  -- 使用的時候注意邏輯。!!



Solver Iterations

---constraint solver應該是一個求解器吧, 迭代求解的次數越多,結果越準。

When the motion of a rigid body is constrained either by contacts or joints, the constraint solver comes into play. The solver satisfies the constraints on the bodies by iterating over all the constraints restricting the motion of the body a certain number of times. The more iterations, the more accurate the results become. The solver iteration count defaults to 4 position iterations and 1 velocity iteration(因爲位置求解是解非線性方程,速度求解是在位置求解的基礎上的線性方程哦,我之前都做過). Those counts may be set individually for each body using the following function:

void PxRigidDynamic::setSolverIterationCounts(PxU32 minPositionIters, PxU32 minVelocityIters);

Typically it is only necessary to significantly increase these values for objects with lots of joints and a small tolerance for joint error. If you find a need to use a setting higher than 30, you may wish to reconsider the configuration of your simulation.

The solver groups contacts into friction patches; friction patches are groups of contacts which share the same materials and have similar contact normals. However, the solver permits a maximum of 32 friction patches per contact manager (pair of shapes). If more than 32 friction patches are produced, which may be due to very complex collision geometry or very large contact offsets, the solver will ignore the remaining friction patches. A warning will be issues in checked/debug builds when this happens.



Immediate Mode

該部分或許需要先學習solver等,才能理解。

In addition to simulation using a PxScene, PhysX offers a low-level simulation API called "immediate mode". This provides an API to access the low-level contact generation and constraint solver. This approach currently only supports CPU rigid bodies and reduced coordinate articulations. It does not support maximal coordinate articulations.

---immediate mode 就是一些low level simulation API,使用這些api可以代替PxScene來進行仿真。牛逼。

 

The immediate mode API is defined in PxImmediateMode.h and there are two Snippets demonstrating its usage: "SnippetImmediateMode" and "SnippetImmediateArticulation".      The first one does not use articulations and shows how to use the API for rigid bodies and joints that still belong to a PxScene. This can be used e.g. to simulate a specific actor of a scene with a higher frequency than the rest of the scene.           The second snippet is a "pure" immediate mode example where all involved actors, joints and articulations exist without the need for PxScene, PxActor or PxArticulation objects.

---提供了兩個如何使用immediate model api的例子, 第一個例子,仍然使用了PxScene, 第二個例子完全擺脫了PxSecne,是一個純正的immediate mode 例子。

 

The immediate mode API provides a function to perform contact generation:

PX_C_EXPORT PX_PHYSX_CORE_API bool PxGenerateContacts(

const PxGeometry* const * geom0, const PxGeometry* const * geom1,

const PxTransform* pose0,        const PxTransform* pose1,

PxCache* contactCache,

const PxU32 nbPairs,

PxContactRecorder& contactRecorder,

const PxReal contactDistance,

const PxReal meshContactMargin,

const PxReal toleranceLength, PxCacheAllocator& allocator);

 

This function takes a set of pairs of PxGeometry objects located at specific poses and performs collision detection between the pairs. If the pair of geometries collide, contacts are generated, which are reported to contactRecorder. In addition, information may be cached in contactCache to accelerate future queries between these pairs of geometries. Any memory required for this cached information will be allocated using allocator.

 

In addition, the immediate mode provides APIs for the constraint solver. These include functions to create bodies used by the solver:

PX_C_EXPORT PX_PHYSX_CORE_API void PxConstructSolverBodies(const PxRigidBodyData* inRigidData,
 PxSolverBodyData* outSolverBodyData, const PxU32 nbBodies,
 const PxVec3& gravity, const PxReal dt);

PX_C_EXPORT PX_PHYSX_CORE_API void PxConstructStaticSolverBody(const PxTransform& globalPose, 
                                                               PxSolverBodyData& solverBodyData);

In addition to constructing the bodies, PxConstructSolverBodies also integrates the provided gravitational acceleration into the bodies velocities.

The following function is optional and is used to batch constraints:

PX_C_EXPORT PX_PHYSX_CORE_API PxU32 PxBatchConstraints( const PxSolverConstraintDesc* solverConstraintDescs, const PxU32 nbConstraints,
 PxSolverBody* solverBodies, const PxU32 nbBodies,
 PxConstraintBatchHeader* outBatchHeaders, PxSolverConstraintDesc* outOrderedConstraintDescs,
 Dy::ArticulationV** articulations=NULL, const PxU32 nbArticulations=0);

Batching constraints reorders the provided constraints and produces batchHeaders, which can be used by the solver to accelerate constraint solving by grouping together independent constraints and solving them in parallel using multiple lanes in SIMD registers. This process is entirely optional and can bypassed if not desired. Note that this will change the order in which constraints are processed, which can change the outcome of the solver.   -----SIMD全稱Single Instruction Multiple Data,單指令多數據流,能夠複製多個操作數,並把它們打包在大型寄存器的一組指令集。

The following methods is provided to create contact constraints:

PX_C_EXPORT PX_PHYSX_CORE_API bool PxCreateContactConstraints(PxConstraintBatchHeader* batchHeaders, 
const PxU32 nbHeaders, 
PxSolverContactDesc* contactDescs,
PxConstraintAllocator& allocator, 
const PxReal invDt, 
const PxReal bounceThreshold, const PxReal frictionOffsetThreshold, 
const PxReal correlationDistance);

This method can be provided with the contacts produced by PxGenerateContacts or by contacts produced by application-specific contact generation approaches.

The following methods are provided to create joint constraints:

PX_C_EXPORT PX_PHYSX_CORE_API bool PxCreateJointConstraints(PxConstraintBatchHeader* batchHeaders,
 const PxU32 nbHeaders, PxSolverConstraintPrepDesc* jointDescs, PxConstraintAllocator& allocator,
 const PxReal dt, const PxReal invDt);

PX_C_EXPORT PX_PHYSX_CORE_API bool PxCreateJointConstraintsWithShaders(PxConstraintBatchHeader* batchHeaders, 
const PxU32 nbBatchHeaders,
PxConstraint** constraints, PxSolverConstraintPrepDesc* jointDescs,
PxConstraintAllocator& allocator, const PxReal dt, const PxReal invDt);

PX_C_EXPORT PX_PHYSX_CORE_API bool PxCreateJointConstraintsWithImmediateShaders(PxConstraintBatchHeader* batchHeaders, 
const PxU32 nbBatchHeaders, 
immConstraint* constraints, 
PxSolverConstraintPrepDesc* jointDescs,
                                                                                                                                                                PxConstraintAllocator& allocator, const PxReal dt, const PxReal invDt);

The methods provide a mechanism for the application to define joint rows or for the application to make use of PhysX PxConstraint objects, which create the constraint rows.

The following method solves the constraints:

PX_C_EXPORT PX_PHYSX_CORE_API void PxSolveConstraints(const PxConstraintBatchHeader* batchHeaders, const PxU32 nbBatchHeaders, const PxSolverConstraintDesc* solverConstraintDescs,
        const PxSolverBody* solverBodies, PxVec3* linearMotionVelocity, PxVec3* angularMotionVelocity, const PxU32 nbSolverBodies, const PxU32 nbPositionIterations, const PxU32 nbVelocityIterations,
        const float dt=0.0f, const float invDt=0.0f, const PxU32 nbSolverArticulations=0, Dy::ArticulationV** solverArticulations=NULL);

This method performs all required position and velocity iterations and updates the objects' delta velocities and motion velocities, which are stored in PxSolverBody and linear/angularMotionVelocity respectively.

The following method is provided to integrate the bodies' final poses and update the bodies' velocities to reflect the motion produced by the constraint solver:

PX_C_EXPORT PX_PHYSX_CORE_API void PxIntegrateSolverBodies(PxSolverBodyData* solverBodyData, PxSolverBody* solverBody, const PxVec3* linearMotionVelocity, const PxVec3* angularMotionState, const PxU32 nbBodiesToIntegrate,
const PxReal dt);

The above methods are the ones needed for simulating regular rigid bodies and joints in immediate mode. See SnippetImmediateMode for an example.

Additional functions are provided to simulate reduced coordinate articulations. First, register articulation-related solver functions with PxRegisterImmediateArticulations:

PX_C_EXPORT PX_PHYSX_CORE_API void PxRegisterImmediateArticulations();

This is the counterpart of PxRegisterArticulationsReducedCoordinate for immediate mode. You only need to call it once at the start of your program. Then create a low-level reduced coordinate articulations with the following function:

PX_C_EXPORT PX_PHYSX_CORE_API Dy::ArticulationV*        PxCreateFeatherstoneArticulation(const PxFeatherstoneArticulationData& data);

Once the articulation is created, add articulation links to it with the following function:

PX_C_EXPORT PX_PHYSX_CORE_API Dy::ArticulationLinkHandle        PxAddArticulationLink(Dy::ArticulationV* articulation, const PxFeatherstoneArticulationLinkData& data, bool isLastLink=false);

The number of links per articulation is currently limited to 64, just as with PxScene-level articulations. After all links have been added, the articulation is ready to be simulated.

Note that for articulations the current API is not as "immediate" as for rigid bodies, since the returned object is still a thin "retained mode" wrapper around low-level structures. This is done to make articulations easier to use: the low-level structures currently contain data for both reduced coordinate and maximal coordinate articulations, and intimate knowledge of PhysX's internals is needed to distinguish between the two. The thin wrapper makes things more accessible. On the other hand, the data is not directly owned by the user, and the following function must be called to eventually release it at the end of your program:

PX_C_EXPORT PX_PHYSX_CORE_API void      PxReleaseArticulation(Dy::ArticulationV* articulation);

Meanwhile there are a number of data accessor functions available:

PX_C_EXPORT PX_PHYSX_CORE_API Dy::ArticulationV*        PxGetLinkArticulation(const Dy::ArticulationLinkHandle link);
PX_C_EXPORT PX_PHYSX_CORE_API PxU32     PxGetLinkIndex(const Dy::ArticulationLinkHandle link);
PX_C_EXPORT PX_PHYSX_CORE_API bool      PxGetLinkData(const Dy::ArticulationLinkHandle link, PxLinkData& data);
PX_C_EXPORT PX_PHYSX_CORE_API PxU32     PxGetAllLinkData(const Dy::ArticulationV* articulation, PxLinkData* data);
PX_C_EXPORT PX_PHYSX_CORE_API bool      PxGetMutableLinkData(const Dy::ArticulationLinkHandle link, PxMutableLinkData& data);
PX_C_EXPORT PX_PHYSX_CORE_API bool      PxSetMutableLinkData(Dy::ArticulationLinkHandle link, const PxMutableLinkData& data);
PX_C_EXPORT PX_PHYSX_CORE_API bool      PxGetJointData(const Dy::ArticulationLinkHandle link, PxFeatherstoneArticulationJointData& data);
PX_C_EXPORT PX_PHYSX_CORE_API bool      PxSetJointData(Dy::ArticulationLinkHandle link, const PxFeatherstoneArticulationJointData& data);

Some of them are here to update the data at runtime, say for articulation drives. Some of them are needed to setup the articulation data for aforementioned immediate mode functions like PxSolveConstraints, which have been updated in PhysX 4.1 to take additional articulation-related parameters (but which should otherwise be used the same way as for immediate mode rigid bodies).

The only new articulation-specific functions are otherwise:

PX_C_EXPORT PX_PHYSX_CORE_API void      PxComputeUnconstrainedVelocities(Dy::ArticulationV* articulation, const PxVec3& gravity, const PxReal dt);
PX_C_EXPORT PX_PHYSX_CORE_API void      PxUpdateArticulationBodies(Dy::ArticulationV* articulation, const PxReal dt);

Use the first one at the start of the simulation loop to compute unconstrained velocities for each immediate mode articulations. Use the second one at the end of the simulation loop to update the articulation bodies/links after PxIntegrateSolverBodies has finished. Please refer to SnippetImmediateArticulation for examples.



Enhanced Determinism

PhysX provides limited deterministic simulation. Specifically, the results of the simulation will be identical between runs if simulating the exact same scene (same actors inserted in the same order) using the same time-stepping scheme and same PhysX release running on the same platform. The simulation behavior is not influenced by the number of worker threads that are used.

----Physx的仿真在相同條件下運行多次的話,每次的運行結果時是一致的。

However, the results of the simulation can change if actors are inserted in a different order.  In addition, the overall behavior of the simulation can change if additional actors are added or if some actors are removed from the scene. This means that the simulation of a particular collection of actors can change depending on whether other actors are present in the scene or not, irrespective of whether these actors actually interact with the collection of actors. This behavioral property is usually tolerable but there are circumstances in which it is not acceptable.

----有一些因素會影響仿真結果,例如,actors被插入到場景中的順序等等/

To overcome this issue, PhysX provides a flag: PxSceneFlag::eENABLE_ENHANCED_DETERMINISM, which provides additional levels of determinism.   Specifically, provided the application inserts the actors in a deterministic order, with this flag raised, the simulation of an island will be identical regardless of any other islands in the scene. However, this mode sacrifices some performance to ensure this additional determinism.

----使用PxSceneFlag::eENABLE_ENHANCED_DETERMINISM可以克服上面提到的仿真結果不同的缺點,但是以降低一些性能爲代價



Axis locking

It is possible to restrict motion along or around specific world-space axes in PhysX using PxRigidDynamicLockFlag. For example, the below code snippet demonstrates how to restrict a PxRigidDynamic to two dimensional simulation. In this case, we permit the PxRigidDynamic to rotate only around the Z-axis and to translate only along the X- and Y- axes:
----提供了限制一個物體某個方向的自由度的功能哦。

PxRigidDynamic* dyn = physics.createRigidDynamic(PxTransform(PxVec3(0.f, 2.5f, 0.f)));

...

//Lock the motion
dyn->setRigidDynamicLockFlags(
PxRigidDynamicLockFlag::eLOCK_LINEAR_Z | 
PxRigidDynamicLockFlag::eLOCK_ANGULAR_X | 
PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y);

It is legal to restrict movement or rotation around any combination of the 6 degrees of freedom.



Temporal Gauss-Seidel

---簡單介紹了兩種solver

PhysX provides a default Projected Gauss-Seidel-style (PGS) solver and an optional Temporal Gauss-Seidel (TGS) solver.

Temporal gauss-seidel offers several advantages over the PGS-style solver: - Dramatically improved convergence - Improved handling of high-mass ratios - Minimizes energy introduced when correcting penetrations (depending on solver convergence) - Improved joint drive accuracy

TGS is generally a little slower than PGS. This is partially due to the increased complexity of the constraint solver and also partially due to TGS solving friction constraints every iteration, whereas PGS solves friction constraints only in the final 3 position iterations by default.

Enabling the TGS solver requires setting PxSceneDesc::solverType to PxSolverType::eTGS. This is an immutable scene property that must be set before the scene is constructed.

The TGS solver is available when using both CPU and GPU simulation.

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章