Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

LookAt on Y axis only

Discussion in 'Scripting' started by olliecard, Aug 24, 2009.

  1. olliecard

    olliecard

    Joined:
    Nov 6, 2007
    Posts:
    39
    What is the cleanest way of coding gameobject.transform.LookAt (Transform); in a way that only focuses on the y axis? Everytime I try to split it up it ends up not working. Any thoughts?
     
  2. matthewminer

    matthewminer

    Joined:
    Aug 29, 2005
    Posts:
    331
    Instead of using Transform.LookAt(Transform), what about using Transform.LookAt(Vector3) and supplying a custom Vector3 as a parameter?

    Code (csharp):
    1. // The variable "target" is the transform we're looking at
    2. Vector3 targetPosition = new Vector3(transform.position.x, target.position.y, transform.position.x);
    3. transform.LookAt(targetPosition);
    I haven't tested this myself, but give it a try and see if it does what you want it to do.
     
  3. GargerathSunman

    GargerathSunman

    Joined:
    May 1, 2008
    Posts:
    1,571
    If you supply your own transform.position.x and transform.position.z for the custom vector3, you'll always look either straight up or straight down. No slants at all.

    If you want to restrict rotation, store your current eulerAngles before LookAt, LookAt, and then restore the eulerAngles axis you didn't want changed.

    So, it'd be like:

    var tempEuler : Vector3 = transform.eulerAngles;
    transform.LookAt(target);
    transform.eulerAngles.x = tempEuler.x;
    transform.eulerAngles.z = tempEuler.z;
     
  4. Jim Offerman

    Jim Offerman

    Joined:
    Jul 17, 2009
    Posts:
    177
    The algebraic solution goes like this:

    Code (csharp):
    1.  
    2. function LookAtOnY(targetPosition : Vector3)
    3. {
    4.    // Project targetPosition on the horizontal (xz) plane.
    5.    var d : float = Vector3.Dot(transform.up, targetPosition - transform.position);
    6.    var p : Vector3 = transform.position - d * transform.up;
    7.    transform.LookAt(p);
    8. }
    9.  
    We know that transform.up (the y-axis) is the normal to the horizontal (xz) plane and that transform.position lies in that plane - so we can use those two quantities to compute p, the projection of our target position onto the horizontal plane. For a full explanation:
    http://mathworld.wolfram.com/Point-PlaneDistance.html (I used eq 13)

    Since p lies in the horizontal plane (in the local coordinate space of our object), the LookAt() operation will turn around the y-axis only. This will work, regardless of the actual world-space orientation of the object.
     
  5. olliecard

    olliecard

    Joined:
    Nov 6, 2007
    Posts:
    39
    Thanks for all the opinions on this one -

    Matthew Miner - This was my first attempt, I thought if I took the singular y axis it would work, but it seems that it still adjusts the actual angle of the object and only looks in the direction that the target it facing.

    GargerathSunman - eulerAngles only changes the local rotation, which is not what I want. I have a controller game object which I want to rotate, but it seems to only rotate the objects attached to it. Doesn't work with my controller I have setup, and Im in too deep to change it!

    Jim Offerman - Still tinkering, will get back to you with results...
     
  6. olliecard

    olliecard

    Joined:
    Nov 6, 2007
    Posts:
    39
    Jim - This gives some very odd results. It seems to flick the controller between two different rotations everytime you click on the look at button, which is calling the function.

    - The controller should only be rotating on the Y axis
    - A first click changes rotation to (270, 0, 0)
    - A second click changes rotation to (-4, 0, 0)
    and so on...

    ...which all in all screws the controller, which needs to remain on Y at a constant 72.

    Here is a sample of the code, doesn't include everything.

    Code (csharp):
    1.  
    2. var controller : Transform;
    3. var MyBuilding1 : Transform;
    4.  
    5. function OnGUI(){
    6.  
    7. var MyBuilding1GO= GameObject.Find ("MyBuilding1");
    8. MyBuilding1 = MyBuilding1GO.transform;
    9.  
    10. if (GUI.Button (Rect (5, 65, 70, 20), "Look At")) {
    11. var MyBuilding1V3: Vector3 = MyBuilding1.position;
    12.     LookAtMyBuilding1(MyBuilding1V3);
    13.    
    14.     }
    15. }
    16.  
    17. function LookAtMyBuilding1(targetPosition : Vector3)
    18. {
    19. var d : float = Vector3.Dot(controller.transform.up, targetPosition - controller.transform.position);
    20. var p : Vector3 = controller.transform.position - d * controller.transform.up;
    21.  
    22. controller.transform.LookAt(p);
    23. }
    Please let me know if you can see anything obvious, or any key mistakes. Thanks!
     
  7. olliecard

    olliecard

    Joined:
    Nov 6, 2007
    Posts:
    39
    Like with most problems, its usually the simplest solution. I went back to start from scratch, and it seems to be working where it wasn't before! I simply stripped it down so I was only grabbing x and z of the target.

    Code (csharp):
    1. function LookAtMyBuilding1(targetPosition : Vector3){
    2. var building1lookAt = new Vector3(targetPosition.x, controller.transform.position.y, targetPosition.z);
    3. controller.transform.LookAt(building1lookAt);
    4. }
    Cheers for all your help!
     
  8. Jim Offerman

    Jim Offerman

    Joined:
    Jul 17, 2009
    Posts:
    177
    Odd. Point p in my solution ought to have been equal to building1lookAt in your final solution. Must've made a typo in there somehwere...

    Anyway, seems like you have a working solution now, so hurrah for you! :)