Search Unity

Question Set Visual Effect Capacity From Script (Not runtime)

Discussion in 'Visual Effect Graph' started by IgnacioLlacay, Nov 19, 2022.

  1. IgnacioLlacay

    IgnacioLlacay

    Joined:
    Dec 11, 2018
    Posts:
    3
    I'm writing an Editor Tool to duplicate a Visual Effect Asset with the same properties except a different Capacity.
    Having trouble to access and change its Capacity.

    I know Unity doesn't allow to change it on runtime, but is it possible to do so script in Editor? Or any ideas for a workaround?

    Current algorithm is (Only need help with Step 3.b.)
    1. Create a GameObject,
    2. Copy VisualEffectAsset and Save on disk
    2. Add a Visual Effect Component
    3. Set Visual Effect properties
    a) Assign VisualEffectAsset (copy) to the new object's Visual Effect component
    b) Set new Capacity (in Visual Effect added component)​
    4. Create & Save the new game object as a Prefab
     
    Last edited: Nov 19, 2022
  2. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,307
    Where is the step where you create new vfx graph asset and save it on disk?
     
  3. IgnacioLlacay

    IgnacioLlacay

    Joined:
    Dec 11, 2018
    Posts:
    3
    Edited post for more clarity on this. Though as the post states, the issue how to set by script the capacity after adding the visual effect component to the new game object.
     
  4. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,307
    Don't take my word as final and wait for answer from devs, but from what I know there is no exposed API to do that. Possibly it could be done via some hacky way by json modification or/and reflection, but you would need to dig into the source code.
     
  5. PaulDemeulenaere

    PaulDemeulenaere

    Unity Technologies

    Joined:
    Sep 29, 2016
    Posts:
    154
    Hello,
    The Visual Effect Editor package is mainly internal, but there are workarounds, of course, you could:
    - Use the abstract scriptable object to modify the serialized data but it would be really complex to navigate through VisualEffect data
    - Admit VisualEffectAsset are serialized as readable YAML and search/replace `capacity: xxx`, but it would be really hacky
    - Massively rely on reflection to reach the internals of Visual Effect as suggested by @Qriva

    These solutions aren't really ideal, that is why I would recommend to grant your code with the internal access of Visual Effect Editor assembly, the Visual Effect Graph package have readable source but isn't documented.

    With internal access you can implement a modifier like this:
    Code (CSharp):
    1. [MenuItem("Edit/VFX/Modify VFX from Script (Multiply capacity by two)", priority = 321)]
    2. public static void ModifyVFX()
    3. {
    4.    var vfxAssets = new List<VisualEffectAsset>();
    5.    foreach (var guid in AssetDatabase.FindAssets("t:VisualEffectAsset", new [] { "Assets" }))
    6.    {
    7.      var assetPath = AssetDatabase.GUIDToAssetPath(guid);
    8.      var vfxAsset = AssetDatabase.LoadAssetAtPath<VisualEffectAsset>(assetPath);
    9.      if (vfxAsset != null)
    10.        vfxAssets.Add(vfxAsset);
    11.    }
    12.  
    13.    foreach (var vfxAsset in vfxAssets)
    14.    {
    15.      var graph = vfxAsset.GetResource().GetOrCreateGraph();
    16.      foreach (var initialize in graph.children.OfType<VFXBasicInitialize>())
    17.      {
    18.        var data = initialize.GetData();
    19.        var capacitySetting = data.GetSetting("capacity");
    20.        var currentCapacity = (uint)capacitySetting.value;
    21.        data.SetSettingValue(capacitySetting.name, currentCapacity * 2);
    22.      }
    23.    }
    24.  
    25.    AssetDatabase.SaveAssets();
    26. }
    There are two ways to access the internal within your project:
    - Using asmdef: The Visual Effect Package declares some InternalVisibleTo (mainly for testing purpose), if you are using an asmdef with the same name than one of InternalVisibleTo then internal will be accessible.
    - Using asmref (since 2019.3): Probably the most straightforward solution and less hacky, you simply have to declare a reference to Unity.VisualEffectGraph.Editor

    N.B: The asmref approach is used in this extension project by @peeweekVFX (see this thread)

    You will find a simple repro project attached to this post, it showcases the asmdef & asmref solution.

    Warning: As previously mentioned, the internal code of the visual effect graph isn't documented but the behavior is also highly subject to change without any script migration.

    Additionally, if you are interacting with internals, it can be useful to browse the source code, you can consider to enable the project generation for the packages in Preferences > External Tools.
     

    Attached Files:

    Last edited: Nov 22, 2022
    IgnacioLlacay and Qriva like this.