Everyday 3D

Creative use of technology // A blog about 3D Flash and Actionscript by Bartek Drozdz

Loading 3d models at runtime in Unity3d

This post is an addition to the last series I wrote about dynamic content loading in Unity3D.

When building a dynamic application, every now and then you might need to load some 3d models at runtime. Either because there's a database with models you want to use or just because you want someone to update the models without rebuilding the project. I actually had this situation a few weeks ago. Surprisingly, this option does not come with Unity out of the box.

Asset bundles and resource folders

But first thing first. I said there's no ready-to-use way to load 3d models at runtime, but it's not 100% true. In fact, there are two options: asset bundles and resource folders. These methods are discussed in depth here.

They can both be useful in some cases, but they both have one fundamental drawback: in order to create them, someone needs to open the project in Unity, import the 3d models, create the bundles or resource folders and then export the whole thing again. To create an AssetBundle you need to run a script in the editor, while the Resource Folders... honestly, I failed to even make them work!

In brief, it's all too complicated for what I was looking for.

A straightforward solution

What I needed and wanted was easy and simple: to load a 3d object (geometry + some materials and textures) at runtime, using just a URL as parameter. The only solution seemed to write my own importer.

Basically, I had the choice between Collada and Wavefornt OBJ. I would choose OBJ any time of the day because it's a simple, concise plain-text format, while Collada is bloated and is XML-based.

It's not that I hate XML (although I'm not a big fan either) but in order to parse XML you need to include a pretty weighty DLL in your *.unity3d file, around 850Kb, which in this case (and in many others) defeats the purpose. Still, it's good to know that it possible, and there are situations when it's ok to use it. If you want to learn more about Unity3D and XML there's a awesome article on this topic by Paul Tondeur.

It turned out that while it's not rocket science to write an OBJ importer, it's not exactly banal either. I spent a few days coding it so I thought I'll share this with everyone - maybe someone will make good use of it.

Here's a package with the source code (v1.1), along with a simple scene demonstrating how it works. In fact it couldn't be simpler. All you have to do is to create an instance of the OBJ class and start a coroutine to load the contents, like this:

C#:
  1. string path = "http://www.everyday3d/unity3d/obj/monkey.obj";
  2. OBJ obj = new OBJ();
  3. StartCoroutine(obj.Load(path));

Supported features

  • Vertex, normals and UV data
  • Multiple objects per file
  • Vertex groups and multiple materials per object
  • MTL files, diffuse and specular materials
  • Basic textures

And it's all at a cost of ~12Kb extra added to your final file!

Testing and the universality of OBJ format

In the 3D world the OBJ format is nearly universal - I think that every 3D editor in existence is able to export to this format. This also means that Wavefront files come in many different flavors.

I tested the code against models created with Blender and against common sense assumptions on how an OBJ file can be constructed. If it doesn't work with files exported from your editor send me the OBJ file, and if possible I'll update the code. It's released under the MIT license so feel free to use it in your projects, commercial or not.

That's it! I hope you'll find it useful!

Categories: 3D, CSharp, Unity3d

comments RSS

22 Comments

  1. Nice- I’ve seen a few requests for something like this, though I haven’t needed it myself. I suggest you assign the category “Unity3d” to the post.. You also might want to create a page for it on the Unify Wiki, which can just link back to here if you prefer. (There’s already an OBJExporter script there.)

  2. Great idea! I’ve tried working with Asset Bundles, and although I got them to work, I found the process a bit clunky. And as you mentioned, you have to open up the Unity editor.

    I’ll be giving this a try in the future.

  3. Arnaud Fontaine

    Nice work ! I tried your demo scene and got an error parsing the remote obj (the Monkey.obj from your website). Is it related to indie vs pro version of Unity ?

  4. @Arnaud I’m double checking this right now. It should work both in Indie and in Pro. Can you paste the error message?

  5. @Matt Thanks, I forgot to add categories and tags :) I will post it on Unify as soon as I’m sure that it works on the free version as well.

  6. [...] in Unity3D??? Check this Quer carregar modelos 3d durante a execução no Unity??? Veja o link. Share and [...]

  7. This is very cool! I’ll be testing this this week as Asset Bundles seemed tougher than needed to implement.

  8. As always, excellent post here! I hope to get some spare time to actually try it out instead of just reading through it.

    We’re doing a broadcast on Wednesday about the impact of Unity Google Native Client. If you can join in please drop me an email at mani at diamondtearz.org

  9. Hello,
    Ia m trying your package and the main scene is not working. I have this error in the console :

    FormatException: Unknown char: .
    System.Double.Parse (System.String s, NumberStyles style, IFormatProvider provider)
    System.Single.Parse (System.String s)
    System.Convert.ToSingle (System.String value)
    OBJ.cf (System.String v) (at Assets\OBJ\src\OBJ.cs:115)
    OBJ.SetGeometryData (System.String data) (at Assets\OBJ\src\OBJ.cs:83)
    OBJ+c__CompilerGenerated0.MoveNext () (at Assets\OBJ\src\OBJ.cs:46)

  10. @krys64 Can you send me the OBJ file you are loading? (bartek at everyday3d com)

  11. I am using your package with your file : http://everyday3d.com/unity3d/obj/monkey.obj
    I have changed nothing. I see that :
    http://webcache.googleusercontent.com/search?q=cache:p3iAr1PRiqwJ:markmail.org/message/rgcv25vopmpvzbeq+FormatException:+Unknown+char:+.&cd=1&hl=fr&ct=clnk&gl=fr
    My computer is an european system

  12. @krys64 Thanks, that helps a lot! I’ll look into that as soon as I can.

  13. @kyrs64 I posted an updated version of the importer which contains a fix to this problem.

  14. Thank you, i’ll test end post a news on my site ;)

  15. [...] -Le site [...]

  16. Thanks you. i’ll test this

  17. krys64

    Hello, i am trying to convert your script for read a local .obj file.
    I have modified the OBJ.cs script and i have replaced “WWW” by “streamReader” but to the line 61 i can’t load the texture. What is the syntax please. THX :)

  18. krys64

    I am stupid, i reimport the package and i have change “http” by “fil”e and it’s work ! :)

  19. MonkeyNotLoading

    Hi, this is a great post, and will be very useful to me, but I can’t get it to work. I imported the package, and then changed the “Obj Import Demo” script to:

    using UnityEngine;
    using System.Collections;

    public class ObjImportDemo : MonoBehaviour {

    public string filename;

    void Start () {
    string path = “http://www.everyday3d.com/unity3d/obj/monkey.obj”;
    OBJ obj = new OBJ();
    StartCoroutine(obj.Load(path));

    }

    void Update () {
    }
    }

    When I run the scene, I get the following error:

    You are trying to load data from a www stream which had the following error when downloading.
    couldn’t connect to host
    UnityEngine.WWW:get_data()
    UnityEngine.WWW:get_data()
    c__CompilerGenerated0:MoveNext() (at Assets\OBJ\src\OBJ.cs:47)

    [..\..\Runtime\Export\WWW.cpp line 771]

  20. Epicyeti

    This is a great idea and something I’ve been looking for for a while. I am having some trouble getting it working though. It works great with the given .obj file and www location. But as soon as I use either a local file (file///:) or a test file I put on the web I get an error:

    “ArgumentNullException: Argument cannot be null.
    Parameter name: key

    System.Collections.Generic.Dictionary`2[System.String,UnityEngine.Material].get_Item (System.String ) [0x00000]
    GeometryBuffer.PopulateMeshes (UnityEngine.GameObject[] gs, System.Collections.Generic.Dictionary`2 mats) [0x00197] (at Assets\OBJ\src\GeometryBuffer.cs:145)
    OBJ.Build () (at Assets\OBJ\src\OBJ.cs:236)
    OBJ+c__CompilerGenerated0.MoveNext () (at Assets\OBJ\src\OBJ.cs:63)”

    this is cause by the line 145 in GeometryBuffer.cs

    I was wondering if there is a specific file structure the .obj and .mtl and texture files need to be in.

  21. Epicyeti

    The other problem I have is that it will work, but the object it creates is empty. I think the previous problem is because a *.mtl file was not available.

  22. Giancarlo

    Hi, well first my huge thank you as it solved quite a big issue I got with Unity! :)
    I was trying to use it and I had to convert my GoogleSkected OBJ files into Blender… and it worked quite well. But for a little more complex scene, I got this weird message:
    KeyNotFoundException: The given key was not present in the dictionary.
    System.Collections.Generic.Dictionary`2[System.String,UnityEngine.Material].get_Item (System.String ) [0x00000]

    which I don’t know what it depends for.

    Many many thanks!
    Giancarlo

Leave a comment



  • FITC10


  • FITC10


  • FITC10