Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

Question Convert a Rigidebody script into a Physics Body? - Buoyancy system

Discussion in 'Physics for ECS' started by MedoMelo, Apr 21, 2020.

  1. MedoMelo

    MedoMelo

    Joined:
    Jul 5, 2019
    Posts:
    42
    Hi,

    For a DOTS seafaring game we want to use an existing very performant buoyancy system (DWP2) and make it compatible with DOTS. The buoyancy needs a Rigidebody on object so we want it functional with a Physics Body instead.
    After contacting the dev, he said the only Rigidebody function he is using in the script is: AddForceAtPosition.

    I'm wondering what is the best solutions to make it compatible. Is there a chance Unity Physics come up with support to make existing Rigidebody script work with Physics Body? Or it's not likely and it is better to just rework the script with equivalent functions (PhysicsWorld.AddImpulseAtPoint) at risk the calculations for buoyancy could give a different result on object.

    I really appreciate your help as I'm not very comfortable with DOTS Physics.
     
  2. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    This isn't complete code but you could be able to rewrote it for your own project:

    This is part of a wrapper I am working on to expose the legacy Rigidbody interface.
    Get/SetComponent are just wrappers for
    World.EntityManager.Get/SetComponentData(Entity)
    . World and Entity are store locally, hence not exposed in this function. The physics TimeStep is also held by the wrapper.

    Code (CSharp):
    1.         public void AddForceAtPosition(float3 force, float3 position, ForceMode mode = ForceMode.Force)
    2.         {
    3.             if (!isDynamic) return;
    4.  
    5.             var mass = GetComponent<PhysicsMass>();
    6.             mass.GetImpulseFromForce(force, mode, TimeStep, out float3 impulse, out PhysicsMass impulseMass);
    7.  
    8.             var translation = GetComponent<Translation>();
    9.             var rotation = GetComponent<Rotation>();
    10.             var velocity = GetComponent<PhysicsVelocity>();
    11.  
    12.             velocity.ApplyImpulse(impulseMass, translation, rotation, impulse, position);
    13.  
    14.             AddOrSetComponent(velocity);
    15.         }
    Next this extension function implements the conversation of forces into velocity changes (i.e. impulses)

    Code (CSharp):
    1.         public static void GetImpulseFromForce(this PhysicsMass mass, float3 force, UnityEngine.ForceMode mode, float timeStep, out float3 impulse, out PhysicsMass impulseMass)
    2.         {
    3.             var unitMass = new PhysicsMass { InverseInertia = new float3(1.0f), InverseMass = 1.0f, Transform = mass.Transform };
    4.  
    5.             switch (mode)
    6.             {
    7.                 case UnityEngine.ForceMode.Force:
    8.                     // Add a continuous force to the rigidbody, using its mass.
    9.                     impulseMass = mass;
    10.                     impulse = force * timeStep;
    11.                     break;
    12.                 case UnityEngine.ForceMode.Acceleration:
    13.                     // Add a continuous acceleration to the rigidbody, ignoring its mass.
    14.                     impulseMass = unitMass;
    15.                     impulse = force * timeStep;
    16.                     break;
    17.                 case UnityEngine.ForceMode.Impulse:
    18.                     // Add an instant force impulse to the rigidbody, using its mass.
    19.                     impulseMass = mass;
    20.                     impulse = force;
    21.                     break;
    22.                 case UnityEngine.ForceMode.VelocityChange:
    23.                     // Add an instant velocity change to the rigidbody, ignoring its mass.
    24.                     impulseMass = unitMass;
    25.                     impulse = force;
    26.                     break;
    27.                 default:
    28.                     impulseMass = mass;
    29.                     impulse = float3.zero;
    30.                     break;
    31.             }
    32.         }
    velocity.ApplyImpulse
    should already exist in the Unity Physics package.
     
  3. MedoMelo

    MedoMelo

    Joined:
    Jul 5, 2019
    Posts:
    42
    this looks really great, I really appreciate you share your hard work.
    We'll try it this week, I let you know how it goes
     
  4. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    How would I add Torque?
     
  5. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    So here is what I got. Its like almost there but has some issues. Here is video to see what is happening.


    • First I used ForceMode.Impulse instead of ForceMode.Acceleration because the object was getting crazy results flying out of water and stuff
    • Physics.gravity.normalized is probably not getting DOTS Gravity so it might be messing things up.
    • The objects act crazy at the beginning but stabilize. Not sure why.
    • Sometimes the objects kind of go crazy for a few moments randomly. Not sure why.
    Any feedback and help would be appreciated.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Entities;
    3. using Unity.Physics;
    4. using Unity.Mathematics;
    5. using Unity.Transforms;
    6. using UnityEngine;
    7. using Unity.Physics.Extensions;
    8. using Unity.Entities.UniversalDelegates;
    9.  
    10. namespace DOTSActorWater
    11. {
    12.     public class ActorWaterBuoyancySystem : ComponentSystem
    13.     {
    14.  
    15.         private float deltaTime;
    16.  
    17.         protected override void OnUpdate()
    18.         {
    19.             var forces = new List<float3>();
    20.             var physicsWorld = World.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>().PhysicsWorld;
    21.             deltaTime = Time.DeltaTime;
    22.  
    23.             Entities.ForEach((Entity entity, ref ActorActionWaterBuoyancyComponent actorActionWaterBuoyancyComponent, ref Translation translation,ref Rotation rotation, ref LocalToWorld localToWorld, ref PhysicsVelocity physicsVelocity, ref PhysicsMass physicsMass) =>
    24.             {
    25.                 if (actorActionWaterBuoyancyComponent.bottomDepth > 0 && !actorActionWaterBuoyancyComponent.disabled)
    26.                 {
    27.                     var velocityRelativeToWater = physicsVelocity.Linear - actorActionWaterBuoyancyComponent.waterSurfaceVelocity;
    28.                     var bottomDepth = actorActionWaterBuoyancyComponent.bottomDepth;
    29.  
    30.                     //Buoyancy
    31.                     var buoyancy = -Physics.gravity.normalized * actorActionWaterBuoyancyComponent.buoyancyCoeff * bottomDepth * bottomDepth * bottomDepth;
    32.                     physicsVelocity.Linear += (float3)buoyancy * deltaTime;
    33.  
    34.                     //Get Forces
    35.                     var forcePosition = translation.Value + actorActionWaterBuoyancyComponent.forceHeightOffset * (float3)Vector3.up;
    36.                     forces.Add(Vector3.up * Vector3.Dot(Vector3.up, -velocityRelativeToWater) * actorActionWaterBuoyancyComponent.dragInWaterUp);
    37.                     forces.Add(localToWorld.Right * Vector3.Dot(localToWorld.Right, -velocityRelativeToWater) * actorActionWaterBuoyancyComponent.dragInWaterRight);
    38.                     forces.Add(localToWorld.Forward * Vector3.Dot(localToWorld.Forward, -velocityRelativeToWater) * actorActionWaterBuoyancyComponent.dragInWaterForward);
    39.  
    40.                     //Apply Forces NEW
    41.                     for (int i = 0; i < forces.Count; i++)
    42.                         AddForceAtPosition(ref physicsMass, ref translation, ref rotation, ref physicsVelocity, forces[i], forcePosition, ForceMode.Impulse);
    43.  
    44.  
    45.  
    46.                     //Torque
    47.                     {
    48.                         var torqueWidth = (float3)Vector3.Cross(localToWorld.Up, actorActionWaterBuoyancyComponent.waterSurfaceNormal);
    49.                         var torqueLength = (float3)Vector3.Cross(localToWorld.Up, actorActionWaterBuoyancyComponent.normalLongitudinal);
    50.  
    51.                         physicsVelocity.Angular += torqueWidth * actorActionWaterBuoyancyComponent.boyancyTorque * deltaTime;
    52.                         physicsVelocity.Angular += torqueLength * actorActionWaterBuoyancyComponent.boyancyTorque * deltaTime;
    53.  
    54.                     }
    55.                 }
    56.             });
    57.  
    58.         }
    59.  
    60.         private void AddForceAtPosition(ref PhysicsMass physicsMass, ref Translation translation, ref Rotation rotation, ref PhysicsVelocity velocity, float3 force, float3 position, ForceMode mode = ForceMode.Force)
    61.         {
    62.  
    63.             GetImpulseFromForce(ref physicsMass, force, mode, deltaTime, out float3 impulse, out PhysicsMass impulseMass);
    64.             velocity.ApplyImpulse(impulseMass, translation, rotation, impulse, position);
    65.         }
    66.  
    67.         private void AddAngularImpulseAtPosition(ref PhysicsMass physicsMass, ref PhysicsVelocity velocity, float3 force, float3 position, ForceMode mode = ForceMode.Force)
    68.         {
    69.  
    70.             GetImpulseFromForce(ref physicsMass, force, mode, deltaTime, out float3 impulse, out PhysicsMass impulseMass);
    71.             velocity.ApplyAngularImpulse(physicsMass, impulse);
    72.         }
    73.  
    74.  
    75.         private void GetImpulseFromForce(ref PhysicsMass mass, float3 force, UnityEngine.ForceMode mode, float timeStep, out float3 impulse, out PhysicsMass impulseMass)
    76.         {
    77.             var unitMass = new PhysicsMass { InverseInertia = new float3(1.0f), InverseMass = 1.0f, Transform = mass.Transform };
    78.  
    79.  
    80.             switch (mode)
    81.             {
    82.                 case UnityEngine.ForceMode.Force:
    83.                     // Add a continuous force to the rigidbody, using its mass.
    84.                     impulseMass = mass;
    85.                     impulse = force * timeStep;
    86.                     break;
    87.                 case UnityEngine.ForceMode.Acceleration:
    88.                     // Add a continuous acceleration to the rigidbody, ignoring its mass.
    89.                     impulseMass = unitMass;
    90.                     impulse = force * timeStep;
    91.                     break;
    92.                 case UnityEngine.ForceMode.Impulse:
    93.                     // Add an instant force impulse to the rigidbody, using its mass.
    94.                     impulseMass = mass;
    95.                     impulse = force;
    96.                     break;
    97.                 case UnityEngine.ForceMode.VelocityChange:
    98.                     // Add an instant velocity change to the rigidbody, ignoring its mass.
    99.                     impulseMass = unitMass;
    100.                     impulse = force;
    101.                     break;
    102.                 default:
    103.                     impulseMass = mass;
    104.                     impulse = float3.zero;
    105.                     break;
    106.             }
    107.         }
    108.  
    109.     }
    110. }
     
  6. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    Here is updated and better code. I like the results.
    The Physics Body has linear and angular damping set to 1 for objects. Mass is pretty high such as 1240000 for boat. Gravity is 1.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Entities;
    3. using Unity.Physics;
    4. using Unity.Mathematics;
    5. using Unity.Transforms;
    6. using UnityEngine;
    7. using Unity.Physics.Extensions;
    8. using Unity.Entities.UniversalDelegates;
    9. using Crest;
    10. using UnityEditor.Build.Pipeline;
    11.  
    12. namespace DOTSActorWater
    13. {
    14.     [UpdateAfter(typeof(Unity.Physics.Systems.StepPhysicsWorld))]
    15.     public class ActorWaterBuoyancySimpleSystem : ComponentSystem
    16.     {
    17.         private SampleHeightHelper sampleHeightHelper;
    18.         private SampleFlowHelper sampleFlowHelper;
    19.         private Vector3 _displacementToObject;
    20.  
    21.         private float3 position;
    22.         private Vector3 normal;
    23.         private Vector3 waterSurfaceVel;
    24.  
    25.         private Vector3 undispPos;
    26.         private Vector3 dispPos;
    27.         private float bottomDepth;
    28.  
    29.         private Dictionary<int, SampleHeightHelper> sampleHeightHelpers = new Dictionary<int, SampleHeightHelper>();
    30.         private Dictionary<int, SampleHeightHelper> sampleHeightLengthHelpers = new Dictionary<int, SampleHeightHelper>();
    31.         private Dictionary<int, SampleFlowHelper> sampleFlowHelpers = new Dictionary<int, SampleFlowHelper>();
    32.  
    33.         private float deltaTime;
    34.  
    35.         protected override void OnUpdate()
    36.         {
    37.             deltaTime = Time.DeltaTime;
    38.  
    39.             CrestScanner();
    40.             DoBuoyancy();
    41.         }
    42.  
    43.         private void CrestScanner()
    44.         {
    45.             //Check For Ocean Rendrer
    46.             if (OceanRenderer.Instance == null)
    47.                 return;
    48.  
    49.             var collProvider = OceanRenderer.Instance.CollisionProvider;
    50.             var deltaTime = Time.DeltaTime;
    51.  
    52.             Entities.ForEach((Entity entity, ref ActorActionWaterBuoyancySimpleComponent actorActionWaterBuoyancyComponent, ref Translation translation, ref LocalToWorld localToWorld) =>
    53.             {
    54.                 position = translation.Value;
    55.                 normal = Vector3.up;
    56.                 waterSurfaceVel = Vector3.zero;
    57.                 _displacementToObject = Vector3.zero;
    58.  
    59.                 if (!sampleHeightHelpers.ContainsKey(entity.Index))
    60.                 {
    61.                     sampleHeightHelpers.Add(entity.Index, new SampleHeightHelper());
    62.                     sampleHeightLengthHelpers.Add(entity.Index, new SampleHeightHelper());
    63.                     sampleFlowHelpers.Add(entity.Index, new SampleFlowHelper());
    64.                 }
    65.                 sampleFlowHelper = sampleFlowHelpers[entity.Index];
    66.                 sampleHeightHelper = sampleHeightHelpers[entity.Index];
    67.  
    68.                 sampleHeightHelper.Init(position, actorActionWaterBuoyancyComponent.objectWidth);
    69.                 sampleHeightHelper.Sample(ref _displacementToObject, ref normal, ref waterSurfaceVel);
    70.  
    71.                 if (QueryFlow.Instance)
    72.                 {
    73.                     sampleFlowHelper.Init(position, actorActionWaterBuoyancyComponent.objectWidth);
    74.  
    75.                     Vector2 surfaceFlow = Vector2.zero;
    76.                     sampleFlowHelper.Sample(ref surfaceFlow);
    77.                     waterSurfaceVel += new Vector3(surfaceFlow.x, 0, surfaceFlow.y);
    78.                 }
    79.  
    80.                 actorActionWaterBuoyancyComponent.waterSurfaceVelocity = waterSurfaceVel;
    81.                 actorActionWaterBuoyancyComponent.waterSurfaceNormal = normal;
    82.  
    83.  
    84.                 undispPos = (Vector3)position - _displacementToObject;
    85.                 undispPos.y = OceanRenderer.Instance.SeaLevel;
    86.                 dispPos = undispPos + _displacementToObject;
    87.  
    88.                 //Get Bottom Of Object
    89.                 bottomDepth = dispPos.y - position.y + actorActionWaterBuoyancyComponent.buoyancyBottomHeight;
    90.                 actorActionWaterBuoyancyComponent.bottomDepth = bottomDepth;
    91.  
    92.                 actorActionWaterBuoyancyComponent.disabled = bottomDepth < 0;
    93.  
    94.                 sampleHeightLengthHelpers[entity.Index].Init(position, actorActionWaterBuoyancyComponent.objectLength);
    95.                 var dummy = 0f;
    96.                 var normalLongitudinal = Vector3.up;
    97.  
    98.                 if (sampleHeightLengthHelpers[entity.Index].Sample(ref dummy, ref normalLongitudinal))
    99.                 {
    100.                     var F = (Vector3)localToWorld.Forward;
    101.                     F.y = 0f;
    102.                     F.Normalize();
    103.                     normal -= Vector3.Dot(F, normal) * F;
    104.  
    105.                     var R = (Vector3)localToWorld.Right;
    106.                     R.y = 0f;
    107.                     R.Normalize();
    108.                     normalLongitudinal -= Vector3.Dot(R, normalLongitudinal) * R;
    109.  
    110.                     actorActionWaterBuoyancyComponent.normalLongitudinal = normalLongitudinal;
    111.                 }
    112.             });
    113.         }
    114.  
    115.         private void DoBuoyancy()
    116.         {
    117.             var forces = new List<float3>();
    118.             var physicsWorld = World.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>().PhysicsWorld;
    119.             Entities.ForEach((Entity entity, ref ActorActionWaterBuoyancySimpleComponent actorActionWaterBuoyancyComponent, ref Translation translation, ref Rotation rotation, ref LocalToWorld localToWorld, ref PhysicsVelocity physicsVelocity, ref PhysicsMass physicsMass) =>
    120.             {
    121.                 if (actorActionWaterBuoyancyComponent.bottomDepth > 0 && !actorActionWaterBuoyancyComponent.disabled)
    122.                 {
    123.  
    124.  
    125.                     //Buoyancy
    126.                     var bottomDepth = actorActionWaterBuoyancyComponent.bottomDepth;
    127.                     var buoyancy = -Physics.gravity.normalized * actorActionWaterBuoyancyComponent.buoyancyCoeff * bottomDepth * bottomDepth * bottomDepth;
    128.                     physicsVelocity.Linear += (float3)buoyancy * deltaTime;
    129.  
    130.                     //Get Forces
    131.                     var velocityRelativeToWater = physicsVelocity.Linear - actorActionWaterBuoyancyComponent.waterSurfaceVelocity;
    132.                     var forcePosition = translation.Value + actorActionWaterBuoyancyComponent.forceHeightOffset * (float3)Vector3.up;
    133.                     forces.Add(Vector3.up * Vector3.Dot(Vector3.up, -velocityRelativeToWater) * actorActionWaterBuoyancyComponent.dragInWaterUp);
    134.                     forces.Add(localToWorld.Right * Vector3.Dot(localToWorld.Right, -velocityRelativeToWater) * actorActionWaterBuoyancyComponent.dragInWaterRight);
    135.                     forces.Add(localToWorld.Forward * Vector3.Dot(localToWorld.Forward, -velocityRelativeToWater) * actorActionWaterBuoyancyComponent.dragInWaterForward);
    136.  
    137.                     //Apply Forces
    138.                     for (int i = 0; i < forces.Count; i++)
    139.                         physicsVelocity.ApplyImpulse(physicsMass, translation, rotation, forces[i], forcePosition);
    140.  
    141.                     //Torque
    142.                     {
    143.                         var torqueWidth = (float3)Vector3.Cross(localToWorld.Up, actorActionWaterBuoyancyComponent.waterSurfaceNormal);
    144.                         var torqueLength = (float3)Vector3.Cross(localToWorld.Up, actorActionWaterBuoyancyComponent.normalLongitudinal);
    145.  
    146.                         physicsVelocity.Angular += torqueWidth * actorActionWaterBuoyancyComponent.boyancyTorque * deltaTime;
    147.                         physicsVelocity.Angular += torqueLength * actorActionWaterBuoyancyComponent.boyancyTorque * deltaTime;
    148.  
    149.                     }
    150.                 }
    151.             });
    152.         }
    153.     }
    154. }
    Code (CSharp):
    1. using System;
    2. using System.ComponentModel;
    3. using Unity.Collections;
    4. using Unity.Entities;
    5. using Unity.Mathematics;
    6. using UnityEngine;
    7.  
    8. namespace DOTSActorWater
    9. {
    10.     [Serializable]
    11.     public struct ActorActionWaterBuoyancySimpleComponent : IComponentData
    12.     {
    13.         //Main Data
    14.         public float buoyancyBottomHeight;
    15.         public float buoyancyCoeff;
    16.         public float boyancyTorque;
    17.  
    18.         public float objectWidth;
    19.         public float objectLength;
    20.  
    21.         public float forceHeightOffset;
    22.         public float dragInWaterUp;
    23.         public float dragInWaterRight;
    24.         public float dragInWaterForward;
    25.         public float dragInWaterRotational;
    26.  
    27.         //Write Data
    28.         public float3 inverseInertia;
    29.         public float3 waterSurfaceVelocity;
    30.         public float3 waterSurfaceNormal;
    31.         public float3 normalLongitudinal;
    32.         public float bottomDepth;
    33.         public bool disabled;
    34.     }
    35. }
    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Transforms;
    3. using UnityEngine;
    4.  
    5. namespace DOTSActorWater
    6. {
    7.     public class ActorWaterBuyancySimpleAuthor : MonoBehaviour, IConvertGameObjectToEntity
    8.     {
    9.         [Header("Buoyancy")]
    10.         public float buoyancyBottomHeight = -1.3f;
    11.         public float buoyancyCoeff = 1.5f;
    12.         public float boyancyTorque = 8f;
    13.  
    14.         [Header("Wave Response")]
    15.         public float objectWidth = 4.5f;
    16.         public float objectLength = 2.25f;
    17.  
    18.         [Header("Fore | Drag")]
    19.         public float forceHeightOffset = -0.3f;
    20.         public float dragInWaterUp = 3f;
    21.         public float dragInWaterRight = 2f;
    22.         public float dragInWaterForward = 1f;
    23.         public float dragInWaterRotational = 0.2f;
    24.  
    25.         [Header("Physics Body")]
    26.         public Vector3 inverseInertia;
    27.  
    28.         public void Convert(Entity entity, EntityManager entityManager, GameObjectConversionSystem conversionSystem)
    29.         {
    30.             entityManager.AddComponentData(entity, new ActorActionWaterBuoyancySimpleComponent()
    31.             {
    32.                 buoyancyBottomHeight = buoyancyBottomHeight,
    33.                 buoyancyCoeff = buoyancyCoeff,
    34.                 boyancyTorque = boyancyTorque,
    35.                 objectWidth = objectWidth,
    36.                 objectLength = objectLength,
    37.                 forceHeightOffset = forceHeightOffset,
    38.                 dragInWaterUp = dragInWaterUp,
    39.                 dragInWaterRight = dragInWaterRight,
    40.                 dragInWaterForward = dragInWaterForward,
    41.                 dragInWaterRotational = dragInWaterRotational,
    42.                 inverseInertia = inverseInertia
    43.             });
    44.  
    45.             entityManager.SetComponentData(entity, new Translation { Value = transform.position });
    46.         }
    47.  
    48.         public void OnDrawGizmos()
    49.         {
    50.         }
    51.     }
    52. }
    53.  
     
  7. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173