Search Unity

Feature Request Better workflow for creating Custom Function nodes

Discussion in 'Shader Graph' started by Bers1504, Feb 24, 2023.

  1. Bers1504

    Bers1504

    Joined:
    Apr 28, 2018
    Posts:
    17
    First, I'd like to thank Unity team for allowing the creation of Custom Function nodes from hlsl include files. I find it extremely useful.

    However, I find the workflow for implementing Custom Functions in File mode to be inefficient.

    The current process requires the manual creation of a .hlsl file for each custom node, along with its boilerplate code. This can be disruptive to one's creative flow, particularly since there is no way to generate hlsl files from the Project View Create Asset menu nor from the Shader Graph Inspector. As a result, creating each custom node necessitates several context switches:

    a) From the Shader Graph view, the need for a custom node arises, and one is created with the addition of necessary parameters.
    b) Because there is no way to generate an hlsl file from the Graph Inspector, the user switches to the Unity Project View to locate the folder where the new hlsl file should be created.
    c) However, creating a new hlsl file from the Project View is not feasible. As a result, the user selects "Show in Explorer" to create a new file in Windows Explorer.
    d) Since there is no direct way to create an hlsl file from Windows Explorer, the user typically creates a text file and then renames it with an .hlsl extension.
    e) The user then switches to a text editor to enter the boilerplate code, including the #ifndef, function name, and parameters.
    f) Finally, the user looks up the most up-to-date Unity documentation for Custom Nodes to determine the actual parameter types for Texture2D and SampleState before beginning work on the custom shader node.

    Most of this process could be automated since all the necessary information to create the .hlsl file structure is already available in the Custom Function node Graph Inspector window.

    It would be extremely beneficial to have a "New" button added to the Graph Inspector Window that generates the custom .hlsl shader file, complete with include guards, function signature, and example code to sample a texture (if at least one Texture input parameter specified). While this may appear to be a minor feature request, it has the potential to save each user 5-10 minutes every time they create a custom function .hlsl file, resulting in substantial time savings, less distraction, and a more pleasant experience.


    upload_2023-2-24_12-45-11.png
     

    Attached Files:

  2. Bers1504

    Bers1504

    Joined:
    Apr 28, 2018
    Posts:
    17
    Not as good as the feature requested, but I have implemented the simple part where an example .hlsl file for a Custom Function is created from the AssetContextMenu. :

    upload_2023-2-24_15-50-31.png

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System.IO;
    4.  
    5. public class HLSLAssetHelper
    6. {
    7.     public static string ProjectViewSelectedFolder()
    8.     {
    9.         //Note : Application.dataPath = "[ProjectPath]/Assets". Remove last part to get project path.
    10.         string projectFolder = Path.GetDirectoryName(Application.dataPath);
    11.  
    12.         string activeObjectFullPath = Path.Combine(projectFolder, AssetDatabase.GetAssetPath(Selection.activeObject));
    13.  
    14.         if((File.GetAttributes(activeObjectFullPath) & FileAttributes.Directory) == FileAttributes.Directory)
    15.         {
    16.             return activeObjectFullPath;
    17.         }
    18.         else
    19.         {
    20.             return Path.GetDirectoryName(activeObjectFullPath);
    21.         }
    22.     }
    23.  
    24.     [MenuItem("Assets/Create/Shader Graph/Custom Function HLSL")]
    25.     public static void CreateAsset()
    26.     {
    27.         string functionName = TextFieldInputDialog.Show("Custom Function HLSL", "Custom function name:", "MyFunction");
    28.         if (string.IsNullOrEmpty(functionName))
    29.         {
    30.             return;
    31.         }
    32.  
    33.         string defSymbolName = functionName.ToUpper() + Random.Range(0, 9999999) + "_INCLUDED";
    34.  
    35.         string fileContent =
    36. @"//UNITY_SHADER_NO_UPGRADE
    37. #ifndef " + defSymbolName + @"
    38. #define " + defSymbolName + @"
    39.  
    40. void " + functionName + @"_float(in float2 uv, in UnityTexture2D tex, in UnitySamplerState tex_sampler, out float4 color)
    41. {
    42.    color = SAMPLE_TEXTURE2D(tex, tex_sampler, uv);
    43. }
    44.  
    45. #endif //" + defSymbolName;
    46.  
    47.         string parentFolder = ProjectViewSelectedFolder();
    48.         string filePath = Path.Combine(parentFolder, functionName + ".hlsl");
    49.         File.WriteAllText(filePath, fileContent);
    50.  
    51.         AssetDatabase.Refresh();
    52.     }
    53. }
    I am not providing my code for TextFieldInputDialog, but you can see this link to implement a similar function.
     
  3. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,314
    Do you know there is no need to have each custom function in separate file? You could even have all of them in single file.
    Aside from that, I agree there could be button generating template and/or with provided in/out parameters to make life easier.
     
    sebastienb_unity likes this.
  4. sebastienb_unity

    sebastienb_unity

    Joined:
    Jul 19, 2019
    Posts:
    1
    Good point about having multiple custom functions in a single file, that is indeed possible and can improve the workflow for some people.
    For my typical use case, however, I prefer creating separate files for one-off shaders, where I want to prevent unnecessary coupling between various different components.

    Also, HLSL code that I want to reuse will typically be in some "Core" HLSL utility that I will include into my one-off, custom function shader file..

    e.g.
    Code (CSharp):
    1. //UNITY_SHADER_NO_UPGRADE
    2. #ifndef SIDESCROLLERSAMPLE_INCLUDED
    3. #define SIDESCROLLERSAMPLE_INCLUDED
    4.  
    5. #include "Assets/Core/Shaders/HLSL/PBR/PBRUtilities.hlsl"
    6.  
    7. void SideScrollerSample_float(in float2 uv,
    8.     in float spacing,
    9.     in UnityTexture2D texLeft,
    10.     in UnityTexture2D texMiddle,
    11.     in UnityTexture2D texRight,
    12.     UnitySamplerState texSampler, out float4 color)
    13. {
    14.     //function body here
    15.     //...
    16. }
    17.  
    18. #endif //SIDESCROLLERSAMPLE_INCLUDED