Search Unity

Bug Transform Bug in CompanionGameObjectUpdateTransformSystem (Entities v0.17.0)

Discussion in 'Entity Component System' started by BobFlame, May 24, 2021.

  1. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    When copy transform from entity's local to world to gameobject's transform, there is an issue in implementation when there is negative scale involved in heirarchy. Below is original implementation. If some negative scale is invovled, Matrix.Rotation computation take negative scale into consideration once, and lossy scale take negative scale second time.

    Code (CSharp):
    1.  
    2.         public unsafe void Execute(int index, TransformAccess transform)
    3.         {
    4.             var ltw = localToWorld[entities[index]];
    5.             var mat = *(UnityEngine.Matrix4x4*) & ltw;
    6.             transform.localPosition = ltw.Position;
    7.             transform.localRotation = mat.rotation;
    8.             transform.localScale = mat.lossyScale;
    9.         }
    10.  
    Here is my solution, maybe not the best, but it indeed solve the problem.
    Code (CSharp):
    1.  
    2.         public unsafe void Execute(int index, TransformAccess transform)
    3.         {
    4.             var ltw = localToWorld[entities[index]].Value;
    5.             var lossyScale = GetLossyScale(ltw);
    6.             transform.localPosition = GetPosition(ltw);
    7.             transform.localRotation =  GetRotationStripScale(ltw, lossyScale);
    8.             transform.localScale = lossyScale;
    9.         }
    10.  
    11.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    12.         static public float3 GetPosition(float4x4 Value)
    13.         {
    14.             return new float3(Value.c3.x, Value.c3.y, Value.c3.z);
    15.         }
    16.  
    17.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    18.         static public quaternion GetRotation(float4x4 Value)
    19.         {
    20.             return new quaternion(Value);
    21.         }
    22.  
    23.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    24.         static public quaternion GetRotationStripScale(float4x4 Value, float3 scale)
    25.         {
    26.             var mt = math.mul(Value, float4x4.Scale(math.rcp(scale)));
    27.             return new quaternion(mt);
    28.         }
    29.  
    30.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    31.         static public float3 GetLossyScale(float4x4 matrix)
    32.         {
    33.             var baseX = matrix.c0.xyz;
    34.             var baseY = matrix.c1.xyz;
    35.             var baseZ = matrix.c2.xyz;
    36.             if (math.dot(math.cross(baseX, baseY), baseZ) < 0)              
    37.                 return new float3(math.length(baseX), math.length(baseY), -math.length(baseZ));
    38.             else
    39.                 return new float3(math.length(baseX), math.length(baseY), math.length(baseZ));
    40.         }
    41.  
     
    Last edited: May 28, 2021
  2. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    My previous implementation is not quite right, now it has been fixed.
    The key point is when scale is negative, the coordination system change from left hand to right hand.
    So it is needed to get the "necessary" negative scale to change coordination system from right hand back to left hand.
     
    MNNoxMortem likes this.