Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Access a SubstanceGraph in Code to edit a Material (Substance Designer Plugin) Unity 2018+

Discussion in 'Formats & External Tools' started by KyleHatch85, Jun 28, 2018.

  1. KyleHatch85

    KyleHatch85

    Joined:
    Dec 13, 2011
    Posts:
    99
    Hi, so colleague of mine has made a nice looking oil slick in Substance Designer. Previously in Unity 2017 he could just put the sbar file into Unity and then i could edit the information via the Material. In the code see old way. I can see from the help, https://support.allegorithmic.com/documentation/display/integrations/Unity+2018
    that the new way you reference the Substance Graph and it does as i need. However i have to drag the substance graph from the material in the project assets into the inspector. I want to be able to get my objects active material's version of the substance graph from code.

    Because at the moment if i have many spills and i want to edit 1, i can't it edits them all. my code below.


    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using Substance.Game;
    4. using UnityEditor;
    5.  
    6. public class OilTest : MonoBehaviour
    7. {
    8.     [SerializeField] private GameObject m_PuddleObject;
    9.  
    10.     private Material m_OilMat;
    11.  
    12.     private SubstanceGraph m_SubstanceGraph;
    13.     private Substance.Game.Substance m_Substance;
    14.  
    15.     // Use this for initialization
    16.     void Start()
    17.     {
    18.         m_Substance = Substance.Game.Substance.Find(Application.dataPath + );
    19.  
    20.         //Old Way
    21.         Renderer renderer = m_PuddleObject.GetComponent<Renderer>();
    22.         if (null != renderer)
    23.         {
    24.             m_OilMat = renderer.material;
    25.             if (null != m_OilMat)
    26.             {
    27.                 m_OilMat.SetFloat("Puddle_Size", 0.7f);
    28.             }
    29.             else
    30.             {
    31.                 Debug.LogError("Oil is null");
    32.             }
    33.         }
    34.         else
    35.         {
    36.             Debug.LogError("Renderer is null");
    37.         }
    38.  
    39.         //New Way, but how do i get the substance graph?
    40.         m_SubstanceGraph.SetInputFloat("Puddle_Size", 0.7f); //set size
    41.         m_SubstanceGraph.QueueForRender(); // queue the substance to render
    42.  
    43.     }
    44. }
    45.  

    one for @wesm?
     
  2. KyleHatch85

    KyleHatch85

    Joined:
    Dec 13, 2011
    Posts:
    99
    So this is what i'm thinking currently. But the SubstanceGraph.Find(Material) always returns null.

    Code (csharp):
    1. using UnityEngine;
    2. using Substance.Game;
    3. using UnityEditor;
    4.  
    5. public class OilTest : MonoBehaviour
    6. {
    7.     [SerializeField] private GameObject m_PuddleObject;
    8.  
    9.     private Material m_OilMat;
    10.     private SubstanceGraph m_SubstanceGraph;
    11.  
    12.     // Use this for initialization
    13.     void Start()
    14.     {
    15.         Renderer renderer = m_PuddleObject.GetComponent<Renderer>();
    16.         if (null != renderer)
    17.         {
    18.             m_OilMat = renderer.material;
    19.             if (null != m_OilMat)
    20.             {
    21.                 m_SubstanceGraph = SubstanceGraph.Find(m_OilMat);
    22.                 if (null != m_SubstanceGraph)
    23.                 {
    24.                     m_SubstanceGraph.SetInputFloat("Puddle_Size", 0.7f); //set size
    25.                     m_SubstanceGraph.QueueForRender(); // queue the substance to render
    26.                 }
    27.                 else
    28.                 {
    29.                     Debug.LogError("Substance graph is null");
    30.                 }
    31.             }
    32.             else
    33.             {
    34.                 Debug.LogError("Oil is null");
    35.             }
    36.         }
    37.         else
    38.         {
    39.             Debug.LogError("Renderer is null");
    40.         }
    41.     }
    42. }
     
  3. Chris_Dougherty

    Chris_Dougherty

    Joined:
    Jul 7, 2015
    Posts:
    3
    Try using sharedMaterial instead. Here is the code that I use in the Editor.

    Code (CSharp):
    1. Material mat;
    2. SubstanceGraph gr;
    3. mat = Selection.activeGameObject.GetComponent<Renderer>().sharedMaterial;
    4. gr=SubstanceGraph.Find(mat);
    5. Debug.Log("Graph Found: " + gr.name);
     
    Last edited: Jul 5, 2018
  4. KyleHatch85

    KyleHatch85

    Joined:
    Dec 13, 2011
    Posts:
    99
    I tired that, it was unsuccessful. Which version of unity are you using? I'm currently using 2018.1.6f1.

    Also given that your using Selection.activeGameObject i assume your doing this as an editor tool and not at run time.
     
  5. Chris_Dougherty

    Chris_Dougherty

    Joined:
    Jul 7, 2015
    Posts:
    3
    I am currently using 2018.1.0f2, 2018.1.1f1 and 2018.1.7f1
    I changed my code to use MonoBehavior.

    I have 4 test objects in my scene, each one has a different substance attached to it.
    When i put this code on my objects and press play it will not find a graph on any object, if I select one of the objects in the Hierarchy and then press "Go to Substance Graph" and press play after that it will find the graphs on every object(most of the time).

    Code (CSharp):
    1. SubstanceGraph gr;
    2. void Start()
    3. {
    4.         Material mat = null;
    5.         mat = this.GetComponent<Renderer>().sharedMaterial;
    6.         Debug.Log(this.GetComponent<Renderer>().sharedMaterial);
    7.         gr = SubstanceGraph.Find(mat);
    8.         if (gr)
    9.         {
    10.             Debug.Log(gr.name);
    11.         }
    12. }
    In the Editor i use 'selection.activeGameObject' instead of 'this'


    Code (CSharp):
    1.   Material mat = null;
    2. mat = Selection.activeGameObject.GetComponent<Renderer>().sharedMaterial;
    3. Debug.Log(Selection.activeGameObject.GetComponent<Renderer>().sharedMaterial);
    4. gr = SubstanceGraph.Find(mat);
    5. if (gr == null)
    6. {
    7. //Debug.Log("Selected graph is null, trying another Method...");
    8. string assetPath = AssetDatabase.GetAssetPath(Selection.activeGameObject.GetComponent<Renderer>().sharedMaterial);
    9. Debug.Log(assetPath);
    10. string pGraphLabel = string.Empty;
    11. if (Selection.activeGameObject && Selection.activeGameObject.GetComponent<Renderer>())
    12. pGraphLabel = (Selection.activeGameObject.GetComponent<Renderer>().sharedMaterial.name.ToString().Remove(0, "mat.".Length));
    13. Debug.Log(pGraphLabel);
    14. Globals.GoToSubstanceGraph(assetPath, pGraphLabel);
    15. Debug.Log(gr);
    16. Selection.activeObject = target;
    17. }
     
  6. Chris_Dougherty

    Chris_Dougherty

    Joined:
    Jul 7, 2015
    Posts:
    3
    I am currently using 2018.1.0f2, 2018.1.1f1 and 2018.1.7f1
    I changed my code to use MonoBehavior.

    I have 4 test objects in my scene, each one has a different substance attached to it.
    When I put this code on my objects and press play it will not find a graph on any object, if I select one of the objects in the Hierarchy and then press "Go to Substance Graph" and press play after that it will find the graphs on every object(most of the time).

    Code (CSharp):
    1. SubstanceGraph gr;
    2. void Start()
    3. {
    4.         Material mat = null;
    5.         mat = this.GetComponent<Renderer>().sharedMaterial;
    6.         Debug.Log(this.GetComponent<Renderer>().sharedMaterial);
    7.         gr = SubstanceGraph.Find(mat);
    8.         if (gr)
    9.         {
    10.             Debug.Log(gr.name);
    11.         }
    12. }
    In the Editor i use 'selection.activeGameObject' instead of 'this'
    if the graph is null I use a function in 'Globals' to manually go to the graph.

    Code (CSharp):
    1. Material mat = null;
    2. GameObject SelectedObj = Selection.activeGameObject;
    3. mat = SelectedObj.GetComponent<Renderer>().sharedMaterial;
    4. Debug.Log(SelectedObj.GetComponent<Renderer>().sharedMaterial);
    5. gr = SubstanceGraph.Find(mat);
    6. if (gr == null)
    7. {
    8. Debug.Log("Selected graph is null, trying another Method...");
    9. string assetPath = AssetDatabase.GetAssetPath(SelectedObj.GetComponent<Renderer>().sharedMaterial);
    10. string pGraphLabel = string.Empty;
    11. if (SelectedObj.GetComponent<Renderer>())
    12. pGraphLabel = (SelectedObj.GetComponent<Renderer>().sharedMaterial.name.ToString().Remove(0, "mat.".Length));
    13. Debug.Log(pGraphLabel);
    14. Globals.GoToSubstanceGraph(assetPath, pGraphLabel);
    15. Debug.Log(gr);
    16. Selection.activeObject = target;
    17. }