Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - wheee09

Pages: [1]
This seems to have been introduced in earlier versions of 2021.1.x and was fixed but when you have the Substance plugin installed, you still get the error.

Based on the other threads, I'm going to guess that we need to wait for the new version of Substance. 

See the original defect:

Verified the issue on:
Unity Editor - 2021.1.6 and 2021.1.7
Substance in Unity Plugin - 2.4.5 and 2.5.4
MacOS (based on the original defect, it seemed to be a defect that affected Macs only)

Steps to reproduce:
  • Install Unity 2021.1.7
  • Install Substance Plugin 2.4.5
  • Import any image
  • Select the image in the editor
See the following error:
InvalidCastException: Specified cast is not valid.
  at UnityEditor.TextureImporterInspector.get_textureInspector () [0x00000] in /Users/bokken/buildslave/unity/build/Editor/Mono/ImportSettings/TextureImporterInspector.cs:119
  at UnityEditor.TextureImporterInspector.DrawPreview (UnityEngine.Rect previewArea) [0x00009] in /Users/bokken/buildslave/unity/build/Editor/Mono/ImportSettings/TextureImporterInspector.cs:1597
  at UnityEditor.PropertyEditor.DrawPreviewAndLabels () [0x0050f] in /Users/bokken/buildslave/unity/build/Editor/Mono/Inspector/PropertyEditor.cs:1310
  at UnityEngine.UIElements.IMGUIContainer.DoOnGUI (UnityEngine.Event evt, UnityEngine.Matrix4x4 parentTransform, UnityEngine.Rect clippingRect, System.Boolean isComputingLayout, UnityEngine.Rect layoutSize, System.Action onGUIHandler, System.Boolean canAffectFocus) [0x001df] in /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.u
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.UIElements.IMGUIContainer:DoOnGUI(Event, Matrix4x4, Rect, Boolean, Rect, Action, Boolean) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/IMGUIContainer.cs:360)
UnityEngine.UIElements.IMGUIContainer:DoMeasure(Single, MeasureMode, Single, MeasureMode) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/IMGUIContainer.cs:815)
UnityEngine.UIElements.VisualElement:Measure(YogaNode, Single, YogaMeasureMode, Single, YogaMeasureMode) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/VisualElement.cs:1539)
UnityEngine.UIElements.VisualElement:<AssignMeasureFunction>b__203_0(YogaNode, Single, YogaMeasureMode, Single, YogaMeasureMode) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/VisualElement.cs:1523)
UnityEngine.Yoga.YogaNode:MeasureInternal(YogaNode, Single, YogaMeasureMode, Single, YogaMeasureMode) (at /Users/bokken/buildslave/unity/build/External/Yoga/csharp/Facebook.Yoga/YogaNode.cs:689)
UnityEngine.Yoga.Native:YGNodeMeasureInvoke(YogaNode, Single, YogaMeasureMode, Single, YogaMeasureMode, IntPtr) (at /Users/bokken/buildslave/unity/build/External/Yoga/csharp/Facebook.Yoga/YogaNative.bindings.cs:146)
UnityEngine.Yoga.Native:YGNodeCalculateLayout(IntPtr, Single, Single, YogaDirection)
UnityEngine.Yoga.YogaNode:CalculateLayout(Single, Single) (at /Users/bokken/buildslave/unity/build/External/Yoga/csharp/Facebook.Yoga/YogaNode.cs:665)
UnityEngine.UIElements.UIRLayoutUpdater:Update() (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/Renderer/UIRLayoutUpdater.cs:51)
UnityEngine.UIElements.VisualTreeUpdater:UpdateVisualTreePhase(VisualTreeUpdatePhase) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/VisualTreeUpdater.cs:155)
UnityEngine.UIElements.Panel:UpdateForRepaint() (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/Panel.cs:940)
UnityEngine.UIElements.Panel:Repaint(Event) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/Panel.cs:985)
UnityEngine.UIElements.UIElementsUtility:DoDispatch(BaseVisualElementPanel) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/UIElementsUtility.cs:446)
UnityEngine.UIElements.UIElementsUtility:UnityEngine.UIElements.IUIElementsUtility.ProcessEvent(Int32, IntPtr, Boolean&) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/UIElementsUtility.cs:209)
UnityEngine.UIElements.UIEventRegistration:ProcessEvent(Int32, IntPtr) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/UIElementsUtility.cs:74)
UnityEngine.UIElements.<>c:<.cctor>b__1_2(Int32, IntPtr) (at /Users/bokken/buildslave/unity/build/External/MirroredPackageSources/com.unity.ui/Core/UIElementsUtility.cs:28)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&) (at /Users/bokken/buildslave/unity/build/Modules/IMGUI/GUIUtility.cs:189)

(Filename: /Users/bokken/buildslave/unity/build/Editor/Mono/ImportSettings/TextureImporterInspector.cs Line: 119)

Here's a sample of my code to find the textures that you want based on the name and make a copy of them:

Code: [Select]
        public void SetFarViewTextures(List<Texture2D> textures) {
            var diffuseTex = textures.FirstOrDefault(texture =>"diffuse"));
            var normalTex = textures.FirstOrDefault(texture =>"any"));
            FarDiffuseTex = new Texture2D(diffuseTex.width, diffuseTex.height, diffuseTex.format, diffuseTex.mipmapCount, true);
            FarNormalTex = new Texture2D(normalTex.width, normalTex.height, normalTex.format, normalTex.mipmapCount, true);

            Graphics.CopyTexture(diffuseTex, FarDiffuseTex);
            Graphics.CopyTexture(normalTex, FarNormalTex);

Hi Jill,

Thanks for the update.  It is reassuring to hear the acknowledgement and that you guys are taking steps to make things better in the future.

As for the patch and your de-recommendation - the patch is there to mitigate the issues that your defect is causing.  It's not meant to be a long term solution by any means.    Given the simplistic nature of the defect and the patch, it's doubtful it would affect your teams ability to assess other defects and reproduce them.  But rest assured, if I do run across more defects I can simply disable the patches and verify them in isolation before writing about them.

Assuming your fix works in the next version then there will be nothing more joyful than removing the patch from my code.

Looking forward to the next release. 

Oh, has your team tried it with the new 2019.4 LTS that released yesterday?

Nope, haven't seen Free().  What does it do?  Unfortunately the API docs are abysmal.

Also ran into another issue yesterday - having do with the rendering of the textures (sync or async).

Unfortunately there doesn't seem to be a way to detect when Substance is done rendering a texture when using RenderAsync().  Which kind of makes it useless from a runtime perspective.

The RenderSync() doesn't seem to be a sync call at all - it doesn't block... so it's pretty useless.

So now I'm restructuring things so that the texture generation is done inside a coroutine so that I can ping the GetGeneratedTextures() and see if there are new textures in there before trying to set them onto a material. 

For people who don't want to wait for a fix... as it seems like it's been months for nothing to happen when it's literally a couple of lines to fix.

You can apply a Harmony patch:
* Download Harmony (really cool tool!) -
* Copy the following code to your Unity project and it will load automatically:

Code: [Select]
    public class SubstancePatchLoader {
        static SubstancePatchLoader() {
            var harmony = new Harmony("SubstancePatches");

            Debug.Log("Loaded Substance Patches.");

    [HarmonyPatch(typeof(EntryPoint), "NeedsReImport")]
    class SubstanceEntryPointPatch {
        static bool Prefix(ref bool __result, string pPath) {
            var obj = AssetDatabase.LoadMainAssetAtPath(pPath);

            if (obj is Material) {
                return true;

            __result = false;
            return false;


The patch is simple - it adds a Prefix method (basically a method that gets run before the actual method gets run) and uses the path string passed into the original method and loads the Asset.

If the loaded object is a Material object, it will allow the actual method to run as normal.
If the loaded object is not a Material object, it will prevent the original method from running (the return false does this) and it will return back a false value back to the caller.  (The thinking being, if it's not a Material object then it doesn't need to be reimported).

Hope it helps other people.

I also patched the Substance.MaterialEditor issue where it spews console log errors when trying to access the Material/Shader properties of code-instantiated materials (ie. not saved as an asset in the file system).  If you want that one, I can also share it.

So did some debugging, it doesn't seem hard to fix...

The issue is in this code snippet of Substance.Editor.EntryPoint:

Code: [Select]
    public static void HandleAssignedTextures()
      foreach (Material material in Resources.FindObjectsOfTypeAll<Material>())
        string assetPath = AssetDatabase.GetAssetPath((UnityEngine.Object) material);
        if (assetPath != "" && assetPath != "Resources/unity_builtin_extra" && (assetPath != "Library/unity default resources" && assetPath != "Library/unity editor resources") && (!assetPath.ToLower().EndsWith(".sbsar") && EntryPoint.NeedsReImport(assetPath)))
          Debug.Log((object) ("Importing: " + assetPath));
          EditorUtility.SetDirty((UnityEngine.Object) material);

The root problem lies in the objects that get returned for:
Code: [Select]

The issue is that for whatever reason, Unity is returning back not just materials (.mat) but also (.asset) files. 
In my particular case, it's returning back  "Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset".

Therefore, when the code tries to run the EntryPoint.NeedsReImport(assetPath) on the .asset file:
Code: [Select]
    public static bool NeedsReImport(string pPath)
      bool flag = false;
      Material material = AssetDatabase.LoadMainAssetAtPath(pPath) as Material;
      for (int propertyIdx = 0; propertyIdx < ShaderUtil.GetPropertyCount(material.shader); ++propertyIdx)
        if (ShaderUtil.GetPropertyType(material.shader, propertyIdx) == ShaderUtil.ShaderPropertyType.TexEnv)
          string propertyName = ShaderUtil.GetPropertyName(material.shader, propertyIdx);
          Texture texture = material.GetTexture(propertyName);
          if (!((UnityEngine.Object) texture == (UnityEngine.Object) null) && AssetDatabase.GetAssetPath((UnityEngine.Object) texture).ToLower().EndsWith(".sbsar"))
            flag = true;
      return flag;

Because the asset is not a Material, it dies trying to access the material.shader property.

The simplest thing to do is to check the objects that get returned from Resources.FindObjectsOfTypeAll<Material>() to filter out objects that do not belong to the Material type.   Seems a bit redundant as I'm not sure why TMP_FontAssets are even coming back when it's not a Material.  It looks to be a ScriptableObject ultimately.

Also have this issue.  It's unfortunately preventing the editor from running my own code when PlayMode is stopped - ie. restoring my scene/hierarchy to the state it was in before I hit play.  This is pretty frustrating.


Is there a reason why you're calling Duplicate in the first place?

I wrote a thread about this just yesterday and it dawned upon me that I didn't actually want or need to use Duplicate.


The short of it is that instead of calling Duplicate do the following - via script:
- access your Substance Graph
- set your parameters (ie. $randomseed)
- generate the textures
- get those generated textures and copy them using Graphics.CopyTexture (see
- set the copied textures to your material

Doing it this way keeps the SubstanceGraph minimal and I can then treat it as a factory for procedurally creating textures based on whatever parameters I want to set when I need them.

It seems to me the only reason why I want to have multiple instances inside the SubstanceGraph (either from Duplicate or from manually creating them) is if I have some notion of a well-defined set of textures that I always want to generate.

Note that CopyTexture is pretty tedious, as in, you'll want to use the constructor that specifies not just the width/length, but also the format and mipmap count and so on. 

Not sure why there isn't a CopyTexture method that just takes another texture and returns you back a copy with everything set for you.

Hopefully that helps you out...

Edit, so copying textures seems like the way to go... I was mislead by the code/comments in the asset that I'm rewriting as the original author was waiting for the Duplicate method to be released so that it could support multiple instances.

Doesn't seem to be a need for any duplication, as I can just generate the textures, copy them and set them to the material and move on to the next planet.


So I'm rewriting this asset that uses Substance for my own purposes.  I never heard of Substance before that so I'm a bit new to it so please bear with me.

What I'm trying to do is essentially generate planets for a level procedurally. 

Here some of the characteristics/requirements:
- There can be many planets on this level.
- Each planet has a type: eg. earth, lava, ice, gas, etc.
- There could be many planets of the same type. 
- These planets (of the same type) should look differently from each other.

This asset has a number of Substance Graph objects that represent each of the planet types (biomes) along with other characteristics like clouds and so on.

Using a "Dust/Barren biome" as an example, it can take a random seed and other properties and generate textures and I can do all of this via the script.

But where I'm stuck is with how I can generate X number of "Dust/Barren" planets with X number of generated textures with different seeds.

What I want to do is this:
* for each planet in the level do the following:
  - create a planet game object
  - access the "Dust/Barren" SGO, choose a random seed, generate the texture
  - assign texture to the planet's material/mesh render

The problem is that the SGO's generated texture is a shared texture and despite generating the texture with a different seed X times, it means that I'm only changing the same texture X times.  This means that every planet I create using the same SGO will look the same - effectively the last random seed that was used.

It appears the "proper" (?) way to do this is to call Duplicate on the Substance Graph object.  This means calling Duplicate, then generating the texture for each planet on the duplicate instance - X times.

The problem with that is that if I have a 100 planets, after generating the planets, if I view the SGO in Unity, it will have a 100 new Substance graph instances and removing them in the editor is a slow and tedious process.

I'm hoping that there's a better way to do this.  It doesn't make any sense that I would need to duplicate a Substance graph.  It smells of poor design.

I'm going to see if I can copy textures at runtime in Unity and perhaps then I can just use one SG to simply act as Texture Factory/Generator (which to me sounds like what it's supposed to be ...)


Found the issue:

Code: [Select]
namespace Substance.Editor
  [CustomEditor(typeof (Material))]
  public class InspectorMaterial : MaterialEditor
    private string myShaderName = "";
    private bool mModified;
    private bool mWorkflowModified;
    private GUITool guiTool;

    public override void OnEnable()
      string assetPath = AssetDatabase.GetAssetPath(;
      if (assetPath == "")
      if (!assetPath.Contains(Globals.SBSAR))
      this.myShaderName = "";

I guess the AssetPath is not set for instantiated materials done at runtime.

I used a Harmony patch to forcibly call the base.OnEnable and it works. 

It doesn't make sense for the override Substance code to short circuit this method and NOT call the base.OnEnable.  Should always call it.  If the assetPath is needed for Substance then do the if check after. 

Hi all,

I've been trying to workaround this very annoying and frustrating error and I'm able to narrow it down to the Substance plugin for Unity.

Simply put, I have a simple script on a game object that only has a mesh renderer with no material set.  I have a button on the script that when clicked (be it in play mode or in editor) does the following:

Code: [Select]
public Material TestMaterial;

public void onClick()
    var material = new Material(TestMaterial);
    var meshRenderer = GetComponent<MeshRenderer>();
    meshRenderer.material = material;

When you inspect the game object and click the button which runs the simple script, you will see the material/shader in the inspector.

When you try to expand it, nothing shows up and you get the following error showing up in the console over and over (while the material/shader is expanded).

I did this on a brand new project without the Substance plugin and it works fine.  As soon as I import the Substance plugin, it happens.

Other notes:
* I'm using the latest Unity 2019.3.15 version.
* Running on MacOS
* Also working with URP.
* This only happens when you instantiate a new material.  If you just reference an existing material, then it's fine.  For example:
Code: [Select]
   meshRenderer.material = TestMaterial;

It's very frustrating.  Tracing through the Unity code, it appears that the LightMapSettings object is not initialized in the MaterialEditor - in fact, the real issue is that the onEnable of the MaterialEditor is never run when you expand the Material/Shader in the inspector which is causing the LightMapSettings to not be initialized thereby causing the NullReferenceException.  My guess is that the Substance plugin is overriding this behaviour and not running base.

Pages: [1]