Search Unity

Smooth LookAt

Discussion in 'Scripting' started by Glemau, Aug 23, 2015.

  1. Glemau

    Glemau

    Joined:
    Jul 24, 2015
    Posts:
    37
    Hi there,
    I need some help with smoothing my lookat.
    Because it turns direct to the target. Can I somehow smooth it or use something else?
    That you can really see it turn.

    ~Glemau
     
  2. Bradamante

    Bradamante

    Joined:
    Sep 27, 2012
    Posts:
    300
    Multiple ways to achieve this. One would be:

    Code (csharp):
    1. // in your Update function
    2. transform.rotation = Quaternion.RotateTowards (
    3. transform.rotation,
    4. Quaternion.LookRotation( transform.position - target.position ),
    5. Time.deltaTime * yourTurnRate );
    Generally look at Lerp and other functions.
     
  3. Glemau

    Glemau

    Joined:
    Jul 24, 2015
    Posts:
    37
    Thanks :)

    ~Glemau
     
  4. dpolyakov

    dpolyakov

    Joined:
    Dec 18, 2015
    Posts:
    16
    This thread is kind of old, but might be helpful for someone else. If you need to rotate and fire at the end of rotation - do rotation in coroutine:
    Code (CSharp):
    1. <...>
    2. StopCoroutine("RotateToFire");
    3. StartCoroutine(RotateToFire(hit));
    4. <...>
    5.  
    6.     IEnumerator RotateToFire(Vector3 hitPoint)
    7.     {
    8.         //transform.LookAt(hitPoint);
    9.         Vector3 dir = (hitPoint - transform.position).normalized;
    10.         Quaternion rotTo = Quaternion.LookRotation(dir);
    11.  
    12.         while(true)
    13.         {
    14.             transform.rotation = Quaternion.RotateTowards(
    15.                 transform.rotation, rotTo,
    16.                 Time.deltaTime * turnSpeedToFire);
    17.  
    18.             if(Vector3.Angle(transform.forward, dir) < 1)
    19.                 break;
    20.  
    21.             yield return null;
    22.         }
    23.  
    24.         // fire
    25.         // ...
    26.     }
    27.  
     
  5. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    Did you seriously just necro a 1 year old thread to suggest abusing co-routines?

     
  6. dpolyakov

    dpolyakov

    Joined:
    Dec 18, 2015
    Posts:
    16
    funny guy.

    Seriously, why "abusing co-routines"? Is there any problems by using them?
    It is a good practice to put in coroutines a code that does not need to be executed in every single frame, even docs are pointing that out. In my example, you turn, fire, and wait. No performance hit. The same exact way many tweens work when you schedule something.
    Also, if you would look closely there was an error in the first suggested code: "transform.position - target.position" - that gives an opposite direction. It should be "target.position - transform.position".
     
  7. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Yeah. Why is that a coroutine abuse?

    Also, why did that pencil not fall off Gordon Ramsey's hear?
     
    Last edited: Jun 15, 2016
    BadSeedProductions likes this.
  8. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    I'm also curious what's wrong with that coroutine? I use them for similar functionality all the time. I use them to death.
     
  9. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    Co-routines are meant to be used when you have something you would like to run repeatedly for long periods of time. The given example by dpolyakov is abusing them because it returns the moment rotation ends. The co-routine will then have to be restarted every single time you want to rotate your object. You are allocating extra garbage for the GC(which will now also run more often) to collect and creating unnecessary overhead with the method calls.

    P.S. The documentation needs to be changed to highlight the "dangers" of using co-routines for small tasks.
     
    Last edited: Jun 15, 2016
  10. dpolyakov

    dpolyakov

    Joined:
    Dec 18, 2015
    Posts:
    16
    > "Co-routines are meant to be used when you have something you would like to run repeatedly for long periods of time."
    Sure, why not? "long period of time" is a relative measurement. It can be a fraction of a second or longer than a minute.

    AFAIK, the whole idea of co-routines is to off load a code from Update(). When you use "yield return null" - it is executed in every single frame and yes there is an "overhead" of a few ticks (really??? you would worry about that?). But once, let's say, gun's rotation is ended, why to call this rotation again? Of cause you can put it all in Update and use flags to check what to call, or you can use co-routines that were designed for that.

    Performance wise - it depends on what you are doing. Issuing thousands of co-routines at the same time will surely drop FPS. For few hundreds - there is no performance hit you will notice at all. If you are fighting for every single tick of your precious CPU time - do not use co-routines. For me, I prefer to actually program logic in the most convenient way, make sure that it works as designed, and worry about performance later _IF_ I hit some slowdowns. More likely, it will be somewhere else, like graphics related than some co-routine.
     
  11. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    http://forum.unity3d.com/threads/why-do-people-hate-coroutines.260160/page-3#post-1722915

    I will just put this here for you to read as I do not wish to re-iterate all the reasons co-routines are bad.

    You could just as easily disable/enable the rotator component without the overhead produced from a co-routine. Your components should at the very least try to follow the single responsibility principle(https://drive.google.com/file/d/0ByOwmqah_nuGNHEtcU5OekdDMkk/view?pref=2&pli=1).
     
    Last edited: Jun 16, 2016
  12. jaasso

    jaasso

    Joined:
    Jun 19, 2013
    Posts:
    64
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class LookAtTarget : MonoBehaviour
    5. {
    6.     public Transform target;
    7.     public Vector2 rotRange;
    8.     public bool smoothRot;
    9.     public float followDelay = 1;
    10.    
    11.     Vector3 followAngles;
    12.    
    13.     Vector3 refVelocity;
    14.    
    15.     Vector3 localTarget,targetAngles;
    16.     float yAngle,xAngle;
    17.    
    18.     void Update()
    19.     {
    20.         if(target!=null)
    21.         {
    22.             transform.localRotation=Quaternion.identity;
    23.  
    24.             localTarget = transform.InverseTransformPoint(target.position);
    25.            
    26.             yAngle = Mathf.Atan2(localTarget.x, localTarget.z)*Mathf.Rad2Deg;
    27.             yAngle = Mathf.Clamp(yAngle, -rotRange.y*.5f, rotRange.y*.5f);
    28.            
    29.             transform.localRotation=Quaternion.Euler(0,yAngle,0);
    30.            
    31.             localTarget = transform.InverseTransformPoint(target.position);
    32.            
    33.             xAngle = Mathf.Atan2(localTarget.y, localTarget.z)*Mathf.Rad2Deg;
    34.             xAngle = Mathf.Clamp(xAngle, -rotRange.x*.5f, rotRange.x*.5f);
    35.  
    36.             if(smoothRot)
    37.             {
    38.                 targetAngles = new Vector3(followAngles.x + Mathf.DeltaAngle(followAngles.x, xAngle),
    39.                                            followAngles.y + Mathf.DeltaAngle(followAngles.y, yAngle));
    40.                
    41.                 followAngles = Vector3.SmoothDamp(followAngles, targetAngles, ref refVelocity, followDelay);
    42.                
    43.                 transform.localRotation = Quaternion.Euler(-followAngles.x, followAngles.y, 0);
    44.             }
    45.             else
    46.             {
    47.                 targetAngles=new Vector3(xAngle,yAngle);
    48.                 transform.localRotation = Quaternion.Euler(-targetAngles.x, targetAngles.y, 0);
    49.             }
    50.         }
    51.     }
    52. }
     
  13. dpolyakov

    dpolyakov

    Joined:
    Dec 18, 2015
    Posts:
    16
    Well, it this case I prefer my own opinion based on my experience and work. Here, co-routines help me to achieve what I need. I'm not fighting for the cleanest code or extra tick (I'm sure that I can point out a lot of stuff in your yard). I reach goals - functionality that I need, not how my "pretty" code is evaluated by some random dude on the Internet. If you prefer to spend all your time optimizing code and reading on forums that something that is btw offered by language and (in this case) engine is bad because some other random guy cannot understand it, lol, go ahead!
     
    jaasso likes this.
  14. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
  15. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    Do you mean there are GC allocations each time a coroutine is started?
    Do you have some references about this?
     
    jaasso likes this.
  16. dpolyakov

    dpolyakov

    Joined:
    Dec 18, 2015
    Posts:
    16
    There is an allocation. All coroutines are built on top of C# yield keyword. Actually, it is a very clever implementation that simulates multi-threading without needing synchronization methods. So there are some little allocations to keep references. Also there is an allocation when you do WaitForSeconds. GC - will need to release a little bit more as well. But all these allocations are very small. Nothing to worry about. You can argue that a statement Vector v = new Vector(x, y, z) will have an impact on your performance, but there is no way you can feel it, unless you make a synthetic test to prove the point, but who really cares that on million allocations it will take 0.1sec?
     
    jaasso likes this.
  17. CyproNET

    CyproNET

    Joined:
    Sep 15, 2013
    Posts:
    79
    I don't know what everyone is screaming about but this makes your transform look at an object and staying in the upright direction.

    Code (CSharp):
    1.  
    2. Quaternion direction =Quaternion.LookRotation(target.position-transform.position, transform.TransformDirection(Vector3.up));
    3. transform.rotation = Quaternion.Lerp(transform.rotation, direction, Time.deltaTime*rotateSpeed);
     
    BitGamey likes this.
  18. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    @dpolyakov
    Well, if there are GC allocations, even if they are very small, that's not to be ignored. It could have a performance issue since it can trigger the GC more often. I understood that's particularly noticeable on mobile platforms, thought I have not run tests myself to benchmark that.