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

Adding objects to assets

Discussion in 'Scripting' started by Wahooney, May 28, 2012.

  1. Wahooney

    Wahooney

    Joined:
    Mar 8, 2010
    Posts:
    281
    Hi all,

    I'm having some troubles with adding objects to assets, I've made a scriptable object and now I want to add materials and textures to it. Problem is that it seems a scripted asset doesn't seem to be able to be a parent asset, so I'll go:
    Code (csharp):
    1. AssetDatabase.AddObjectToAsset(myTexture, myAsset);
    2. AssetDatabase.ImportAsset(AssetImporter.GetAssetPath(myTexture));
    3.  
    And what I end up with is:
    Assets/
    myAsset.asset (empty)/
    myAsset (texture)
    myAsset (scripted asset)​

    Can anyone recomment a course of action for me? And I REALLY don't want to convert my scriptable asset into a prefab ( I know that will make things work out better )

    Thanks for any input!
     
  2. MADmarine

    MADmarine

    Joined:
    Aug 31, 2010
    Posts:
    627
    I'm assuming you're talking about a class that inherits from ScriptableObject, if not, can you clarify what you mean by a scriptable asset?

    From the documentation:

    "A class you can derive from if you want to create objects that don't need to be attached to game objects.

    This is most useful for assets which are only meant to store data."

    These kind of objects are not designed to be attached to anything, so they will not work with parenting. Consider using MonoBehaviour instead.
     
  3. Wahooney

    Wahooney

    Joined:
    Mar 8, 2010
    Posts:
    281
    It's derived from a ScriptableObject, it is a pure data storage class so I don't want it to be a MonoBehaviour, though it is possible to use one, but I really want to avoid that.

    All of that is kinda beside the point though :p I need to be able to add textures/materials/whatever to a ScriptableObject derived asset in my project without it bugging out on me.

    I get:
    MyAsset (some sort of empty asset/object/thing)
    MyAsset (my texture)
    MyAsset (my actual scriptable object)​

    I need:
    MyAsset (my actual scriptable object)
    MyAsset (my texture)​
     
    Seneral likes this.
  4. MADmarine

    MADmarine

    Joined:
    Aug 31, 2010
    Posts:
    627
    I don't understand why you're opposed to using MonoBehaviour, it will solve your problem, and has very very little difference in terms of performance.
     
  5. Wahooney

    Wahooney

    Joined:
    Mar 8, 2010
    Posts:
    281
    I have my reasons which aren't really relevant here, since that's not my question.

    If someone can tell me for sure that it is impossible to add a texture to a ScriptableObject asset then I may consider the monobehaviour option.
     
  6. MADmarine

    MADmarine

    Joined:
    Aug 31, 2010
    Posts:
    627
    Ok, I'm probably not understanding something here, so I'll drop the Monobehaviour argument for the time being.

    Can you clarrify what you mean by attaching a texture to a ScriptableObject?

    You can have a Texture2D as an exposed member variable on a ScriptableObject

    You can have a ScriptableObject on a GameObject through some fairly hackish workarounds, but you cannot ever have a texture by itself in the hierarchy. Your explanation confuses me because it seems to say that the texture is an entity by itself in the hierarchy view.

    If you're talking about making the ScriptableObject item in the Project view a parent in a similar way to a prefab or folder, then that is impossible (even for MonoBehaviour, or anything other than folders or prefabs for that matter), and getting as far as you did surprises me.
     
    Last edited: May 29, 2012
  7. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    953
    Are there any particular reasons as to why you want to include your textures and materials into ".asset" file? This kind of breaks the whole beauty of working with assets in Unity. Asset files are generally created by scripts for dynamically generated content.

    From the reference documentation:
    http://unity3d.com/support/documentation/ScriptReference/AssetDatabase.AddObjectToAsset.html

    That is good because you should not be using "AddObjectToAsset" with prefabs :) Apparently there are a number of bad side effects to this.
     
  8. beck

    beck

    Joined:
    Nov 23, 2010
    Posts:
    294
    I am running into a similar problem. I have content being generated by an editor script, and I would like to save this content on a ScriptableObject. Adding Texture, Material, Mesh, or ScriptableObject assets as a sub asset of a ScriptableObject results in an empty asset being created, with the original parent ScriptableObject as a child. As the OP stated, this is not expected behaviour! Is there any way around this?
     
  9. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    953
    I have reported the issue of the blank parent asset to Unity and they have accepted that it is a bug.

    Basically the main asset becomes "UnityEngine.GenericAsset" instead of the asset that was specified (which becomes a child). There is no workaround to this at the moment (or at least none that were suggested or that I can find). If you add a material then that will usually become the parent asset.

    If anybody does know of a workaround then it would be greatly appreciated here too!
     
  10. Stephan-B

    Stephan-B

    Joined:
    Feb 23, 2011
    Posts:
    2,269
    Was this bug ever fixed or a workaround found?
     
  11. ModStoryGames

    ModStoryGames

    Joined:
    Apr 27, 2012
    Posts:
    179
    Code (csharp):
    1.  
    2. myTexture.hideFlags = HideFlags.HideInHierarchy;
    3. AssetDatabase.AddObjectToAsset(myTexture, myAsset);
    4. AssetDatabase.Refresh();
    5.  
    This will add the object without messing up the asset in the Project View. Just tested to confirm, this works with Textures, as well as any other Object.
     
  12. Stephan-B

    Stephan-B

    Joined:
    Feb 23, 2011
    Posts:
    2,269
    Doesn't work for me. Have you tried this with myAsset being a ScriptableObject?

    What I am after is being able to create a ScriptableObject and then adding a few sub objects to it. Right now, when adding the sub object, it makes both the object being added and myAsset child of a new asset.

    Edit: If I remove the hide flag on the object being added, using AssetDatabase.SaveAssets(); crashes Unity.
     

    Attached Files:

    Last edited: Jan 30, 2013
  13. ModStoryGames

    ModStoryGames

    Joined:
    Apr 27, 2012
    Posts:
    179
    Yeah, I just tested it by creating a ScriptableObject called TextureContainer. I put a List<Texture2D> in it, and made a simple EditorWindow that allows you to add textures to the selected TextureContainer asset. It works perfectly. This is also the technique I use in my GUI Editor; I create a GUIAsset (ScriptableObject) asset, then when controls are added to it, I set their hide flags to HideInHierarchy, and the problem is solved.

    EDIT: Just saw your last edit. I've never encountered that problem before. Also, I'm using Unity 3.5.5f3. If you are using a newer version, things may have changed. I didn't do an extensive test, but when I did test my GUI Editor in 4.0 it appeared to work fine. Hmmm...
     
    Last edited: Jan 30, 2013
  14. Stephan-B

    Stephan-B

    Joined:
    Feb 23, 2011
    Posts:
    2,269
    I must be missing something...

    I create a ScriptableObject via menu and it appears in my project.

    Then in an editor script, I get a reference to the object being selected.
    Code (csharp):
    1.  
    2. Object selection = Selection.activeObject;
    3.  
    Later in this editor Script

    Code (csharp):
    1.  
    2. // Create some Test Object
    3. AnimationClip clip = new AnimationClip();
    4. clip.name = "Special Font";
    5.    
    6. AssetDatabase.AddObjectToAsset(clip, selection);
    7.  
    8. //AssetDatabase.SaveAssets(); // This crashes.
    9.  
    10.  
    If I save the project and then navigate back to this object, we get the results in the image below where it moved the Main Asset and made it a child along with the object to be added to a new generic object with the same name as the main asset.

    I am using 4.0.
     

    Attached Files:

    Last edited: Jan 30, 2013
  15. Stephan-B

    Stephan-B

    Joined:
    Feb 23, 2011
    Posts:
    2,269
    If I do the same operations but the Target object is a Material instead of a ScriptableObject, it works.
     

    Attached Files:

  16. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    I've developed a workaround for this issue:
    $sub-assets 1.png

    As you can see, I have a main scriptable that contains sub-scriptables, that when selected shows up in the inspector.

    While I did not manage to get rid of the "asset container" thingy (AFAICS it's not part of the serialized data, so most likely a dummy created by the editor: no way around it...), what I did was redirect the inspector from the container to the main asset.
    The idea is to mark the main scriptable with a [MainAsset] attribute, have a custom editor that picks it up, create the relevant editor, and redirect calls to it. It works even if the main asset has a custom editor.
    By default the main asset shows up as a child of the container as you guys noticed, but you can optionally hide it.

    I've attached a package with sample code, try it for yourself! Create an asset (it has 3 sub-assets by default):
    $sub-assets 2.png

    $sub-assets 3.png

    From the context menu, you can add more sub-assets, or hide the main asset:
    $sub-assets 4.png

    What I haven't figured out is a way to reorder items in the project view (ie in the asset file itself), which would be nicer. As you can see in the first screenshot the sub-assets are not sorted the same in the project view and in my own list.
     
    Last edited: Feb 11, 2014
    kookyoo likes this.
  17. Democide

    Democide

    Joined:
    Jan 29, 2013
    Posts:
    315
    Appreciated! However you didn't add the context menu things to your unityPackage.
     
  18. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    No no, it's there. You must be using Unity 5? UT changed how "no particular type" assets (such as the scriptable object container I mention above) are handled: before they were just untyped Objects, now they have exposed a new DefaultAsset type (and apparently more assets types are coming for 5.x, yay :).

    So the fix is simple, just change DefaultAssetEditor with this: [CustomEditor(typeof(DefaultAsset))] (instead of [CustomEditor(typeof(Object))])

    I've also attached the updated package.
     

    Attached Files:

    rakkarage likes this.
  19. Democide

    Democide

    Joined:
    Jan 29, 2013
    Posts:
    315
    Hey, actually no. I am using 4.6 - but for some reason that thing didn't show up. I've even searched the source files for some MenuItem thing.
     
  20. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    Well there are MenuItems :) ! See TestMainAsset.cs:
    const string kContext = "CONTEXT/TestMainAsset/";

    [MenuItem(kContext + "Add Sub-Asset")]

    Did you maybe rename the file but not this string? No compile errors?
     
  21. Democide

    Democide

    Joined:
    Jan 29, 2013
    Posts:
    315
    Hm. No clue. I'll check it out later.
     
  22. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    This work around seems promising. Thank you for sharing it.

    I'm running Unity 5.3.1p2, and when the root "Main Asset" object is selected in the Project panel, the Inspector is empty. It does not mirror the Inspector when the ScriptableObject "Main Asset" is selected.

    After adding Debug.Log() calls in each of the methods in DefaultAssetEditor.cs, it became clear that the methods were not being called. It seems as though the CustomEditor attribute is failing or the root object isn't a DefaultAsset or a UnityEngine.Object.

    I realize this thread is a year old, but if you have any suggestions, I'd certain appreciate hearing them.

    Thanks!
     
  23. benblo

    benblo

    Joined:
    Aug 14, 2007
    Posts:
    476
    I'm not on 5.3 yet so I don't know, but I saw this in the 5.3.3p1 release notes:
    • (770926) - Scripting: Fixed issues with Scriptable objects added as sub assets with AssetDatabase.AddObjectToAsset.
    Any chance this could be related?
     
  24. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    Ah. Thanks for the info. I'll have to check that out once we upgrade the project.
     
  25. IgorAherne

    IgorAherne

    Joined:
    May 15, 2013
    Posts:
    393
    Strangely, I just experienced similar issue in unity 2017.1
    However, mine was occurring when the second argument of AddObjectToAsset was a string - a path relative to Assets folder.

    Once I've pluged-in the main asset as an object (instead of the path), the AssetDatabase.SaveAssets() didn't complain