Search Unity

SkinnedMeshRenderers disappear under specific conditions

Discussion in 'Animation' started by NSBryant, Mar 8, 2019.

  1. NSBryant

    NSBryant

    Joined:
    Jul 16, 2017
    Posts:
    8
    Hello!

    We're seeing a very strange bug where, randomly, some of our character's meshes are disappearing. Some characters lose their hair, others lose their bodies, and some only lose a mesh or two during certain animator states.

    For example:

    Editor Mode:
    hair.jpg

    Play Mode:
    nohair.jpg

    Taking a closer look, it seems like the SkinnedMeshRenderer component has been turned off after going into play mode. If we try to re-enable it, it stays off.

    skinnedmeshrenderer.jpg

    This happens with one exception: if the Animator component on the parent object is NOT enabled, the SkinnedMeshRenderer can be turned back on.

    Naturally, we thought this was a case of an animator adding visibility keyframes on an animation. We tried turning "Import Visibility" off in the import settings of all currently running animations (we have a LOT of animations, so we didn't try changing ALL of them). No dice.

    We rolled back the commits in git to find the culprit. The ONE change that was made that makes this happen is adding a curve to the import settings of an animation (that isn't even running) and driving an Animator value with that.

    Interesting.

    Here's the imported curves:
    curves.jpg

    And here are the values they drive on the Animator:
    curvedrivenproperties.jpg

    If I change the name of Match_start and Match_end on the animator only, those values or no longer driven, but the SkinnedMeshRenderer works properly.

    If I change the name on Match_start and/or Match_end but also change the imported curve names to the same thing, the SkinnedMeshRenderer still works incorrectly.

    It's also worth noting that the animations that have these curves on them are NOT playing at all during my tests, and playing them at runtime seems to have no effect. Also, all of our characters share the same AnimatorController, but it is affecting every character differently.

    Thus, this leads me to believe that if an animator has a parameter that is driven by an animation curve, the Animator turns off certain meshes at certain times.

    I can't figure out what the pattern is, though. Am I missing something? I don't think any of our animations have visibility keyframes, but if they did, would Unity act like this? Could it be that having any empty state defaults to having the visibility of certain meshes turned off? Or is this a horrible bug in the animation code?

    I think for now we'll go with a different solution (using animation events that set the match start/end). But any insight into this will be helpful!

    Thanks,
    Bryant
     
  2. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    I have only very limited experience with using a curve to drive an AnimatorController parameter, but I've never had it disable the renderer randomly like that. See if you can replicate it in an empty project to submit a bug report.
     
  3. NSBryant

    NSBryant

    Joined:
    Jul 16, 2017
    Posts:
    8
    Tested this out a bit more, and it looks like it has to do with a behavior we added to the prefab.

    We're using Playables to blend one-off animations with the animator controller. On Start(), we do the following:


    _simpleAnimationGraph = PlayableGraph.Create();
    AnimationPlayableOutput animOutput = AnimationPlayableOutput.Create(_simpleAnimationGraph, "AnimOutput", _animRef);
    _simpleAnimationMixer = AnimationLayerMixerPlayable.Create(_simpleAnimationGraph, 2);
    animOutput.SetSourcePlayable(_simpleAnimationMixer);
    animOutput.SetSourceOutputPort(0);

    AnimatorControllerPlayable cPlay = AnimatorControllerPlayable.Create(_simpleAnimationGraph, _animRef.runtimeAnimatorController);
    _simpleAnimationMixer.ConnectInput(0, cPlay, 0, 1f);
    _simpleAnimationMixer.SetInputWeight(0, 1f);

    _simpleAnimationGraph.Play();

    _simpleAnimationGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);


    We set up two inputs on the AnimationLayerMixerPlayable, but we don't assign it until there's an animation to play. Turning this behavior off or commenting out this code makes the meshes work properly again.

    I'm still not sure what the issue is, though, since I haven't been able to replicate it in an empty project. I'll continue to work on this...

    [Edited for code clarity]
     
  4. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    That's a bit different from the way I initialise the graph in Animancer (link in my signature below). Basically, I don't create an AnimationPlayableOutput or connect my root playable to any output, then I use AnimationPlayableUtilities.Play to play the graph and tell it which playable to use as the output. I have no idea if that actually makes a difference to anything though, I just based it on the SimpleAnimation component.

    The only thing that actually looks wrong to me is that you're passing _animRef.runtimeAnimatorController into the AnimatorControllerPlayable. When you use playables, the regular Animator.runtimeAnimatorController still executes its state machine, but its output has no effect on the model so it's likely just wasting performance. You should serialize the controller reference in your script and keep the Animator's Controller field empty.