Search Unity

Compare rotation of matrix with initial direction

Discussion in 'Scripting' started by kubajs, Oct 22, 2018.

  1. kubajs

    kubajs

    Joined:
    Apr 18, 2015
    Posts:
    58
    Hi guys,
    I'm trying to solve solution very similar to IQ Fit board game.
    I have 3 dimensional bool array / matrix which represent an orientation of say 3D tetris piece.
    Matrix can be rotated horizontally and vertically to all 6 directions in 90 degrees steps only. No problem with this, works flawlessly.
    In every step (horizontal or vertical rotation of the piece) I need to evaluate whether the piece is oriented for example upwards but rotation on global Y axis is irrelevant.
    I tried to use a Quaternion variable to save initial rotation and then with every horizontal or vertical rotation change of the piece (input from player) I re-evaluated the current position and saved it to another quaternion and compared both quaternions.
    But I completely failed here, tried several solutions but I'm unable to evaluate whether the piece is in original upwards position or not.
    Please do you have any idea how to achieve this?
    Of course I might use brute force technique - complete matrix comparison or colliders but I'd like to avoid this terrible solution and do it in some elegant way :).
     
  2. hpjohn

    hpjohn

    Joined:
    Aug 14, 2012
    Posts:
    2,190
    Does it have to be a bool array?
    If they were ints, empty space could be zeros, your tetris piece 'cubes' are 1's (or specifically non-zero), then put a 2 in the top center position.
    Apply a bunch of rotations, and if your 2 is still at the top, you know you are back to vertical

    But your method of tracking a seperate quaternion should work fine
     
  3. kubajs

    kubajs

    Joined:
    Apr 18, 2015
    Posts:
    58
    Right, I might certainly use this approach, it would work fine but you know I'd like to use the quaternions comparison merhod, just don't know how to do it properly.
    Thanks anyway, if I fail completely, I will probably stick with this solution.
     
  4. hpjohn

    hpjohn

    Joined:
    Aug 14, 2012
    Posts:
    2,190
    Try running this and see if its what you want:

    Code (CSharp):
    1.     Quaternion currentState;
    2.     private void Start()
    3.     {
    4.         //store initial state
    5.         currentState = Quaternion.identity;
    6.     }
    7.  
    8.     private void Update()
    9.     {
    10.         //draw axes tripod in viewport for demo
    11.         Debug.DrawRay(Vector3.zero, currentState * Vector3.up, Color.green);
    12.         Debug.DrawRay(Vector3.zero, currentState * Vector3.right, Color.red);
    13.         Debug.DrawRay(Vector3.zero, currentState * Vector3.forward, Color.blue);
    14.     }
    15.  
    16.     private void OnGUI()
    17.     {
    18.         if (GUILayout.Button("Rotate things around X"))
    19.         {
    20.             Rotate(Quaternion.Euler(90, 0, 0));
    21.         }
    22.         if (GUILayout.Button("Rotate things around Y"))
    23.         {
    24.             Rotate(Quaternion.Euler(0, 90, 0));
    25.         }
    26.         if (GUILayout.Button("Rotate things around Z"))
    27.         {
    28.             Rotate(Quaternion.Euler(0, 0, 90));
    29.         }
    30.  
    31.         if (GUILayout.Button("Check State"))
    32.         {
    33.             Vector3 currentUp = currentState * Vector3.up;
    34.             if(Vector3.Dot(currentUp, Vector3.up) > 0.9f)
    35.             {
    36.                 Debug.Log("Current State has up pointing up");
    37.             }
    38.             else
    39.             {
    40.                 Debug.Log("Current State has up pointing somwhere else");
    41.             }
    42.         }
    43.     }
    44.  
    45.     void Rotate(Quaternion rotation)
    46.     {
    47.         //apply rotation to array
    48.         //...
    49.         //...
    50.  
    51.         //Modify tracked state
    52.         currentState = rotation * currentState ;
    53.     }
     
    kubajs likes this.
  5. kubajs

    kubajs

    Joined:
    Apr 18, 2015
    Posts:
    58
    Looks pretty good, I'll modify it to angle axis to avoid gimbal lock but I think you directed me to the right track.
    Thank you!

    Edit: Ok, doesn't seem like gimbal lock, I just omitted it's always rotating on global axis instead of local which is desired. Works fine.
     
    Last edited: Oct 23, 2018
  6. kubajs

    kubajs

    Joined:
    Apr 18, 2015
    Posts:
    58
    Really awesome help, hpjohn!
    I can finally say I now understand Quaternions better.
    The script is really helpful to understand the rotation operations visually. I added local rotation for those who need to understand this as well. Here is the full modified script:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class RotationTest : MonoBehaviour
    4. {
    5.     Quaternion currentState;
    6.     private void Start()
    7.     {
    8.         //store initial state
    9.         currentState = Quaternion.identity;
    10.     }
    11.  
    12.     private void Update()
    13.     {
    14.         //draw axes tripod in viewport for demo
    15.         Debug.DrawRay(Vector3.zero, currentState * Vector3.up, Color.green);
    16.         Debug.DrawRay(Vector3.zero, currentState * Vector3.right, Color.red);
    17.         Debug.DrawRay(Vector3.zero, currentState * Vector3.forward, Color.blue);
    18.     }
    19.  
    20.     private void OnGUI()
    21.     {
    22.         RotateOnGlobalAxis();
    23.         RotateOnLocalAxis();
    24.         CompareCurrentPositionWithInitialState();
    25.     }
    26.  
    27.     private void RotateOnGlobalAxis()
    28.     {
    29.         GUILayout.BeginArea(new Rect(100, 100, 200, 100));
    30.         if (GUILayout.Button("Rotate around global X"))
    31.         {
    32.             currentState = Quaternion.Euler(90, 0, 0) * currentState;
    33.         }
    34.         if (GUILayout.Button("Rotate around global Y"))
    35.         {
    36.             currentState = Quaternion.Euler(0, 90, 0) * currentState;
    37.         }
    38.         if (GUILayout.Button("Rotate around global Z"))
    39.         {
    40.             currentState = Quaternion.Euler(0, 0, 90) * currentState;
    41.         }
    42.         GUILayout.EndArea();
    43.     }
    44.  
    45.     private void RotateOnLocalAxis()
    46.     {
    47.         GUILayout.BeginArea(new Rect(350, 100, 200, 100));
    48.         if (GUILayout.Button("Rotate around local X"))
    49.         {
    50.             currentState = currentState * Quaternion.Euler(90, 0, 0);
    51.         }
    52.         if (GUILayout.Button("Rotate around local Y"))
    53.         {
    54.             currentState = currentState * Quaternion.Euler(0, 90, 0);
    55.         }
    56.         if (GUILayout.Button("Rotate around local Z"))
    57.         {
    58.             currentState = currentState * Quaternion.Euler(0, 0, 90);
    59.         }
    60.         GUILayout.EndArea();
    61.     }
    62.  
    63.     private void CompareCurrentPositionWithInitialState()
    64.     {
    65.         GUILayout.BeginArea(new Rect(225, 200, 200, 20));
    66.         if (GUILayout.Button("Check State"))
    67.         {
    68.             Vector3 currentUp = currentState * Vector3.up;
    69.             if (Vector3.Dot(currentUp, Vector3.up) > 0.9f)
    70.             {
    71.                 Debug.Log("Current State has up pointing up");
    72.             }
    73.             else
    74.             {
    75.                 Debug.Log("Current State has up pointing somewhere else");
    76.             }
    77.         }
    78.         GUILayout.EndArea();
    79.     }
    80. }
    81.