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

Feedback CopyTransformFromGameObject apparently incompatible with Unity Physics?

Discussion in 'Physics for ECS' started by jashan, Aug 31, 2020.

  1. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,306
    I have a setup where I need to synchronize the Transforms from the game objects world to Kinematic Unity Physics objects. I assumed that CopyTransformFromGameObject would do this for me.

    Unfortunately, CopyTransformFromGameObject only overwrites LocalToWorld, which apparently does all that's needed for rendering - but Unity Physics seems to rely on Rotation and Translation instead. And those are not updated by CopyTransformFromGameObject.

    Took me a while to figure that one out.

    For now, I'm using a hacky workaround: I simply copy the Transform position and rotation over to the Translation and Rotation components of the entity on FixedUpdate, Update and LateUpdate. A better solution would probably be to do this in a system that runs before the physics simulation.

    Is there a recommended way of pushing this information properly into the dots-based physics simulation (these are objects controlled by VR controllers).
     
  2. Scorr

    Scorr

    Joined:
    Jul 2, 2013
    Posts:
    73
    You could copy CopyTransformFromGameObjectSystem.cs and swap out a few lines to make a version that works with Translation/Rotation components. All it does is combine position+rotation into a LTW and then copy it to the entity, could just skip the combine step.
     
    jashan likes this.
  3. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Create a job that runs after CopyTransformFromGameObjectSystem and before EndFrameTRSToLocalToWorldSystem that populates Translation/Rotation should work.
     
    jashan likes this.
  4. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,306
    For sake of simplicity and performance ... and at the expense of maintainability in the case of DOTS-updates, I extended CopyTransformFromGameObjectSystem to include the updates to Translation and Rotation. The reason I didn't create my own system is because I believe the costly part of CopyTransformFromGameObjectSystem is generating the TransformStashes, and if I keep CopyTransformFromGameObjectSystem and add my own system that updates Translation and Rotation, that would be kind of a waste. That may be premature optimization, especially because I'm using CopyTransformFromGameObject on only a handful of objects ... but I guess it's also a bit of practice.

    Here's the code, let me know what you think:

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.Burst;
    5. using Unity.Mathematics;
    6. using UnityEngine.Jobs;
    7.  
    8. namespace Unity.Transforms
    9. {
    10.     [UnityEngine.ExecuteAlways]
    11.     [UpdateInGroup(typeof(TransformSystemGroup))]
    12.     [UpdateBefore(typeof(EndFrameTRSToLocalToWorldSystem))]
    13.     public class CopyTransformFromGameObjectSystem : JobComponentSystem
    14.     {
    15.         struct TransformStash
    16.         {
    17.             public float3 position;
    18.             public quaternion rotation;
    19.         }
    20.  
    21.         [BurstCompile]
    22.         struct StashTransforms : IJobParallelForTransform
    23.         {
    24.             public NativeArray<TransformStash> transformStashes;
    25.  
    26.             public void Execute(int index, TransformAccess transform)
    27.             {
    28.                 transformStashes[index] = new TransformStash
    29.                 {
    30.                     rotation       = transform.rotation,
    31.                     position       = transform.position,
    32.                 };
    33.             }
    34.         }
    35.  
    36. #pragma warning disable 618
    37.         [BurstCompile]
    38.         struct CopyTranslations : IJobForEachWithEntity<Translation> {
    39.             [ReadOnly] public NativeArray<TransformStash> transformStashes;
    40.  
    41.             public void Execute(Entity entity, int index, ref Translation translation) {
    42.                 var transformStash = transformStashes[index];
    43.                 translation.Value = transformStash.position;
    44.             }
    45.         }
    46.  
    47.         [BurstCompile]
    48.         struct CopyRotations : IJobForEachWithEntity<Rotation> {
    49.             [ReadOnly] public NativeArray<TransformStash> transformStashes;
    50.  
    51.             public void Execute(Entity entity, int index, ref Rotation rotation) {
    52.                 var transformStash = transformStashes[index];
    53.                 rotation.Value = transformStash.rotation;
    54.             }
    55.         }
    56.  
    57.         [BurstCompile]
    58.         struct CopyTransforms : IJobForEachWithEntity<LocalToWorld>
    59.         {
    60.             [ReadOnly] public NativeArray<TransformStash> transformStashes;
    61.  
    62.             public void Execute(Entity entity, int index, ref LocalToWorld localToWorld)
    63.             {
    64.                 var transformStash = transformStashes[index];
    65.  
    66.                 localToWorld.Value = float4x4.TRS(
    67.                         transformStash.position,
    68.                         transformStash.rotation,
    69.                         new float3(1.0f, 1.0f, 1.0f));
    70.             }
    71.         }
    72.  
    73.         [BurstCompile]
    74.         struct DeallocateStashes : IJob
    75.         {
    76.             [DeallocateOnJobCompletion] public NativeArray<TransformStash> transformStashes;
    77.  
    78.             public void Execute() {
    79.                 // nothing to do ... probably could transformStashes.Dispose
    80.                 // ... but we have [DeallocateOnJobCompletion] ;-)
    81.             }
    82.         }
    83. #pragma warning restore 618
    84.  
    85.         EntityQuery m_TransformGroup;
    86.  
    87.         protected override void OnCreate()
    88.         {
    89.             m_TransformGroup = GetEntityQuery(
    90.                 ComponentType.ReadOnly(typeof(CopyTransformFromGameObject)),
    91.                 typeof(UnityEngine.Transform),
    92.                 ComponentType.ReadWrite<LocalToWorld>(),
    93.                 ComponentType.ReadWrite<Translation>(),
    94.                 ComponentType.ReadWrite<Rotation>());
    95.        
    96.             //@TODO this should not be required, see https://github.com/Unity-Technologies/dots/issues/1122
    97.             RequireForUpdate(m_TransformGroup);
    98.         }
    99.        
    100.         private NativeArray<JobHandle> handles = new NativeArray<JobHandle>(3, Allocator.TempJob);
    101.        
    102.         protected override JobHandle OnUpdate(JobHandle inputDeps)
    103.         {
    104.             var transforms = m_TransformGroup.GetTransformAccessArray();
    105.             var transformStashes = new NativeArray<TransformStash>(transforms.length, Allocator.TempJob);
    106.            
    107.             var stashTransformsJob = new StashTransforms { transformStashes = transformStashes };
    108.             var stashTransformsJobHandle = stashTransformsJob.Schedule(transforms, inputDeps);
    109.  
    110.             // JC (2020-09-01): Unity Physics also needs the Translation and Rotation!
    111.             // can be done parallel, deallocate stashes after all these jobs have been completed
    112.             var copyTranslationJob = new CopyTranslations {transformStashes = transformStashes};
    113.             handles[0] = copyTranslationJob.Schedule(m_TransformGroup, stashTransformsJobHandle);
    114.  
    115.             var copyRotationsJob = new CopyRotations {transformStashes = transformStashes};
    116.             handles[1] = copyRotationsJob.Schedule(m_TransformGroup, stashTransformsJobHandle);
    117.  
    118.             var copyTransformsJob = new CopyTransforms {transformStashes = transformStashes};
    119.             handles[2] = copyTransformsJob.Schedule(m_TransformGroup, stashTransformsJobHandle);
    120.  
    121.             JobHandle combined = JobHandle.CombineDependencies(handles);
    122.            
    123.             var deallocateStashesJob = new DeallocateStashes() { transformStashes = transformStashes };
    124.             return deallocateStashesJob.Schedule(combined);
    125.         }
    126.  
    127.         protected override void OnDestroy() {
    128.             handles.Dispose();
    129.         }
    130.     }
    131. }
    132.