VFX Graph : How do I set a transform reference / set property binder by script?

Hi,

In my VFX, I have a reference to a Transform, that I can assign in the scene through the property binder. However, if my VFX is instantiated at runtime, I can’t find a way to assign this through script.

Yeah, I could change my graph to expose a Vector3 for position, another one for Eulers, and another one for scale, but that would be very convenient and simpler if I could do what you can do in the editor.

So, how do I add / set a property binder through script?

Thanks!

Did you ever figure this out? The UnityEngine.VFX.Utility.VFXPositionBinder is not accessible, how can I get or add that to a Visual Effect that is playing at runtime?

Not only you’re late, but you also didn’t read the original post.

No, I had to expose all the variables instead :confused:

Hi!
Inside VFXTransformBinder class there is a example of how it’s done.
For my cases i wrote this extension class.

public static class VFXExtensions
{
    private const string VFXPositionPostfix = "_position";
    private const string VFXRotationPostfix = "_angles";
    private const string VFXScalePostfix = "_scale";

    public static void SetVFXTransformProperty(this VisualEffect visualEffect, string propertyName, Transform transform)
    {
        var position = propertyName + VFXPositionPostfix;
        var angles = propertyName + VFXRotationPostfix;
        var scale = propertyName + VFXScalePostfix;

        visualEffect.SetVector3(position, transform.position);
        visualEffect.SetVector3(angles, transform.eulerAngles);
        visualEffect.SetVector3(scale, transform.localScale);
    }
}
4 Likes

For anybody how face this issue, the solution is to clone VFXTransformBinder to new class

The new class as below:

using UnityEngine;
using UnityEngine.VFX;
using UnityEngine.VFX.Utility;

// The VFXBinder Attribute will populate this class into the property binding's add menu.
[VFXBinder("Transform/MyTransform")]
// The class need to extend VFXBinderBase
public class MyVFXTransformBinder : VFXBinderBase
{
    public string Property { get { return (string)m_Property; } set { m_Property = value; UpdateSubProperties(); } }

    [VFXPropertyBinding("UnityEditor.VFX.Transform"), SerializeField, UnityEngine.Serialization.FormerlySerializedAs("m_Parameter")]
    protected ExposedProperty m_Property = "Transform";
    public Transform Target = null;

    private ExposedProperty Position;
    private ExposedProperty Angles;
    private ExposedProperty Scale;
    protected override void OnEnable()
    {
        base.OnEnable();
        UpdateSubProperties();
    }

    void OnValidate()
    {
        UpdateSubProperties();
    }

    void UpdateSubProperties()
    {
        Position = m_Property + "_position";
        Angles = m_Property + "_angles";
        Scale = m_Property + "_scale";
    }

    public override bool IsValid(VisualEffect component)
    {
        return Target != null && component.HasVector3((int)Position) && component.HasVector3((int)Angles) && component.HasVector3((int)Scale);
    }

    public override void UpdateBinding(VisualEffect component)
    {
        component.SetVector3((int)Position, Target.position);
        component.SetVector3((int)Angles, Target.eulerAngles);
        component.SetVector3((int)Scale, Target.localScale);
    }

    public override string ToString()
    {
        return string.Format("Transform : '{0}' -> {1}", m_Property, Target == null ? "(null)" : Target.name);
    }
}

Then add it either by dragging the new class file and dropping to visual effect inspector, or from VFX Property Binder inspector (attached screenshot)

Then you can access it from script as below:

MyVFXTransformBinder myTransformBinder =  vfx.GetComponent<MyVFXTransformBinder>();
myTransformBinder.Target = otherGameObject.transform;

Hope this helps.

8 Likes

Thanks! Works like a charm!

Unfortunate, but true. VFXTransformBinder needs to be public. So do its siblings.

component.SetVector3((int)Scale, Target.localScale);

Don’t you guys think this is en error, and it should be Target.lossyScale ?