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

Experimenting with DOTS and Physics

Discussion in 'Physics for ECS' started by Adraesh, Jan 29, 2021.

  1. Adraesh

    Adraesh

    Joined:
    Jan 3, 2019
    Posts:
    13
    Hi guys,

    I am simply trying to experiement with DOTS and Physics by simulating car suspension physics.

    Everything "seems" to be set as it should be but it's not working, the car still falls on the ground without any suspension force applied. I am not just sure from where the issue comes from so attached you will find the piece of code I did to check if you have any idea.

    Code (CSharp):
    1.  
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.Transforms;
    5. using Unity.Physics;
    6. using Unity.Physics.Systems;
    7. using UnityEngine;
    8. using Unity.Physics.Extensions;
    9. using Unity.Mathematics;
    10.  
    11. [UpdateAfter(typeof(ExportPhysicsWorld))]
    12. [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    13. public class CarSuspensionSystem : SystemBase
    14. {
    15.     private BuildPhysicsWorld buildPhysicsWorld;
    16.     private CollisionWorld collisionWorld;
    17.  
    18.     private float minLength;
    19.     private float maxLength;
    20.     private float lastLength;
    21.     private float springLength;
    22.     private float springVelocity;
    23.     private float springForce;
    24.     private float damperForce;
    25.  
    26.     private float3 suspensionForce;
    27.  
    28.     protected override void OnStartRunning()
    29.     {
    30.         buildPhysicsWorld = World.DefaultGameObjectInjectionWorld.GetExistingSystem<BuildPhysicsWorld>();
    31.         collisionWorld = buildPhysicsWorld.PhysicsWorld.CollisionWorld;
    32.     }
    33.  
    34.     protected override void OnUpdate()
    35.     {
    36.         Entities
    37.             .WithoutBurst()
    38.             .ForEach((in CarWheelData carWheelData, in LocalToWorld localToWorld, in Parent parent) => {
    39.                 minLength = carWheelData.restLength - carWheelData.springTravel;
    40.                 maxLength = carWheelData.restLength + carWheelData.springTravel;
    41.  
    42.                 RaycastInput raycastInput = new RaycastInput
    43.                 {
    44.                     Start = localToWorld.Position,
    45.                     End = -localToWorld.Up * (maxLength + carWheelData.wheelRadius),
    46.                     Filter = CollisionFilter.Default,
    47.                 };
    48.  
    49.                 Debug.DrawRay(localToWorld.Position, -localToWorld.Up * (maxLength + carWheelData.wheelRadius), Color.green);
    50.                
    51.                 Unity.Physics.RaycastHit raycastHit = new Unity.Physics.RaycastHit();
    52.                 if (collisionWorld.CastRay(raycastInput, out raycastHit))
    53.                 {
    54.                     lastLength = springLength;
    55.  
    56.                     springLength = Mathf.Clamp(Vector3.Distance(raycastInput.Start, raycastHit.Position) - carWheelData.wheelRadius, minLength, maxLength);
    57.                     springVelocity = lastLength - springLength;
    58.                     springForce = carWheelData.springStiffness * (carWheelData.restLength - springLength);
    59.                     damperForce = carWheelData.damperStiffness * springVelocity;
    60.  
    61.                     suspensionForce = (springForce + damperForce) * localToWorld.Up;
    62.  
    63.                     PhysicsVelocity parentPhysicsVelocity = GetComponent<PhysicsVelocity>(parent.Value);
    64.                     PhysicsMass parentPhysicsMass = GetComponent<PhysicsMass>(parent.Value);
    65.                     Translation parentTranslation = GetComponent<Translation>(parent.Value);
    66.                     Rotation parentRotation = GetComponent<Rotation>(parent.Value);
    67.  
    68.                     parentPhysicsVelocity.ApplyImpulse(parentPhysicsMass, parentTranslation, parentRotation, suspensionForce, raycastHit.Position);
    69.                 }
    70.         }).Run();
    71.     }
    72. }
    73.  
    Thank you very much!
     

    Attached Files:

    Last edited: Jan 29, 2021
  2. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    hi @Adraesh, I didn't go into the calculations, but here are some hints to start with:
    1. Check "Synchronize Collision World" in your Physics Step component - this will make the raycasts you perform after export work on the fresh physics state. Without that, the query would be done on the physics state from the frame start. This doesn't need to stay checked, I just want to see if it improves things.
    2. Try drawing small points/spheres at raycastHit.Position and printing suspensionForce and parentPhysicsMass.InverseMass to see if your code is trying to apply any impulse at all
     
  3. Adraesh

    Adraesh

    Joined:
    Jan 3, 2019
    Posts:
    13
    Hi Milos and thank you for your answer.

    1. By activating Synchronize Collision World I get the bellow error:

    InvalidOperationException: The previously scheduled job CollisionWorld:UpdateRigidBodyTransformsJob writes to the Unity.Collections.NativeArray`1[Unity.Physics.RigidBody] UpdateRigidBodyTransformsJob.RigidBodies. You must call JobHandle.Complete() on the job CollisionWorld:UpdateRigidBodyTransformsJob, before you can read from the Unity.Collections.NativeArray`1[Unity.Physics.RigidBody] safely.


    2. I have no idea how to draw a small,point even though I have the raycastHit.position, if you could help on this? Otherwhise I printed the 2 values for suspensionForce and Invert mass:


    Suspension Force: float3(0.1194021f, 8213.999f, -0.2229677f)
    Parent Inverse Mass: 0.0005555556


    Thank you again!
     
  4. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Ohhh, yes, I totally forgot about 1 thing: you need to wait for the output job of ExportPhysicsWorld to complete in any case. So, please do this at the start of your onUpdate:
    World.GetOrCreateSystem<ExportPhysicsWorld>().GetOutputDependency().Complete()
    .
     
  5. Adraesh

    Adraesh

    Joined:
    Jan 3, 2019
    Posts:
    13
    Thank you again!

    It's compiling but it does not change anything. I guess I am gonna have to look deeper into it :)
     
  6. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Ahh, you're not actually writing the PhysicsVelocity back to the Entity! Try calling
    SetComponent(parent.Value, parentPhysicsVelocity);
    at the end and you'll also probably need to change the Parent param to "ref" (instead of "in") in the ForEach lambda.
    These are structs, so GetComponent will actually give you a copy and changing it won't affect the original value on the Entity. Sorry for missing this initially.
     
    Last edited: Jan 29, 2021
  7. Adraesh

    Adraesh

    Joined:
    Jan 3, 2019
    Posts:
    13
    Oh yes! Thank you it's start working! Not completely but better.

    I guess I have now somehow to exclude my car object from being hit by the Raycast as it's hitting itself now and I want to hit only the floor.

    I will dig into ColliderFilter struc probably this could be achieved with Layer I guess...

    Thanks again!
     
  8. Adraesh

    Adraesh

    Joined:
    Jan 3, 2019
    Posts:
    13
    Humm, following the doc:


    Note: Rays starting inside primitives (spheres, capsules, box and convex shapes) confirm a hit at the starting point, but do not report another intersection as the ray leaves the volume.


    Which is exactly my case, so I am filtering the RayCastInput to only collides with the layer my floor is on (index 6).

    Code (CSharp):
    1. RaycastInput raycastInput = new RaycastInput
    2.                 {
    3.                     Start = localToWorld.Position,
    4.                     End = -localToWorld.Up * (maxLength + carWheelData.wheelRadius),
    5.                     Filter =
    6.                     {
    7.                         CollidesWith = 1u << 6
    8.                     }
    9.                 };
    But it does not register any hit anymore now...

    Attached screen shot that display the raycast where it should be and showing that it hits with the floor.
     

    Attached Files:

  9. Lukas_Kastern

    Lukas_Kastern

    Joined:
    Aug 31, 2018
    Posts:
    97
  10. Adraesh

    Adraesh

    Joined:
    Jan 3, 2019
    Posts:
    13
    Yes, still by adding BelongsTo it will register the hit on the primitive the Ray starts in even though I set this primitive to be on a different layer than 6 and filtered the RayCast.

    Seems there is no other way than not using a primitive.
     
  11. Adraesh

    Adraesh

    Joined:
    Jan 3, 2019
    Posts:
    13
    I managed to make it work by excluding the layer I wanted to.

    Please note that BelongsTo and CollidesWith does not expect a bitmaks of a Layer (Top right of Unity Editor) but a CollisionLayer that you can set via a PhysicsShape Component.