Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved How to achieve one AddForceAtPosition in Ecs 1.0.11 (2023) using Unity.Physics

Discussion in 'Physics for ECS' started by RaveOnTheGrave, Aug 10, 2023.

  1. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    27
    Problem with Physics conversion
    I'm translating a script to an ECS system where AddForceAtPosition() is used a few times. The problem is that I can't get the same behavior from ApplyImpulse() (in Physics Extentions). The fact is that these two methods behave differently, you need to select the settings again (if the correct settings exist at all), and this is not very successful for me.
    If anyone has also encountered this problem, tell me a variant that is more or less similar in effect to AddForceAtPosition().

    Here is the code I am using for the conversion:

    Code (CSharp):
    1.         public static void AddForceAtPosition(
    2.             this ref PhysicsVelocity velocity,
    3.             float3 force, float3 position, PhysicsMass mass,
    4.             float3 translation, quaternion rotation,
    5.             float dt, ForceMode mode = ForceMode.Force)
    6.         {
    7.             GetImpulseFromForce(mass, force, out float3 impulse,
    8.                                 out PhysicsMass impulseMass, dt, mode);
    9.             velocity.ApplyImpulse(impulseMass, translation, rotation, impulse, position);
    10.         }
    11.        
    12.         private static void GetImpulseFromForce(
    13.             PhysicsMass mass, float3 force,
    14.             out float3 impulse, out PhysicsMass impulseMass,
    15.             float dt, ForceMode mode = ForceMode.Force)
    16.         {
    17.             var unitMass = new PhysicsMass { InverseInertia = new float3(1.0f),
    18.                                              InverseMass = 1.0f,
    19.                                              Transform = mass.Transform };
    20.             switch (mode)
    21.             {
    22.                 case ForceMode.Force:
    23.                     // Add a continuous force to the rigidbody, using its mass.
    24.                     impulseMass = mass;
    25.                     impulse = force * dt;
    26.                     break;
    27.                 case ForceMode.Acceleration:
    28.                     // Add a continuous acceleration to the rigidbody, ignoring its mass.
    29.                     impulseMass = unitMass;
    30.                     impulse = force * dt;
    31.                     break;
    32.                 case ForceMode.Impulse:
    33.                     // Add an instant force impulse to the rigidbody, using its mass.
    34.                     impulseMass = mass;
    35.                     impulse = force;
    36.                     break;
    37.                 case ForceMode.VelocityChange:
    38.                     // Add an instant velocity change to the rigidbody, ignoring its mass.
    39.                     impulseMass = unitMass;
    40.                     impulse = force;
    41.                     break;
    42.                 default:
    43.                     impulseMass = mass;
    44.                     impulse = float3.zero;
    45.                     break;
    46.             }
    47.         }
     
  2. Tigrian

    Tigrian

    Joined:
    Mar 21, 2021
    Posts:
    105
    I think from what i read in your description that your problem is on code conversion, and not that the actual physic behaviour of your method is different from classic rigidbody. You would like an ecs method to have this signature :
    Code (CSharp):
    1. public static void AddForceAtPosition(this ref PhysicsVelocity, float3 force, float position, ForceMode mode)
    like the rigidbody one from gameObjects.

    I believe that unfortunately, this is not possible in a performant way (without some GetComponent directly in the method, which would be absurd because they can be included in the query of the PhysicsVelocity). The reason why the rigidbody method is able to have so few parameters is because it caches data like mass, or transform inside the Rigidbody monobehaviour. I do not agree that these parameters sometimes don't exist (as you said "if the correct settings exist at all"). You need a transform to apply this type of method (i mean your object is dynamic), but as every gameobject has a transform in gameobjects, the rigidbody method knows where to look. You need mass properties to apply this method (again, as your rigidbody is dynamic), but as it is cached in the rigidbody in gameobjects, it knows where to look. But in ecs, you cannot be sure your entity has both the transform, physics velocity and physics mass at the same time, and if they do, it is better to include them in your query, and not do a GetComponent.

    That is why i believe the only optimization you can make in your method is to set the timestep directly in it. All the other settings are mandatory, and should be always available (i mean you can always include the transform and the mass in your query).

    If the physics velocity you add force to is accessed from a component lookup, you can add a temporary component to that entity, with the position and force data, and process it in an other system, running after this one in the physic step.
     
    Last edited: Aug 14, 2023
  3. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    27
    Unfortunately, the method signature is not a problem at all, all I need is that, given the same parameters, these methods act the same way. If I take a gameobject and an entity and apply the same force to the same point, the result should be about the same. I never succeeded in this behavior. I think the problem is in the force to torque conversion code. In ecs we have this code, but in UnityEngine it is unfortunately an external call.
     
    Last edited: Aug 15, 2023
  4. MidnightCow

    MidnightCow

    Joined:
    Jun 2, 2017
    Posts:
    30
    I think possibly:

    PhysicsWorldExtensions.ApplyImpulse

    I think to change from force to impulse mult by fixed deltaTime..

    [EDIT]

    Sorry just re-reading what you posted.. it seems you are already using pv.ApplyImpulse and some method to convert force to impulse.. Maybe the PhysicsWorldExtensions version of apply impulse works differently, i'm not sure - worth a try!
     
    Last edited: Aug 15, 2023
  5. Tigrian

    Tigrian

    Joined:
    Mar 21, 2021
    Posts:
    105
    Oh, my bad, i thought you had a problem actually converting the code (gathering the transform and mass data). I'll check the two version, to see the physics difference you are talking about. About the rigidbody method being inaccessible because of external call, this should be a nvidia PhysX implementation call, so you can actually check the code behind it (but it is c++) :
    https://github.com/NVIDIAGameWorks/.../physxextensions/src/ExtRigidBodyExt.cpp#L393
     
  6. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    27
    This is code under // Angular for converting force to torque. It looks like PhysX does it in a different way. I'll try to figure it out)

    Code (CSharp):
    1.  
    2.         var mass = pm.ApplyScale(bodyScale);
    3.             // Linear
    4.             pv.ApplyLinearImpulse(mass, impulse);
    5.  
    6.             // Angular
    7.             {
    8.                 // Calculate point impulse
    9.                 var worldFromEntity = new RigidTransform(r, t);
    10.                 var worldFromMotion = math.mul(worldFromEntity, mass.Transform);
    11.                 float3 angularImpulseWorldSpace = math.cross(point - worldFromMotion.pos, impulse);
    12.                 float3 angularImpulseInertiaSpace = math.rotate(math.inverse(worldFromMotion.rot), angularImpulseWorldSpace);
    13.  
    14.                 pv.ApplyAngularImpulse(mass, angularImpulseInertiaSpace);
    15.             }
     
  7. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    27
    I'll try to dig in that direction, thanks for the tip)
     
    Tigrian likes this.
  8. RaveOnTheGrave

    RaveOnTheGrave

    Joined:
    Oct 28, 2022
    Posts:
    27
    I came to the option when I use the conversion of force to impulse and PhysixExtentions.ApplyImpulse(). So far, it works better than transferring the method from PhysiX.