Search Unity

Setting a public variable on TrackAsset to be accessed in behaviour mixer

Discussion in 'Timeline' started by spakment, Jul 29, 2020.

  1. spakment

    spakment

    Joined:
    Dec 19, 2017
    Posts:
    96
    I'm trying to find a way to access a variable (currently set on the Track Asset) while processing the clips in the behaviour mixer, its a scriptable object that configures some texture offsets to switch between on the timeline clips.

    Is there any way to access this or do I have to add the scriptable object reference on every clip?
    (which seems a messy way to handle the data as its a "track" level setting) - but I can't understand from any examples or docs a way in which I can reference this variable.




    Here's an example of the TrackAsset

    Code (CSharp):
    1. public class LipSwitcherTrack : TrackAsset
    2. {
    3.  
    4.     public LipSwitcherPhonemsDefinition definitions;
    5.     public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    6.     {
    7.         return ScriptPlayable<LipSwitcherMixerBehaviour>.Create (graph, inputCount);
    8.     }
    9. }

    and the Mixer Behaviour PlayableBehaviour

    Code (CSharp):
    1. public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    2.     {
    3.         m_TrackBinding = playerData as Material;
    4.  
    5.         if (!m_TrackBinding)
    6.             return;
    7.  
    8.         int inputCount = playable.GetInputCount ();
    9.  
    10.         float greatestWeight = 0.3f; //using a float higher than 0 to avaoid any precicion issues - we only want playables at weight = 1 or at minum higher then .5 really
    11.  
    12.  
    13.         //every frame it processes EVERY clip on the timeline....
    14.         for (int i = 0; i < inputCount; i++)
    15.         {
    16.             float inputWeight = playable.GetInputWeight(i); //get the weight for this "blend"
    17.  
    18.  
    19.             if ( inputWeight > greatestWeight){
    20.                
    21.                 greatestWeight = inputWeight;
    22.                
    23.                 ScriptPlayable<LipSwitcherBehaviour> inputPlayable = (ScriptPlayable<LipSwitcherBehaviour>)playable.GetInput(i);
    24.                 LipSwitcherBehaviour input = inputPlayable.GetBehaviour ();
    25.                
    26. //
    27.                 // This is were I need to be able to access the scriptable object set on the TrackAsset
    28. //              
    29.                 m_offset = input.offset;
    30.  
    31.                 if( m_lastOffset != m_offset){
    32.  
    33.                     m_TrackBinding.mainTextureOffset = m_offset;
    34.                     m_lastOffset = m_offset;
    35.                 }
    36.  
    37.  
    38.             }
    39.  
    40.         }
    41.     }
     
  2. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    The most straightforward way is to also put it as a variable on your LipSwitcherMixerBehaviour, and assign it in CreateTrackMixer.

    Code (CSharp):
    1. var playable = ScriptPlayable<LipSwitcherMixerBehaviour>.Create (graph, inputCount);
    2. playable.GetBehaviour().definition = definition;
    3. return playable;

    Alternatively you can use a 'template' approach - make your playable behaviour serializable and have the track store a 'template' of it. When you call create playable, pass the template.

    The advantage of this approach, is the editor supports animation of those public fields (of certain types), similar to audio track volume.


    Code (CSharp):
    1.  
    2. [Serializable]
    3. public class LipSwitcherMixerBehaviour : PlayableBehaviour
    4. {
    5.      public LipSwitcherPhonemsDefinition definitions;
    6.      public float SomeOtherTrackVariable;
    7.      public override void ProcessFrame(...)
    8.      ...
    9. }
    10.  
    11.  
    12. public class LipSwitcherTrack : TrackAsset
    13. {
    14.     public LipSwitcherMixerBehaviour template;
    15.  
    16.     public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    17.     {
    18.         return ScriptPlayable<LipSwitcherMixerBehaviour>.Create (graph, inputCount, template);
    19.     }
    20. }
     
    spakment likes this.
  3. spakment

    spakment

    Joined:
    Dec 19, 2017
    Posts:
    96
    @seant_unity
    thank you so much, I was having a complete mental block on this one.
    You're first solution is exactly what I was looking for, its made the implementation so much more flexible, cheers!
     
  4. crdmrn

    crdmrn

    Joined:
    Dec 24, 2013
    Posts:
    152
    Thi is not always a desirable solution though: having a variable fetched from the TrackAsset makes it "global" for all the clips on that Track, that's what should be possible.

    If the variable is set on the clips at creation, it means that if you change the variable on the TrackAsset, then you need to change on the clips as well, not ideal.
    Also, what happens if you drag a clip to another Track of the same type? really not ideal cause you might end up with a reference on another track. :S
     
  5. spakment

    spakment

    Joined:
    Dec 19, 2017
    Posts:
    96
    Absolutely - it depends on your use case, always best to do what makes sense for your timeline and project.
    For my usage this is the desired behaviour as the track is used for lip syncing and needs to hold the reference to the material and the clips contain the phoneme, which define how some texture offsets get processed on the material.

    Again for my project this is the desired behaviour. When dragging between tracks I want the clips to reference a completely different material setup at the track level, but still hold their phoneme data.
     
  6. crdmrn

    crdmrn

    Joined:
    Dec 24, 2013
    Posts:
    152
    It's the desirable behaviour for your project, and that's ok.
    But it's not an answer to the question you asked in your first post and that should be clear to whoever comes across this thread; I just wanted to point out to @seant_unity that the answer provided works for you, but doesn't address the general issue you pointed out with your initial question ^^"