Search Unity

Adding random "twitches" or "saccades" to existing movement and animation

Discussion in 'Animation' started by dradog33, Mar 22, 2018.

  1. dradog33

    dradog33

    Joined:
    Nov 3, 2017
    Posts:
    9
    I am using an Animation controller to move an object to be in the view of the camera and once there track the camera by always pointing at it. That is working. I also want to add some "random" movements like twitches back and forth to the existing movement. I have been looking online and this forum and tried a bunch of solutions but nothing seems to work.

    I tried creating an animation that just does the twitch movement and then added an additional animation layer that has that animation on it and then I randomly "play" that state after a random interval. I can get the twitch to work but the side effect is that all the other rotations are being ignored, i.e. the object no longer points at the camera. I have set the layer to additive and even turning the weight all the way to zero still has the same effect of eliminating the other rotation moves I was doing. I also saw some comments on this forum about needing an animation on the first layer that has the same intital keyframe as the additive layer. This is problematic because I don't know what my starting rotation will be. I just keyframed the current rotation and it still doesn't work but that doesn't really surprise me.

    Does anyone have any ideas on how to add "random" blinks? It looks like I can just hard code the actual rotations into the state behavior but that will be kind of hacky and will make getting the correct values difficult to iterate. Any suggestions would be greatly appreciated.
     
  2. PGJ

    PGJ

    Joined:
    Jan 21, 2014
    Posts:
    899
    Try to add the random movement animation to an empty object that is the parent of your GameObject. Then, the random movement and the "normal" animation shouldn't interfere with each others.
     
    theANMATOR2b likes this.
  3. dradog33

    dradog33

    Joined:
    Nov 3, 2017
    Posts:
    9
    Thanks for the suggestion. Unfortunately, the "blink" is moving only part of the object instead of the whole object. The object is a set of nested cubes and only one of the cubes is moving.
     
  4. DavidGeoffroy

    DavidGeoffroy

    Unity Technologies

    Joined:
    Sep 9, 2014
    Posts:
    542
    Hello @dradog33,

    If I understood your use case correctly, you want to align something to look at the camera (I imagine you do that using script), and you want to "add" an animation on top of this alignment.

    You could use Root motion to do this, but you would probably end up with some kind of drift, and it would be fairly hard to make this consistent
    And, if you try to directly animate the rotation in absolute terms, it will always override whatever you have done using scripts.

    So, you can either:
    1. Calculate the correct orientation rotation from the default position of your object, and add it to the twitch animation every frame (in LateUpdate)
    2. Animate an invisible object with your twitch animation, and add this local rotation every frame (in LateUpdate) to your oriented object (oriented in Update or LateUpdate)
    3. (harder) Animate your twitch as a Vector3 in your orientation script, then add this rotation in LateUpdate to your "Look at Camera orientation"
     
  5. dradog33

    dradog33

    Joined:
    Nov 3, 2017
    Posts:
    9
    Thank you for the reply. Because I was already creating the look movement in code, it ended up being simpler to just add the offset a la #3 in your solution but man it was hard to get there. It took me like three rewrites. This is what I ended up doing and it looks better than the actual jitter animation I was trying to add:

    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
    elapsedTime += Time.deltaTime;
    var step = speed * Time.deltaTime;
    var targetDir = cameraTransform.position - bot.transform.position;
    if (elapsedTime >= waitInterval)
    {
    if (!glancingAway)
    {
    offsetVector = new Vector3(Random.Range(minOffset, maxOffset), Random.Range(minOffset, maxOffset));
    waitInterval = 1;
    glancingAway = true;
    }
    else
    {
    offsetVector = new Vector3(0, 0, 0);
    waitInterval = Random.Range(minTime, maxTime);
    glancingAway = false;
    }
    elapsedTime = 0;
    Debug.Log("Next Wait Time " + waitInterval);
    }
    Debug.Log("Gaze Offset " + offsetVector);
    targetDir += offsetVector;
    var newDir = Vector3.RotateTowards(bot.transform.forward, targetDir, step, 0.0f);
    // Rotate to face player
    var newRotation = Quaternion.LookRotation(newDir);

    bot.transform.rotation = newRotation;
    }



    It would still be great to have a more generic solution for layering animation effects on top of scripted movements.