Search Unity

Head Look Controller

Discussion in 'Scripting' started by runevision, Jul 10, 2009.

  1. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Just a heads up that I made a head look controller that you can use to make characters look at any point in space, turning their head and upper bodies etc.

    Blog entry (with video!):
    http://blogs.unity3d.com/2009/07/10/just-looking-around/

    Example project:
    http://unity3d.com/support/resources/example-projects/head-look-controller

    If you want the script itself only, you can get it on the Unify Community Wiki:
    http://www.unifycommunity.com/wiki/index.php?title=HeadLookController

    Looking forward to see what you people can do with it. :)

    Rune
     
  2. horsman

    horsman

    Joined:
    Jul 19, 2008
    Posts:
    156
    Very nice.
     
  3. Matroblend

    Matroblend

    Joined:
    Jan 30, 2009
    Posts:
    134
    Wow this is very cool, it just makes me think of all the ways this could be used.

    Thanks abunch
     
  4. KlaRo115

    KlaRo115

    Joined:
    Feb 24, 2006
    Posts:
    675
    I tried a million times to write some code like yours, but I never really got it... Thanks, that code will save much of my time! :)

    (I need it for characters who should be able to shoot in different angles, and not only forward...)
     
  5. spacefrog

    spacefrog

    Joined:
    Jun 14, 2009
    Posts:
    734
    very cool !

    just a small suggestion:

    adding a "rootNode" public variable holding the root node transform, allows the script to be attached anywhere ( thus without breaking a Prefab ) - eg. to a global gamehandler...

    i made the following 3 changes to the class

    Code (csharp):
    1.  
    2. public class HeadLookController : MonoBehaviour {
    3.  
    4. // CHANGE 1 -> this declaration will hold the root transform to use
    5.     public Transform rootNode;  
    6.  
    7.     public BendingSegment[] segments;
    8.  
    9.     public NonAffectedJoints[] nonAffectedJoints;
    10.     public Vector3 headLookVector = Vector3.forward;
    11.  
    12.     public Vector3 headUpVector = Vector3.up;
    13.  
    14.     public Vector3 target = Vector3.zero;
    15.  
    16.    
    17.  
    18.     void Start () {
    19.  
    20.         // Setup segments
    21.  
    22.         foreach (BendingSegment segment in segments) {
    23.  
    24.             Quaternion parentRot = segment.firstTransform.parent.rotation;
    25.  
    26.             Quaternion parentRotInv = Quaternion.Inverse(parentRot);
    27.  
    28.             segment.referenceLookDir =
    29.  
    30. // CHANGE 2 -> here we use rootNode's transform
    31.                 parentRotInv * rootNode.transform.rotation * headLookVector.normalized;
    32.  
    33.             segment.referenceUpDir =
    34. // CHANGE 3 -> again here we use rootNode's transform
    35.                 parentRotInv * rootNode.transform.rotation * headUpVector.normalized;  
    36. .
    37. .
    38. .
    39. .[continued]
    40.  


    this small change works for me - now i can use the script anywhere, not just attached to the animated root bone....
     
  6. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Thanks, good point!

    I'll integrate those changes on the wiki next week (or you're welcome to do it if you want, as long as the changed script is fully tested and known to work).

    Rune
     
  7. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    This has now been added.

    Rune
     
  8. ohm

    ohm

    Joined:
    Aug 24, 2008
    Posts:
    88
    Hi,

    I tried and use your HeadLookController script and it works very good. So first of all thanks for the great script!

    I have a question though. I'm using the script on some npc characters that should look at the player when he gets close to it. When I get out of range I disable the script. All fine but the bone rotations are locked in the latest position when I disable the script. Shouldn't the animation take control over the bones when the script stops overriding it? It should at least snap back?


    //ohm
     
  9. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Yes it should. If the head doesn't snap back when you disable the HeadLookController component, it must be because you don't have any animations playing that have animation curves for the bones in question.

    Edit: Also see below for how to avoid snapping completely.

    Rune
     
  10. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    I added an effect variable to the script on the Wiki that can be used to gradually turn the head look controller on and off. When effect is 1 the controller is fully turned on; when it's 0 it has no effect.

    Rune
     
  11. ohm

    ohm

    Joined:
    Aug 24, 2008
    Posts:
    88
    Yes it was animation problems that I had before. It now works fine. I did a similar change as you did with the effect variable and interpolates from and to that before I turn on and off the script and it now works as intended. Thanks again!


    //ohm
     
  12. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    This script is awesome, thank you Rune :)
     
  13. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
  14. teatime

    teatime

    Joined:
    Jun 16, 2008
    Posts:
    129
    Rune, this is really impressive, as is all your work. In fact, right now my player character is controlled by the Normal Character Motor and Platform Character Controller scripts, the Head Look Controller, and the Locomotion System! The character holds a flashlight that points at whatever surface is behind the cursor with the help of the Head Look Controller, and I'm using a modified version of the Follower script that changes only the desiredFacingDirection to get the body to point toward that same cursor-projected object while the actual movement is controlled with WASD.

    But I'm having a somewhat tangential problem. It's not a problem with the Head Look Controller per se, more a problem with the Normal Character Motor, but I figured it fit better here than anywhere else.

    Because the character motor's facing direction changes with the slightest angle change from the cursor object and at a constant speed, it looks rather stiff and nullifies most of the nice natural effect the Head Look Controller gave to controlling the flashlight. Worse, if I do move the cursor far and fast enough to see the character's arm significantly bend before the motor's facing direction catches up, when it does catch up the arm's gone too far and has to "snap back" to center on the cursor object which looks quite ugly and jarring. I thought I might be able to solve the first problem (the sudden, linear-feeling movement) by incorporating some ideas from the Head Look Controller into the character motor's UpdateFacingDirection function, such as a threshold angle difference and max angle difference. But solving the second problem (the "snap-back" on the Head Look Controller's actions) would seem to require making the Head Look Controller take the character motor's facing direction into account as if it were a segment in the Head Look Controller script itself, and though I've studied the scripts for the last day and a half I'm at a loss as to how to make it do so. Does anyone have any ideas? I'm not expecting anyone to do the work for me, just someone with more experience setting me on a track that might be right. Let me know if I'm not making sense and I'll try to clarify.
     
  15. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    I have a vague understanding of the problem from your description, but seeing a video might help me better understand it.

    Rune
     
  16. teatime

    teatime

    Joined:
    Jun 16, 2008
    Posts:
    129
    hopefully this helps:

    http://www.vimeo.com/6268716

    i was a bit lazy/creative with the test scene textures, heh. i have someone else working on the real model and animation, which will be much more suited to holding a flashlight than the stock Hero model, but you should get the idea. it's worth noting that before i posted i tried many different combinations of settings in the head look controller and character motor rotations and the problems persist. actually without the follower script activated there is still a small amount of snap-back in the character's arm movements, but it's not nearly as jarring and exagerrated. but this may still be a problem that fine-tuning the head look controller might alleviate, rather than having to program something custom. as for the stiffness, i can't make the max rotation speed too small or it makes the character's reactions too sluggish and has a detrimental effect on gameplay.

    ideally the character itself should only start rotating once the angle of the target is a specified amount different enough, and it should only move about as far as it needs to for the flashlight to smoothly center on the target with the head look controller's help.
     
  17. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    It sounds like you could make a check in the character motor if the current forward direction is less than a certain angle away from the desired direction, and if so, don't rotate further or only rotate very slowly. The threshold angle should match how far you have specified the arm to be able to point to the sides.

    Rune
     
  18. teatime

    teatime

    Joined:
    Jun 16, 2008
    Posts:
    129
    this is the first thing i tried:

    Code (csharp):
    1. private void UpdateFacingDirection() {
    2.        
    3.         if (Vector3.Angle(desiredFacingDirection,transform.forward) < thresholdAngleDifference) return;
    4.    
    which did stop the motor from turning instantly, but when it did move it was very choppy.

    i ended up adapting the features of the head look controller into UpdateFacingDirection, and it seems to work very nicely for my purposes. here's the changed code:

    Code (csharp):
    1.     public float thresholdAngleDifference;
    2.     public float turningMultiplier;
    3.     public float maxAngleDifference;
    4.     public float responsiveness;
    5.  
    6.     private void UpdateFacingDirection() {
    7.  
    8.         float angleDifference = Vector3.Angle(desiredFacingDirection,transform.forward);
    9.  
    10.         //handling threshold angle difference
    11.         float hfacingThr = Mathf.Max(
    12.             0, Mathf.Abs(angleDifference) - thresholdAngleDifference
    13.         ) * Mathf.Sign(angleDifference);
    14.  
    15.         //handling bending multiplier and max angle difference
    16.         angleDifference = Mathf.Max(
    17.             Mathf.Abs(hfacingThr) * Mathf.Abs(turningMultiplier),
    18.             Mathf.Abs(angleDifference) - maxAngleDifference
    19.         ) * Mathf.Sign(angleDifference) * Mathf.Sign(turningMultiplier);
    20.  
    21.         maxRotationSpeed = Mathf.Lerp(
    22.             maxRotationSpeed, angleDifference, Time.deltaTime * responsiveness
    23.         );
    24.  
    25.         // Calculate which way character should be facing
    26.         float facingWeight = desiredFacingDirection.magnitude;
    27.         Vector3 combinedFacingDirection = (
    28.             transform.rotation * desiredMovementDirection * (1-facingWeight)
    29.             + desiredFacingDirection * facingWeight
    30.         );
    31.         combinedFacingDirection = Util.ProjectOntoPlane(combinedFacingDirection, transform.up);
    32.         combinedFacingDirection = alignCorrection * combinedFacingDirection;
    33.        
    34.         if (combinedFacingDirection.sqrMagnitude > 0.01f) {
    35.             Vector3 newForward = Util.ConstantSlerp(
    36.                 transform.forward,
    37.                 combinedFacingDirection,
    38.                 maxRotationSpeed*Time.deltaTime
    39.             );
    40.             newForward = Util.ProjectOntoPlane(newForward, transform.up);
    41.             //Debug.DrawLine(transform.position, transform.position+newForward, Color.yellow)
    42.             Quaternion q = new Quaternion();
    43.             q.SetLookRotation(newForward, transform.up);
    44.             transform.rotation = q;
    45.         }
    46.     }
    smoothing out the rotation like this probably isn't the right choice for many situations, but i thought posting it might be helpful to someone else using the Normal Character Motor down the road.
     
  19. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Cool. I'm looking forward to following the project / see it when it's finished. :)

    Rune
     
  20. teatime

    teatime

    Joined:
    Jun 16, 2008
    Posts:
    129
    hmm, every so often, most commonly when waving the flashlight around slowly in front of the character, the character jerks violently for a split second and i get this warning:

    Code (csharp):
    1. Look rotation viewing vector is zero
    supposedly due to the following line:

    Code (csharp):
    1.             q.SetLookRotation(newForward, transform.up);
    2.  
    it looks like changing

    Code (csharp):
    1.         maxRotationSpeed = Mathf.Lerp(
    2.             maxRotationSpeed, angleDifference, Time.deltaTime * responsiveness
    3.         );
    to LerpAngle prevents that problem, but makes the rest of the movement choppy again. any idea what's up with this?
     
  21. striderdoom

    striderdoom

    Joined:
    Oct 14, 2009
    Posts:
    12
    I'm trying to use the Head Look Controller to point the gun instead of the head. The obvious idea would be to have the character hold his arm out straight and point the gun wherever the mouse cursor is. However, anytime I put the arm/shoulder/hand/any combination of arm pieces, I can't get the gun to point at the cursor. Anyone have any luck with this?
     
  22. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    I need more info.

    What does your animation look like without the Head Look Controller? Is he holding out his arm straight to begin with?

    How have you setup the Head Look Controller? Can you post a screenshot of it shown in the Inspector?

    When you say "I can't get the gun to point at the cursor" what exactly do you mean? What does happen? Do you get errors? Do the arm do something at all, or does it not respond to moving the cursor at all?

    Rune
     
  23. Newnab

    Newnab

    Joined:
    Oct 25, 2010
    Posts:
    7
    This is absolutely amazing. Been banging my head against a wall, found this... Completely sorted. Thankyou!
     
  24. scarletsnake

    scarletsnake

    Joined:
    Nov 27, 2009
    Posts:
    106
    Absolutely awesome component, but I have some questions regarding the customization of the head look controller for use with my project;

    I use the controller in conjunction with the aiming animation I have to create the control scheme that most modern games have, but since it raycasts a sphere into just about anywhere in the world when I get up close to an object the character starts looking at the top of the object, creating some rather strange looking animations... I noticed that in LookAtMouse script that the code creates a plane for the raycast to occur, so that prevents the issue that I mentioned.

    Is there a particular way to do this kind of thing? I'm using the package I found here:
    http://unity3d.com/support/resources/unity-extensions/head-look-controller

    And it's only available in C#, which I know nearly nothing about so I really cant make any modifications that I require... Can you help me out?

    Thanks in advance
     
  25. huxley

    huxley

    Joined:
    Apr 27, 2009
    Posts:
    334
    Sorry to pound an old thread. But I'm trying to use the Javascript version of this script from the Wiki found here:
    http://www.unifycommunity.com/wiki/index.php?title=HeadLookController

    But it won't compile and the debug log says," (76,18) BCE0022: Cannot convert 'Object' to 'UnityEngine.Transform'., (188,18) BCE0022: Cannot convert 'Object' to 'UnityEngine.Transform'.
     
  26. juanelo

    juanelo

    Joined:
    Jan 28, 2011
    Posts:
    46
    Hello, I'm encountering something similar to striderdoom.
    I've been using the head look controller to aim an arm. For testing purposes, i've set a single keyframe with the arm rigid and extended, to see if I can get it to aim exactly at the target.

    I've set the max angle difference as high as 360, the responsiveness in the 100's, and the max angle difference to 0. What I've noticed is that even when the target is in front of and near the aiming arm, it doesn't seem to target it exactly, but rather seems to simply aim in a more or less similar direction.

    As i pull the target farther away from the front of the arm, it seems responsive and closely follows the object, but if I draw a line from the end of the arm to the target, I find that although it's pretty close, it misses the target altogether. From the values that I've inputted I would have expected a perfect aim, even if it broke the model visually.

    In other words, what I'm asking is, is there a way to get the controller to aim at an object immediately and exactly? Am I going about this the wrong way?

    Thanks,
    Juanelo
     
  27. Vinícius Sanctus

    Vinícius Sanctus

    Joined:
    Dec 14, 2009
    Posts:
    282
    Is this thread really abandoned by runevision?

    I really needed some help with this awesome tool!

    I wanted to use it along with AnimatePhysics on my model. But if i turn animatePhysics on it get really glitchy.

    Does anyone knows how to solve this?

    Thx!

    =)

    EDIT: Just talked to Rune himself, he said Unity currently doesn't support HeadLookController while using AnimatePhysics.

    So if you're having problem using it you may want to check if you got AnimatePhysics enabled, if you do, HeadLookController wont work properly.
     
    Last edited: Jun 4, 2011
  28. BFDesign

    BFDesign

    Joined:
    Mar 16, 2011
    Posts:
    214
    Looks like a super awesome tool. Are there any tutorials? I can't seem to get it to work with my model. I attached the headlook controller script to my model, and the cursor hit to the sphere, and I set up segments and joints. Then when I hit play... nada. Any help with set up here would be greatly appreciated.

    -Richard
     
  29. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    Has anyone been able to implement this with 3DMax's godawful orientation setup on biped characters?

    Cheers
    AC
     
  30. Carwash

    Carwash

    Joined:
    Nov 12, 2009
    Posts:
    95
    Anyone got any ideas how I can get a smooth transiiton in and out of a target for this?

    I've got the head controller working fine, character looks at and tracks a target that is passed to the headcontroller script when the target enters a certain range. Trouble is, the head SNAPS to the target when the target is in range, then SNAPS back when i move the target out of range. I want a smooth transtion.
     
  31. affd

    affd

    Joined:
    Feb 15, 2012
    Posts:
    3
    I have the same problem. I use :
    lookAtManager.effect = Mathf.Lerp(lookAtManager.effect, 1, 0.3f);" // in
    lookAtManager.effect = Mathf.Lerp(lookAtManager.effect, 0, 0.2f); " // out
    it can improve the result , but there still is "SNAPS" .Please help me
     
  32. affd

    affd

    Joined:
    Feb 15, 2012
    Posts:
    3
    interpolate effect variable and overrideAnimation = false. The problem will solve.
     
  33. scarletsnake

    scarletsnake

    Joined:
    Nov 27, 2009
    Posts:
    106
    I'm using this with characters created in 3ds Max using biped setups. What's so godawful about it?
     
  34. generalmcmutton

    generalmcmutton

    Joined:
    May 20, 2010
    Posts:
    42
    Necropost, but the fact that this is the main thread makes me feel less bad about it.

    I'd like to have this so that NPCs look at my character, but I can't figure out how I'd do that. The demo had a script on that ball that referred to a headLook variable within the headLookController, but that isn't an actual thing:

    Code (csharp):
    1. public HeadLookController headLook;
    2.  
    3. void LateUpdate () {
    4.      headLook.target = transform.position;
    I'm also using JavaScript, so I can't really dissect the code.
     
  35. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    Oh in general I've had difficulty with the 3drt "seniors". I cant even remember that particular issue at this point. Retargeting mocap has been absolutely nasty onto those suckers, and thats the nastiness I'm facing with their bipeds on a daily basis at present.

    @General McMutton, inserting a forward facing gameobject in the character hieracy between neck and head nodes with a "SmoothLookAt" script is a low-fi alternative. Switch script on and off as needed to look where you want head to look. Not as fancy as full body though.

    ~A
     
  36. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    At a guess you might just want to try

    headLook.target = transform;
     
  37. busuzima

    busuzima

    Joined:
    Dec 11, 2012
    Posts:
    2
    Hi!

    I'm trying to get access to the size of the segments. I have to set it to "3". How can I get access to it and over elements to all parts of an element (first transform, last transform, etc.)?
    Thank you!
     
  38. sgoodrow

    sgoodrow

    Joined:
    Sep 28, 2012
    Posts:
    150
    Hopefully someone else can explain why this works as well as it does, but I encountered a problem and a solution, so I thought I'd provide it.

    In some cases, the current implementation can result in a character's head turning not just in the horizontal plane, but also with a slight roll rotation. For bipeds this might not be terribly noticeable, and is likely the correct result, however with quadripeds, it gives them a very large desire to "cock their head" (like a dog), making them look ever-curious. This... is an interesting, but undesirable affect.

    I made the following alteration to fix it:


    // Look rotation in world space
    //Quaternion lookRot = (
    // (parentRot * Quaternion.LookRotation(lookDir, segment.dirUp)) *
    // Quaternion.Inverse( parentRot * Quaternion.LookRotation( segment.referenceLookDir, segment.referenceUpDir ) )
    //);

    // Look rotation in world space
    Quaternion lookRot = (
    (parentRot * Quaternion.LookRotation(lookDir, parentRotInv * Vector3.up)) *
    Quaternion.Inverse( parentRot * Quaternion.LookRotation( segment.referenceLookDir, segment.referenceUpDir ) )
    );
     
    Last edited: Jan 25, 2014
    scarletsnake likes this.
  39. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,442
    I was just about to complain about a necro-thread that was started in 2009 and idle since January, but anyone who posts Quaternion math and fixes a known problem gets a free pass in my book. Extra pluses for not resorting to Q->Euler conversions in your solution! Thanks.
     
  40. martinamenegon

    martinamenegon

    Joined:
    Aug 28, 2014
    Posts:
    31
    hi! so I'm using your amazing scripts.. i managed to have my ragdoll head kind of following a target.. thing is i need to clone this ragdoll, and somehow when i clone it, the target is not working for the clones.. how can i solve this?
    thanks
     
  41. Honorsoft

    Honorsoft

    Joined:
    Oct 31, 2016
    Posts:
    81
    The links seem to be dead, so is the link to the Unity procedural look controller.
    -Do any of these resources still work with Unity 2018 and 2019? Animations don't seem editable now, and the Animator seems to overide any changes you make to animated model, like turning a character's hear to look at the player while in an idle animation. Any advice on what to look for please?
     
  42. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    I haven't looked at this for a while. The code is available at http://wiki.unity3d.com/index.php/HeadLookController but I haven't checked if it works in recent versions.

    The code doesn't rely on editing animations. It overrides poses on a per-frame bases in LateUpdate, which I believe still runs each frame *after* animation has updated poses.
     
    Honorsoft likes this.
  43. Honorsoft

    Honorsoft

    Joined:
    Oct 31, 2016
    Posts:
    81
    Thanks for the info, I am still learning about Unity's animator system. I got that HeadLookController, and I will try to apply my animations AFTER Unity finishes with their's and see if that works. I still have reading to do, but I have collected a lot of info about "Inverse Kinematics" which people say is related to what I am trying to do. ???

    -I appreciate your response, you are the best person to ask (being a Unity professional). Just to give some context so you know what I am doing, I have a rigged animated model character, they attack with eyebeams so he turns his head to look at the target. I have a script that rotates the head to look at the target. When being animated with the Controller, my "attack script" doesn't seem to move the head. When, I disable the animation controller, the script works fine. Like you said, I might have to apply animations after Unity does. Any advice helps.
     
    Last edited: Aug 21, 2020
  44. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Change your logic to be inside LateUpdate instead of Update.
     
    Honorsoft likes this.
  45. Honorsoft

    Honorsoft

    Joined:
    Oct 31, 2016
    Posts:
    81
    Thanks, I have to remember Unity's order of operations.
     
  46. Crouching-Tuna

    Crouching-Tuna

    Joined:
    Apr 4, 2014
    Posts:
    82
    Sorry for the necro!!

    I managed with animatePhysics by calling HeadLookController.Update after doing a
    Code (CSharp):
    1. anim.Update(0); // workaround, to make animator "catch up" with LateUpdate
    2.  
    I hope that answer there justifies the necro bcoz i got my own problem...

    So i've been using this with a generic rig and it works great. It's a legless spirit, and the body-chest and neck-head
    segment can blend the LookAt nicely

    But then i recently added legs to the rig so it fits the Humanoid system, and ever since then, the neck-head part seems to rotate further than it should be, as if unaware of the body-chest's already rotating halfway

    upload_2021-5-27_1-37-51.png
    On a pose where the chest is already looking straight, and .target is straight ahead



    upload_2021-5-27_1-42-11.png
    On a pose where the chest is facing towards right, same .target position. Notice the head tilts waay to the left

    Anyone had this issue? Is there anything with Humanoid that makes this break, compared to Generic?
    Note i'm also not using any Animator.SetLookAtPosition whatsoever to even utilize Unity's Humanoid IK

    Cheers
     
  47. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    284
    Just wondering if anybody's tried this with hands, arms etc - pointing a gun at someone, for example?
     
  48. scarletsnake

    scarletsnake

    Joined:
    Nov 27, 2009
    Posts:
    106
    Thank you so much for this... This solved a lot of issues for me!