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

Question How do you rotate a cube in global space

Discussion in 'Entity Component System' started by Kitsuba, Jul 8, 2023.

  1. Kitsuba

    Kitsuba

    Joined:
    Mar 5, 2015
    Posts:
    17
    I have a cube entity that's rotated 45 degrees on the x axis. I'm trying to rotate it on the y-axis in world space.

    How would I go about this?

    Code (CSharp):
    1. localTransform.ValueRW = localTransform.ValueRO.RotateY(3 * deltaTime);
    This code simply rotates it in local-space. I know i'm supposed to do something with LocalToWorld but no matter what I do, it just won't work. I've read through the Entities documentation multiple times by now but that really doesn't do anything for me at all.

    My code currently looks like this
    Code (CSharp):
    1. //Transform local-rotation to world-space
    2. quaternion worldRotation = math.mul(localToWorld.ValueRO.Rotation, localTransform.ValueRO.Rotation);
    3.  
    4. //Rotate in world-space
    5. worldRotation = math.mul(worldRotation, quaternion.RotateY(3 * SystemAPI.Time.DeltaTime));
    6.  
    7. //Transform rotation back to local-space
    8. quaternion newLocalRotation = math.mul(math.inverse(localToWorld.ValueRO.Rotation), worldRotation);
    9.  
    10. localTransform.ValueRW = localTransform.ValueRO.WithRotation(newLocalRotation);
    which apparently does the exact same thing as rotating it in local-space so yeah, I seem to have made lots of extra steps with no progress whatsoever.

    Someone help me out.
     
  2. xindexer2

    xindexer2

    Joined:
    Nov 30, 2013
    Posts:
    78
    Last edited: Jul 8, 2023
  3. Kitsuba

    Kitsuba

    Joined:
    Mar 5, 2015
    Posts:
    17
    Hey xindexer2, thanks for responding. This unfortunately isn't the solution since i'm using DOTS. The Space.World enum seems to only work on regular transforms. I'm using the LocalTransform which only accept a quaternion as parameter for its Rotate() method.
     
  4. xindexer2

    xindexer2

    Joined:
    Nov 30, 2013
    Posts:
    78
    Well I'm running into the same thing as you are now - the Rotate call on the transform does not take a second input... My work around is to parent the entity that is located at 0,0,0 then rotate that. Works great if you need the parent which I do on the majority of my entities but not all.
     
  5. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    262
    Quaternions always result in me just trying all combinations until one works :)

    Maybe :
    quaternion.AxisAngle(new float3(0,1,0), someAngleInRad) -> multiply this with your 45 degrees turned quaternion for the new Quaternion.

    Or change the order of the parameters when you multiply the quaternions.

    Or maybe something else :confused: sorry in this case.
     
  6. Wobbers

    Wobbers

    Joined:
    Dec 31, 2017
    Posts:
    55
  7. MattMuko

    MattMuko

    Joined:
    Sep 20, 2017
    Posts:
    3
    Just as Wobbers said, you need use LocalToWorld of parent to calculate transformation matrix instead of child.
    Code (CSharp):
    1.        
    2.         /// <summary>
    3.         /// Rotate entity around axis with angle in world space.
    4.         /// </summary>
    5.         /// <param name="e"></param>
    6.         /// <param name="axis"></param>
    7.         /// <param name="angle"></param>
    8.         private void Rotate(ref SystemState state, Entity e, float3 axis, float angle)
    9.         {
    10.             // global rotation axis and angle.
    11.             var rotation = quaternion.AxisAngle(axis, angle);
    12.            
    13.             // if entity has parent, transform rotation to local space.
    14.             if (SystemAPI.HasComponent<Parent>(e))
    15.             {
    16.                 var parentEntity = SystemAPI.GetComponentRO<Parent>(e).ValueRO.Value;
    17.                 var parentL2W = SystemAPI.GetComponentRO<LocalToWorld>(parentEntity).ValueRO.Value;
    18.                 rotation = math.inverse(parentL2W).TransformRotation(rotation);
    19.             }
    20.  
    21.             // rotate entity.
    22.             var localTransform = SystemAPI.GetComponent<LocalTransform>(e);
    23.             rotation = localTransform.TransformRotation(rotation);
    24.             SystemAPI.SetComponent(e, localTransform.WithRotation(rotation));
    25.         }
    26.  
     
  8. xindexer2

    xindexer2

    Joined:
    Nov 30, 2013
    Posts:
    78
    So I tried using MattMuko's solution and the one in the Transform Comparison page but I always get the same thing - If I don't have a parent on the entity, it rotates around it's own axis. If I add a parent, then there is no problem and it rotates around world space, but that's because the parent is at 0,0,0 and any rotation it has will be world space.

    In a job, I'm setting the entities position on the Y axis:
    Code (CSharp):
    1. localTransforms[i] = new LocalTransform()
    2.                 {
    3.                     Position = new float3
    4.                     {
    5.                         x = 0,
    6.                         y = PositionData[entityIndexInQuery].x,
    7.                         z = 0
    8.                     },
    9.                     Scale = 1,
    10.                     Rotation = quaternion.identity
    11.                 };
    Then in a for loop after the job completes, I'm trying to rotate it in world space (using Matt's function above):
    Code (CSharp):
    1. for (var i = 0; i < tickArray.Length; i++)
    2.                         {
    3.                             Rotate(ref state, tickArray[i], new float3(0,0,1), tickAngleData[i]);
    4.  
    5.                         }
    and this is the result
     

    Attached Files:

  9. MattMuko

    MattMuko

    Joined:
    Sep 20, 2017
    Posts:
    3
    Oh, It's my mistake that transforming quaternion incorrectly. Maybe, you can try another more direct solution, transform rotate axis to local space firstly, and then apply rotation in local space.
    Code (CSharp):
    1. private void Rotate2(ref SystemState state, Entity e, float3 axis, float angle)
    2.         {
    3.             // local rotation axis.
    4.             var localAxis = axis;
    5.            
    6.             // if entity has parent, transform axis to local space.
    7.             if (SystemAPI.HasComponent<Parent>(e))
    8.             {
    9.                 var parentEntity = SystemAPI.GetComponentRO<Parent>(e).ValueRO.Value;
    10.                 var parentL2W = SystemAPI.GetComponentRO<LocalToWorld>(parentEntity).ValueRO.Value;
    11.                 localAxis = math.mul(new float3x3(math.inverse(parentL2W)), axis);
    12.             }
    13.  
    14.             // rotate entity.
    15.             var localTransform = SystemAPI.GetComponent<LocalTransform>(e);
    16.             var rotation = quaternion.AxisAngle(localAxis, angle);
    17.             rotation = localTransform.TransformRotation(rotation);
    18.             SystemAPI.SetComponent(e, localTransform.WithRotation(rotation));
    19.         }
     
  10. xindexer2

    xindexer2

    Joined:
    Nov 30, 2013
    Posts:
    78
    I appreciate all the help but maybe it can't be done without a parent? Rotate2 ends up doing the same thing as Rotate.
     
    Last edited: Jul 12, 2023