Animation/Material/Mesh Delinking

I’d really like to know what the following enums do?

I had a question about the following enums which are not documented:

ReplacePrefabOptions.Default

ReplacePrefabOptions.ConnectToPrefab

ReplacePrefabOptions.ReplaceNameBased

ReplacePrefabOptions.UseLastUploadedPrefabRoot

I’m trying to add a particle system to a prefab, but when I reopen the project the references to the animation system and materials are blank.

I’m guessing one of these options will copy the referenced items.

According to this doc:

"ReplacePrefab

Replaces the targetPrefab with a copy of the game object hierarchy go."

If that’s English, doesn’t that mean the hierarchy should be copied?

Here is a video of my problem:
http://screencast.com/t/qEvucrRlKbz

Isn’t the hierarchy supposed to be copied?

Hmm, your stuff looks fine on a first look.
I’m succesfully using ReplacePrefab(), but I don’t specify any options. just an old GameObject and a new one.

You’re not doing anything funky in terms of using svn for versioning or something right?

could you paste the copmlete code that creates this prefab?

Bye, Lucas

I’ll have to create a test project.

The particle emitter, renderer, and animator were created from an asset bundle.

The game object was then added to the prefab.

Before exiting the links are correct.

On reload the links are missing.

I only saw one missing link, which was the material.
(texture is not a link, it’s only displayed in the inspector as a courtesy)

If they come from an assetbundle, that explains things. I don’t think you can do that. It apparently works for gameobjects and components, but a material isn’t stored in the actual renderer component. only a reference to it is stored. The material it references lives in the assetbundle, so when you restart unity, unity cannot find the material (as the assetbundle is no longer loaded).

assetbundles encourage you to use a workflow like this:

  • put all your stuff in the project folder
  • make something cool
  • split up the different assets into assetbundles, and use those assetbundles at runtime.

you can also use the assetbundles at editortime, but not as a means for general datastorage, that other assets can then again reference into.

You’ll probably need to explain a bit more about your setup (where does this assetbundle come from?) in order to get decent advice on what would be the best setup for the problem you’re trying to solve.

Bye, Lucas

Okay that does explain the issue.

The animation system was missing from the ParticleAnimator.

Since we cannot edit specific EllipsoidParticleEmitter and MeshParticleEmitter properties in script, instead we created a set of asset bundles that contain common settings.

We are attempting to reuse the assetbundles to create prefabs and new assetbundles and are running into this issue.

Essentially recycling asset bundles. Using asset bundles to create more asset bundles.

you can’t do that.

you can create different prefabs from the prefabs you stuffed into your assetbundle. you can’t do it from your assetbundle directly. Assetbundles are only a method to deliver assets, and cannot be used as asset containers that you can reference into.

I believe not having ElipsoidParticleEmitter, and its mesh equivalent are oversights in the api.

what you can do is create some prefabs with common settings for these components, and create new prefabs from those in your editor script.

Bye, Lucas

It’s not like there is a WWW.prefab property.

I think the concept of an asset bundle is using it like a WWW accessible container.

We need the asset bundles capable of being recycled.

Recycle - create an asset bundle and then load an asset bundle (which makes a gameObject) and create another asset bundle (from the gameObject)

This is essentially going to screw up our design. We need to rethink our design.

I think this is just a bug that slipped through the cracks.

With a proper design, the way I envisioned asset bundles as working is.

  1. A prefab is created,

  2. An initial asset bundle is created from the prefab.

  3. The asset bundle is uploaded to a web accessible place.

  4. An entry is added to a database that describes the asset bundle and what it contains.

  5. A content reviewer downloads the asset bundle, and makes some minor edits, creates a new prefab, and packages a new asset bundle.

  6. The new asset bundle is uploaded to a web accessible place.

  7. Another database entry is created that describes the asset bundle and changes.

  8. Repeat.

What did I plan on using Asset Bundles for?

  • Developers use asset bundles to create common assets for UnityEngine objects that can only edited in the Unity editor and can’t be scripted

  • Content developers and modders with a Unity license could take existing asset bundles and customize them and recreate new asset bundles

  • End users download units, buildings, and scenery as asset bundles

The lack of being able to create an asset bundle from an existing asset bundle is an unexpected limitation.

It would be useful to know what UnityEngine objects can be safely rebuilt from asset bundles and which can’t.

CAN:
*EllipsoidParticleEmitter

CAN’T:
*ParticleAnimator - missing animation system
*ParticleRenderer - missing material reference

You can create new stuff based on stuff assets in other assetbundles, as long as you recreate the assets from the assetbundle and store them somewhere they can be referenced from (read your assetdatabase).

all your gameobjects and components work. anything they reference within the assetbundle doesn’t work. It’s nothing special with gameobjects and components, except that you’re actively making a copy of them when you say ReplacePrefab(). It can work with materials just the same, you would just have to make a copy of those too.
(use AssetDatabase.CreateAsset() IIRC to create a new asset on disk from your material) then have your Renderer component reference this new material that is no longer stored inside the assetbundle.

Bye, Lucas

We may have a work around. When we build asset bundles, we are uploading the asset bundles and the prefab that was used to create the asset bundle.

When the editor downloads the asset bundle, it also downloads the prefab.

In this way, the references are still valid in the prefab.

A new asset bundle can be created from the prefab.

And the changes can be saved.

We have a web player that tracks changes to the asset bundles and saves the deltas to a database.

Our editor script picks up those changes, to rebuild prefabs and asset bundles.

We would love to investigate this further. The best way for us to do this is for you to submit a bug using the Bug Reporter (Help->Report a Bug). Attach a project folder and any other assets or asset bundles required along with a complete description of the problem and specific steps to reproduce. We’ll look into it and if we need any further info we’ll contact you through our bug tracking system.

You’ll like our example project then ;p

We have a Silverlight application which talks to the Unity plugin. The silverlight application provides fancier UI controls which pass the input into the Unity web plugin. We can also use the Silverlight application to load local texture files from disk into the Unity web player.

The Silverlight application talks to a database and tracks changes to game objects. Changes can be exported back to Unity with a serialized file. We have a Unity editor script that reads the serialized file that can load the asset bundles, apply modifications, and recreate new asset bundles.

We are in the process of making further modifications so the Silverlight app also uploads prefabs paired with the asset bundles.

You probably only need to see the last piece. It repeats what you see in the screencast in one of the first posts in this thread. It loads a serialized file, applies the changes to the downloaded asset bundle and creates a new asset bundle. When you restart Unity you’ll be able to see the missing references.

The plan is to create a test project for you today. But it might take until tomorrow.

I have a related issue. I’ve recorded a video of me creating a couple prefabs that I want to use in a separate project.

What is the proper way to do what I’m doing?

In this video I attempt to create two prefabs that are copied to a new project and find the material references are missing. http://screencast.com/t/GMDYJxJT

In this video I attempt to create a prefab and then export the prefab as a Unity package. When the package is imported, I find that the Mesh and Material references are missing. http://screencast.com/t/D5H2GNQsk

I know of two other ways to move files.

  1. Build an asset bundle from the prefab.

  2. Use that editor script that opens a scene in additive mode and remove the unwanted elements. Does that script work if you open another project’s scene?

One other idea is to create a script with public properties that reference the two materials and the mesh. Apply the script to the PineTree1 in the scene, and populate the references. Then create a prefab with the attached script. When exporting a package it should detect the materials and mesh are linked…???

And if I manually select the dependencies (mesh, and materials) all the references could be exported as a package and imported into a new project. http://screencast.com/t/WIpWtNijWE

Notice a couple UI caveats in the videos above.

Notice: I had renamed my gameObject and when I disabled the gameObject, the name reverted in the scene view. And the inspector showed the correct gameObject name.

Notice: When I selected the assets from the project view by control clicking, the export package dialog showed the assets in a hierarchy form, like it knew what it was supposed to export. I would have expected the same options to appear originally when selecting a prefab to export as a package.

Notice: The UI does not permit materials to be added to a prefab. http://screencast.com/t/5yWdIJGKy

I ran a test and when I select just the PineTree1 prefab and export the prefab to an asset bundle (Assets->Build Asset Bundle From Selection - Track dependencies), the expected game objects are loaded after downloading.

The difference with export package earlier is with the prefab I needed to select all the dependencies before exporting. With “Build Asset Bundle From Selection - Track dependencies”, I just needed to select the prefab.

Here is the logic that I used to download and load the AssetBundle.

using UnityEngine;

public class AssetBundleDownloader : MonoBehaviour
{
    WWW m_www = null;
    string m_assetBundleURL = @"http://tagenigma.com/qa/Unity3d/SceneryAssetBuilder/pinetree4.unity3d";

    public Object[] m_assetBundleObjects = null;

    void OnGUI()
    {
        GUI.Label(new Rect(0, 0, 150, 20), "Asset Download URL:");
        m_assetBundleURL =
            GUI.TextArea(new Rect(155, 0, 400, 20), m_assetBundleURL);

        if (null == m_www)
        {
            if (GUI.Button(new Rect(0, 25, 100, 20), "Download"))
            {
                m_www =
                    new WWW(m_assetBundleURL);
            }
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (null != m_www 
            m_www.isDone)
        {
            m_assetBundleObjects =
                m_www.assetBundle.LoadAll();
            m_www = null;
        }
    }
}

140104--5118--$assetbundlepreview_986.jpg

I’ll have to do more checking and see what happens when I take the UnityEngine.Object[ ] array and send it to ReplacePrefab.

From what I know now, I don’t see how I’ll be able to add the material to a new prefab because it can’t be assigned to the prefab. http://screencast.com/t/5yWdIJGKy

Instead I can try to instantiate the UnityEngine.Object[ ] array that is returned when loading the AssetBundle.

    // Update is called once per frame
    void Update()
    {
        if (null != m_www 
            m_www.isDone)
        {
            m_assetBundleObjects =
                m_www.assetBundle.LoadAll();

            foreach (Object obj in m_assetBundleObjects)
            {
                Object.Instantiate(obj);
            }

            m_www = null;
        }
    }

Oddly after running this, I get a lot of clones. I’m getting duplicate game objects for some reason. I understand that I get both my pine tree prefab, and the prefab from the original terrain asset. Where did the duplicates come from. Looking at the asset bundle contents and the code snippet above, I’m just instantiating each of the 9 objects. Where would the duplicates come from?

The duplicates are exact duplicates/copies of the same type.

I’ll attach the AssetBundleTester which is a project that downloads and instantiates the asset bundle Objects.

Update: When I instantiate the AssetBundle.MainAsset I get the one PineTree1 and no duplicates as expected.

When you download the asset bundle and click the main asset button you get the 1 pine tree as expected.

When you download the asset bundle and click the all asset bundle creates the duplicates.

Update: Added web player test link: Unity Web Player - AssetBundleTester

Update: It seems that you only ever want to instantiate the main asset because you can’t destroy most of the other asset objects once they’ve been created because Object.DestroyImmediate can’t figure out the dependencies.

140105--5119--$assetbundlepreview2_632.jpg
140919–5151–$assetbundletester3_981.zip (1.09 MB)
140105--5129--$assetbundlepreview4_484.jpg

If I inspect the downloaded asset bundle, it looks like the system is designed so that I should instantiate the main asset on the asset bundle.

I made a slight change to expose the downloaded AssetBundle to the inspector.

using UnityEngine;

public class AssetBundleDownloader : MonoBehaviour
{
    WWW m_www = null;
    string m_assetBundleURL = @"http://tagenigma.com/qa/Unity3d/SceneryAssetBuilder/pinetree4.unity3d";

    public AssetBundle m_assetBundle = null;

    public Object[] m_assetBundleObjects = null;

    void OnGUI()
    {
        GUI.Label(new Rect(0, 0, 150, 20), "Asset Download URL:");
        m_assetBundleURL =
            GUI.TextArea(new Rect(155, 0, 400, 20), m_assetBundleURL);

        if (null == m_www)
        {
            if (GUI.Button(new Rect(0, 25, 100, 20), "Download"))
            {
                m_www =
                    new WWW(m_assetBundleURL);
            }
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (null != m_www 
            m_www.isDone)
        {
            m_assetBundle =
                m_www.assetBundle;

            m_assetBundleObjects =
                m_www.assetBundle.LoadAll();

            foreach (Object obj in m_assetBundleObjects)
            {
                Object.Instantiate(obj);
            }

            m_www = null;
        }
    }
}

Here’s another question. Why can’t I save the scene when the editor is paused?

I tried Save Scene and Save Scene As, while in pause mode and nothing happens???

The next step is to move this logic into an editor script. And then we test creating an asset bundle from the downloaded asset main asset.