Search Unity

How to bind to component fields within a constraint?

Discussion in 'Animation Rigging' started by aylanonsense, Jun 18, 2020.

  1. aylanonsense

    aylanonsense

    Joined:
    Sep 22, 2019
    Posts:
    5
    Suppose I had a simple component like so:
    public class CoolComponent : MonoBehaviour {  public float coolMultiplier; }

    And let's say I wanted to write an Animation Rigging constraint that did the following:
    targetObject.position = sourceObject.position * sourceObject.coolMultiplier;

    How would I accomplish this?


    IDEA #1:
    I could try giving the IWeightedAnimationJob two fields:
    Code (CSharp):
    1. public ReadWriteTransformHandle targetObject;
    2. public CoolComponent sourceObject;
    But of course that won't work--it'll end up throwing a "Job structs may not contain any reference types" error. Makes sense; the job shouldn't be passed the entire CoolComponent by reference.


    IDEA #2:
    I could try binding my job like this:
    Code (CSharp):
    1. // IWeightedAnimationJob
    2. public ReadWriteTransformHandle targetObject;
    3. public ReadOnlyTransformhandle sourceObject;
    4. public FloatProperty coolMultiplier;
    5.  
    6. // IAnimationJobData
    7. public Transform targetObject;
    8. public CoolComponent sourceObject;
    9.  
    10. // AnimationJobBinder's Create method
    11. targetObject = ReadWriteTransformHandle.Bind(animator, data.targetObject.transform)
    12. sourceObject = ReadOnlyTransformHandle.Bind(animator, data.targetObject.transform)
    13. coolMultiplier = FloatProperty.Bind(animator, data.sourceObject, "coolMultiplier")
    This compiles and runs, but it seems the coolMultiplier field always evaluates to 0.0f within the job, even if it's set to a different value. I couldn't find a combination of attributes that would actually get the animation job to properly pick up the coolMultiplier's true value.


    IDEA #3:
    Same as above, but try binding in the AnimationJobBinder like such:
    coolMultiplier = FloatProperty.Bind(animator, component, "m_Data.sourceObject.coolMultiplier")

    That just reults in a "The PropertyStreamHandle is invalid" error.


    IDEA #4:
    Add the following to the IAnimationJobData:
    public float coolMultiplier { get => sourceObject.coolMultiplier; }

    And then try binding to that in the AnimationJobBinder as follows:
    coolMultiplier = FloatProperty.Bind(animator, component, PropertyUtils.ConstructConstraintDataPropertyName(nameof(data.coolMultiplier)))

    This just results in another "The PropertyStreamHandle is invalid" error.


    So what's the right way to make this work? And as a follow-up question, what's the best way to actually learn the ecosystem of the Jobs system and the Animation system and the Animation Rigging package. I've watched tons of great Unite and GDC talks on the subjects, I've seen the rad Unity announcement blog posts, and I've browsed through the (often very sparse) documentation... and honestly I still feel like I can't answer most of my own questions. What's the best way for a developer to actually learn all of this stuff both at a conceptual level and at a practical programming level?
     
  2. simonbz

    simonbz

    Unity Technologies

    Joined:
    Sep 28, 2015
    Posts:
    295
    Hi,

    I don't think you're far off from making your constraint work actually. The remaining issue lies with how you set up your `coolMultiplier`.

    FloatProperty represents an animated float property on your component. If you want this property to be set on a MonoBehaviour component on your sourceObject, then you need to bind it to the animator with the right component and path.

    something like
    Code (CSharp):
    1. var myCoolMultiplierComponent = sourceObject.GetComponent<MyCoolMultiplierComponent>();
    2. coolMultiplier = FloatProperty.Bind(animator, myCoolMultiplierComponent, "coolMultiplier");
    should work.

    However, you should be cautious with that, as your source object may very well be outside of the animated hierarchy, and thus trying to bind it to the Animator will result in unresolved errors. For this reason, most parameters in Animation Rigging constraints are set on the constraint component itself.

    As for documentation, this is coming together. We have just finished an overhaul of the API documentation and this should be available in an upcoming version of Animation Rigging.
     
  3. tonycoculuzzi

    tonycoculuzzi

    Joined:
    Jun 2, 2011
    Posts:
    301
    Is there a way to do this without assuming the FloatProperty is animated? I assume that may be preventing me from modifying the base property.

    In my case, the FloatProperty is set through code or the inspector, but FloatProperty doesn't seem to update once it's initially bound using Bind