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

SimpleOBJ - Runtime importer for OBJ models

Discussion in 'Assets and Asset Store' started by Orbcreation, Nov 25, 2014.

  1. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Hi everyone,

    For my own project I will allow end users to upload their own 3D models. For this I needed a simple importer for OBJ files (Also for DAE but that is a different asset store package).

    OBJ is an open file format for 3D models, introduced by Wavefront. It is supported by most 3D modeling tools.

    SimpleLOD imports vertices, normals, 1 uv map and triangles. (polygons are
    automatically converted to triangles). It supports multiple meshes and sub meshes.

    This is a runtime importer and there is no Editor interface, since the Unity Editor already imports OBJ files by default.

    To import a model at runtime, you simply
    - download an OBJ file into a string,
    - pass the string to the import function
    - and receive a GameObject in return.

    Like so:
    myGameObject = ObjImporter.Import(objString);

    All source code is included and written in C#. There are no DLL's or hidden stuff.

    The web player demo can be found here
    The documentation can be found here
    The asset store package can be found here

    Notes: Does not support skinned meshes

     
    Last edited: Dec 11, 2014
  2. petrucio

    petrucio

    Joined:
    Aug 30, 2011
    Posts:
    126
  3. stevenapolo7

    stevenapolo7

    Joined:
    Aug 15, 2012
    Posts:
    24
    Hi, can i load and obj from my hard disk? i mean not from the internet? Thanks
     
  4. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    For the demo enclosed in the package: Yes, your url would then become:
    file:///mylocalpath/mylocalfile.obj (note the 3 slashes after file: )

    But this will not work with the webdemo, since the Unity Webplayer has of course no access to local files. If you cant upload it to some server somewhere, you can also email it to me: info (at) orbcreation (dot) com And I will upload it for you or send you the screenshots of the results.
     
  5. stevenapolo7

    stevenapolo7

    Joined:
    Aug 15, 2012
    Posts:
    24
    Thank you very much! :)
     
  6. JesperL

    JesperL

    Joined:
    Oct 3, 2014
    Posts:
    15
    Hello! I'm working on a project in which I need to import very large, detailed models during runtime. I was wondering if there is any upper limit on file size or polygon count in this importer? :) The same question goes for your DAE importer, I have not yet decided on what file format to use in my project. Thanks in advance!
     
    yuanjianzhong likes this.
  7. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    I would use OBJ if you don't need any special Collada features that are not available in OBJ.
    Collada has so much overhead. It has bigger files and it also takes longer to import them.

    Unity has a limit of 64K vertices for all models. This also applies to the SimpleOBJ and SimpleCollada packages. But I could make a new version, that would automatically split large meshes in chunks of 64K and create child gameobjects for them.

    The end resut may have slightly more vertices than the original, because when mesh part A and mesh part B have triangles that use the same vertices, those vertices will have to be copied.

    If you'd combine this with SimpleLOD, you could simplify those meshes at runtime.
     
  8. JesperL

    JesperL

    Joined:
    Oct 3, 2014
    Posts:
    15
    I see, that 64k limit is hardcoded in Unity. Actually, a version of your importer that automatically splits large meshes into child gameobjects would be really awesome, it would solve my problem. I would definitely purchase such a version!
     
    boxeldev likes this.
  9. Fargrey

    Fargrey

    Joined:
    Mar 30, 2013
    Posts:
    3
    Hello does it work on Android?
     
  10. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    @Fargrey, I never tested that, but don't see why it shouldn't. I dont have any android devices here to test it on, else I would have done so for you. But just in case you do have problems I'll borrow someone's phone and we'll find a way to solve them.
     
  11. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Version 1.1 is now available in the assetstore
    It has some major improvements:
    - Import can now run in a background thread (example provided)
    - Meshes with more than 64K vertices (Unity limit) can be imported. The mesh is automatically split into 2 or more parts.
    - Material .MTL specifications can be imported along with the .OBJ file (only basic material properties like color, transparency and specularity)
    - Textures can be automatically applied

    Examples have been added of how to download the .OBJ file and automatically download the .MLT file and textures.
    The online demo has been updated as well.

    Screenshot1.png
     
  12. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    I've put a new demo online that allows you to drag & drop your own OBJ model directly into Unity at runtime and see how SimpleOBJ imports it.
    The drag and drop part is handled by my other Asset Store package 'Drop on Unity".
    http://orbcreation.com/SimpleObjDrop/Demo.html
     
  13. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Version 1.2 is now available in the assetstore
    It has better support for large meshes with more than Unity's limit of 64K vertices.
    The original structure is better preserved and you can optionally add a gameObject for each group that is defined in the OBJ file
     
  14. alphakanal

    alphakanal

    Joined:
    Jan 21, 2013
    Posts:
    52
    Hi,

    cool asset!

    By testing the drag & drop demo:
    Drag the obj file only works fine.But testing the obj ( 2.9MB ) + mat + textures ( tga-files ) - an message pops up that says:

    An exception has occured, but exception handling has been disabled in this build. If you are the developer of this content, enable exceptions in your project's WebGL player settings to be able to catch the exception or see the stack trace.


    I'm whether the developer of this scene or a premium coder ;) just doing simple codings...what's this message about?

    And will it support bump-maps in the near future ?
     
    Last edited: Mar 14, 2015
  15. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    The error is due to the current limitations of games published on WebGL (or at least it was when this demo was build with the beta version of Unity5) it entails that when you upload data to the WebGL game, at some point it runs out of memory. I test for the max size per file, but the demo does not test the size of all files together.

    The bumpmaps are not implemented in the demo. It shouldn't be hard to do this yourself, since importing textures and assigning them to materials is not something that is OBJ format specific. When you want you can mail me your model + material and texture + bumpmap files and I will test for you how it imports. info (at) orbcreation (dot) com
     
  16. Eric_K

    Eric_K

    Joined:
    Mar 23, 2015
    Posts:
    1
    Hello,

    Very cool asset, exactly what we need.
    We have object with over 60 mio vertices (molecule), so I have a few questions:
    - Would Simple Obj support such a big amount?
    - How long do you think it will need to process it?
    - Can it create object instances? e.g our model is composed of spheres and cylinders -> instead of creating millions of spheres, just create one + coordinates

    Thanks!
    Eric
     
  17. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Uhm, to be honest, I never tried to import 60 million vertices before. So I have no idea how long this would take.
    It should work though. Provided you have enough memory.

    If I were you I'd import the positions and rotations with SimpleJson and write a small script to create the spheres and cylinders at runtime. But if all you have is the big OBJ file that holds both positions/rotations and the vertices/triangles, you could edit the script to ignore the vertices and triangles and just instantiate default spheres and cylinders at the transform locations.
     
  18. ejml1603

    ejml1603

    Joined:
    Apr 6, 2015
    Posts:
    1
    Hi - I want to be able to watch the demo video before I buy it but my unity web player is stuffing up and no matter how many times I reinstall it or try to fix it, it just won't play nice! Any chance you could put the vid up on youtube or something? Cheers
     
  19. aperez

    aperez

    Joined:
    May 13, 2015
    Posts:
    1
    Hello

    I have been working some time with this library on Windows and all worked fine. But now I need to develop an application for Linux Standalone and I have found that it doesn't work as it should do. For example objects have wrong scale values, wrong vertex positions and other errors that I couldn't fix.
    Also I have checked the file encoding to match with the reader encoding but still not working.

    Has someone any idea about that?
     
  20. S_P_S

    S_P_S

    Joined:
    Feb 25, 2015
    Posts:
    91
    How do I load local files?

    I tried:

    file:///H:/models/myModel.obj

    But it's not working.

    Regards
     
  21. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    @aperez ,
    Have you tried to import the same file that fails on Linux on Windows yet? And if it fails there as well, could you mail it to me?
    @_Beyond_
    What you can do is add a TextAsset property to your class like this:
    Code (CSharp):
    1. public TextAsset myXmlFile;
    2.  
    3. void Start() {
    4.    Hashtable xml = SimpleXmlImporter.Import(myXmlFile.text);
    5. }
    6.  
     
  22. S_P_S

    S_P_S

    Joined:
    Feb 25, 2015
    Posts:
    91
    xml file? I want to load a local .obj file.
     
  23. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Oh, my bad. Copy pasted this from an email I send to somone who asked the same thing for SimpleXML

    Code (CSharp):
    1. public TextAsset myObjFile;
    2. void Start() {
    3.    GameObject newObject = ObjImporter.Import(myObjFile.text);
    4. }
     
  24. S_P_S

    S_P_S

    Joined:
    Feb 25, 2015
    Posts:
    91
    Okay, no problem, thanks, but why do I have to deal with TextAssets?
    Am I not able to simply pass my filepath (H:/models/myModel.obj) to the model?
     
  25. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,350
    Also looking for how to load local file easily..

    I did:
    - Rename test.obj file to test.obj.txt
    - Assigned that to myObjFile
    - Run

    getting many errors (and debug.log hangs unity if tried with bigger models)
    Bad vertex index:-530 at:0
    Bad vertex index:-529 at:1
    ......
    ObjImporter:Log(String) (at Assets/SimpleObj/ObjImporter.cs:759)


    Any .obj from 3ds max doesnt seem to work(?) attached one sample file.
     

    Attached Files:

    Last edited: Aug 14, 2015
  26. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    @_Beyond_ You can't pass a file path because that would not work in all build targets. If you want to load local text files you can use the WWW class or a TextAsset. But this all has very little to do with SimpleOBJ and is Unity behaviour, all the importer needs is a string as input.
     
  27. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    @mgear Your teapot works fine (see screenshot)
    I think something is wrong with the way you obtain the contents of your obj file. Can you post your code?
     

    Attached Files:

  28. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,350
    Aha, it worked if export from Max with "Blender" as preset, previously had export .OBJ with with "Maya" preset (attached the .obj that gives errors)

    My code it just this (where objFile is text asset and myfile.obj.txt is assigned to it)
    GameObject importedObject = ObjImporter.Import (objFile.text);
     

    Attached Files:

  29. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Ah ok. Apparently 3dsmax exports with relative vertex indices (negative numbers) with the Maya preset.
    (see https://en.wikipedia.org/wiki/Wavefront_.obj_file#Relative_and_absolute_indices)
    I have made a small update to make sure SimpleOBJ supports both relative and absolute indices. I will upload it to the AssetStore for review tomorrow, but the reviewing itself may take a week. If you are in a hurry, send me an email and I will send you the updated file.
     
    mgear likes this.
  30. the_greenlig

    the_greenlig

    Joined:
    Feb 5, 2013
    Posts:
    29
    Hey there, really liking this asset. I've been using it for a month now and it works a charm.

    Quick question, is there a way to import sub-objects with correct pivot points? Currently it places the pivot at (0,0,0).

    So, this model with pivots at either end of the boxes - http://puu.sh/jUCqO/2b33fdd6ae.png - imports as this - http://puu.sh/jUCKQ/51ae79fbf4.png. In that second image, both the pivots are at the base of the first object.

    Is there a way around this? Am I missing something in the importer? Basically I just want to import the objects pivot when loading. This will help me no end :)

    Cheers,
    Greenlig
     
    Last edited: Aug 31, 2015
  31. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Can you mail me that model? So I can see how the pivots are defined in the OBJ file?
     
  32. the_greenlig

    the_greenlig

    Joined:
    Feb 5, 2013
    Posts:
    29
    Thanks for clearing that all up Orb, really liking the asset!
     
    Orbcreation likes this.
  33. BorisRA

    BorisRA

    Joined:
    Oct 13, 2015
    Posts:
    4
    Tell me I understood correctly?
    Just need this code to import:

    using UnityEngine;
    using System.Collections;

    public class ioobj : MonoBehaviour {
    public string url = "File:///C:/teapot_maya.obj.txt";
    public bool press =true;
    public GameObject importedObject;

    void Start ()
    {
    importedObject = ObjImporter.Import(url);
    press = false;
    }

    void Update ()
    {
    }
    }
    But it doesn't work
    there is not any errors
     
    Last edited: Oct 13, 2015
  34. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    That's because you tell the ObjImporter to interpret the string "File:///C:/teapot_maya.obj.txt" as if it were the contents of an OBJ file. You need to download the file first and then pass it's contents to the importer.

    Like so:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ioobj : MonoBehaviour {
    5.     public string url = "File:///C:/teapot_maya.obj.txt";
    6.     public bool press =true;
    7.     public GameObject importedObject;
    8.  
    9.     void Start ()
    10.     {
    11.         StartCoroutine(DownloadAndImport());
    12.         press = false;
    13.     }
    14.  
    15.     private IEnumerator DownloadAndImport() {
    16.         WWW www = new WWW(url);
    17.         yield return www;
    18.         importedObject = ObjImporter.Import(www.text);
    19.     }
    20. }
    In the SimpleObjDemo.cs code file is a more enhanced example of downloading and then importing a file.
     
  35. BorisRA

    BorisRA

    Joined:
    Oct 13, 2015
    Posts:
    4
    Thank you so much!!!!
    You saved me!
    And thank you for the quick answer!
     
  36. asmboom

    asmboom

    Joined:
    May 22, 2013
    Posts:
    3
    Hi! You are testing on webgl? It is working correctly?
     
    melss likes this.
  37. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    There is no reason why it shouldn't work on WebGL, because it doesn't call any functions that are unsupported. I believe I even have a demo online that runs on WebGL. So no worries.
     
  38. BorisRA

    BorisRA

    Joined:
    Oct 13, 2015
    Posts:
    4
    Please tell me how can I auto-calculate vertex normals, if my file shows only the vertices and the surface and the imported object is divided into multiple objects.
    Is this possible?
     
  39. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Sure
    Code (CSharp):
    1. MeshFilter[] meshFilters myGameObject.GetComponentsInChildren<MeshFilter>();
    2. for(int i=0;i<meshFilters.Lemgth;i++) {
    3.     Mesh mesh = meshFilters[i].sharedMesh;
    4.     mesh.RecaculateNormals();
    5. }
     
  40. BorisRA

    BorisRA

    Joined:
    Oct 13, 2015
    Posts:
    4
    Should be like this:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ioobj : MonoBehaviour {
    5.     public string url = "File:///C:/TEST2.obj";
    6.     public string mtll = "File:///C:/2cil.mtl";
    7.  
    8.     GameObject importedObject;
    9.  
    10.  
    11.     void Start () {
    12.  
    13.  
    14.         StartCoroutine(DownloadAndImport());
    15.  
    16.         MeshFilter[] meshFilters = importedObject.GetComponentsInChildren<MeshFilter>();
    17.         for(int i=0;i<meshFilters.Length;i++)
    18.         {
    19.             Mesh mesh = meshFilters[i].sharedMesh;
    20.             mesh.RecalculateNormals();
    21.         }
    22.  
    23.  
    24.  
    25.     }
    26.     private IEnumerator DownloadAndImport() {
    27.         WWW www = new WWW (url);
    28.         WWW mtl = new WWW (mtll);
    29.         yield return www;
    30.         importedObject = ObjImporter.Import (www.text, Quaternion.Euler (270, 0, 0), new Vector3 (1, 1, 1), Vector3.zero, mtl.text, null, true,false,false);
    31.     }
    32.      
    33.         // Update is called once per frame
    34.     void Update () {
    35.  
    36.  
    37.     }
    38. }
    excuse me formy stupid questions!!!
     
  41. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Not a stupid question at all. This is difficult stuff.

    In your script you start the coroutine to download the file, bu do not wait for it to complete. So when you recalculate normals the importedObject is not there yet.

    Also it would be better to simply use the default name for the .mtl file instead of specifying it.
    If the .mtl file references any textures, it would be nice to download them as well. I changed your script using some of the code from SimpleObjDemo.cs. I didn't test it but I think it should be ok.
    What it does is this:

    - Start the coroutine that downloads and imports everything.
    - Start a coroutine that downloads the .obj file and wait for the result
    - Start a coroutine that downloads the .mtl file and wait for the result
    - Imports the .mtl file
    - Checks if there are any tetures needed
    - If so, it downloads those textures and waits for the result
    - Imports the .obj file
    - Recalculates the normals

    But....... When a model does not have any normals, the importer already automatically calculates them. Are you sure that last step is needed?

    Code (CSharp):
    1.  
    2.  
    3.     using UnityEngine;
    4.     using System.Collections;
    5.    
    6.     public class ioobj : MonoBehaviour {
    7.         public string url = "File:///C:/TEST2.obj";
    8.         // Better rename your materials file to TEST2.mtl
    9.         // public string mtll = "File:///C:/2cil.mtl";
    10.    
    11.         GameObject importedObject;
    12.  
    13.    
    14.         void Start () {
    15.             StartCoroutine(DownloadAndImportFile(url, Quaternion.Euler (270, 0, 0), new Vector3 (1, 1, 1), Vector3.zero, bool false, false, false));
    16.         }
    17.  
    18.        
    19.         private IEnumerator DownloadAndImportFile(string url, Quaternion rotate, Vector3 scale, Vector3 translate, bool gameObjectPerGrp, bool subMeshPerGrp, bool usesRightHanded) {
    20.             string objString = null;
    21.             string mtlString = null;
    22.             Hashtable textures = null;
    23.  
    24.             yield return StartCoroutine(DownloadFile(url, retval => objString = retval));
    25.             yield return StartCoroutine(DownloadFile(url.Substring(0,url.Length-4)+".mtl", retval => mtlString = retval));
    26.             if(mtlString!=null && mtlString.Length>0) {
    27.                 string path = url;
    28.                 int lastSlash = path.LastIndexOf('/',path.Length-1);
    29.                 if(lastSlash>=0) path = path.Substring(0,lastSlash+1);
    30.                 Hashtable[] mtls = ObjImporter.ImportMaterialSpecs(mtlString);
    31.                 for(int i=0;i<mtls.Length;i++) {
    32.                     if(mtls[i].ContainsKey("mainTexName")) {
    33.                         Texture2D texture = null;
    34.                         string texUrl = path+mtls[i]["mainTexName"];
    35.                         yield return StartCoroutine(DownloadTexture(texUrl, retval => texture = retval));
    36.                         if(texture != null) {
    37.                             if(textures == null) textures = new Hashtable();
    38.                             textures[mtls[i]["mainTexName"]] = texture;
    39.                         }
    40.                     }
    41.                 }
    42.             }
    43.  
    44.             if(objString!=null && objString.Length>0) {
    45.                 yield return StartCoroutine(ObjImporter.ImportInBackground(objString, mtlString, textures, rotate, scale, translate, retval => importedObject = retval, gameObjectPerGrp, subMeshPerGrp, usesRightHanded));
    46.                 AddToLog("Done importing model");
    47.  
    48.                 MeshFilter[] meshFilters = importedObject.GetComponentsInChildren<MeshFilter>();
    49.                 for(int i=0;i<meshFilters.Length;i++)
    50.                 {
    51.                     Mesh mesh = meshFilters[i].sharedMesh;
    52.                     mesh.RecalculateNormals();
    53.                 }
    54.             }
    55.         }
    56.  
    57.         private IEnumerator DownloadFile(string url, System.Action<string> result) {
    58.             AddToLog("Downloading "+url);
    59.             WWW www = new WWW(url);
    60.             yield return www;
    61.             if(www.error!=null) {
    62.                 AddToLog(www.error);
    63.             } else {
    64.                 AddToLog("Downloaded "+www.bytesDownloaded+" bytes");
    65.             }
    66.             result(www.text);
    67.         }
    68.        
    69.         private IEnumerator DownloadTexture(string url, System.Action<Texture2D> result) {
    70.             AddToLog("Downloading "+url);
    71.             WWW www = new WWW(url);
    72.             yield return www;
    73.             if(www.error!=null) {
    74.                 AddToLog(www.error);
    75.             } else {
    76.                 AddToLog("Downloaded "+www.bytesDownloaded+" bytes");
    77.             }
    78.             result(www.texture);
    79.         }
    80.     }
    81.  
     
  42. inlee

    inlee

    Joined:
    Dec 15, 2015
    Posts:
    1
    Hello

    I got everything works on the "Web Player" and "Desktop applications"
    However, it does not import 3D obj file using "WebGL" player for unity...

    do I need to do something different for WebGL?
     
  43. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    @inlee WebGL and WebPlayer should have the same results. Remember that you can't import a local file from within the browser. If you download from a webserver, check the cross domain settings
     
  44. Uli_Okm

    Uli_Okm

    Joined:
    Jul 10, 2012
    Posts:
    95
    Hi, @Orbcreation, just one small question: the importer will correctly handle models made using polys and tris? And it will be able to triangulate possible ocassional pentas or there will be a hole in the 3d model?
    Thanks
     
  45. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Yes no worries. faces with more that 3 vertices will be triangulated
     
  46. benfattino

    benfattino

    Joined:
    Nov 26, 2010
    Posts:
    43
    Great plugin...
    I try to import very large mesh (more than 500.000 faces) and works. But i have question:
    Is it possibile group splitted mesh into parent with same name of the originale mesh?

    S.
     
  47. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Uhm, I thought that is exactly what it does. Can you send me a copy of your model, so I can see what you mean? richard@orbcreation.com
     
  48. world_naoki

    world_naoki

    Joined:
    Mar 24, 2016
    Posts:
    11
    Hello,
    I plan to buy this asset.

    I used other asset to import obj file(scanned by structure sensor) and Unity said 'Format Exception Unknown char :n'.

    I dont know what is this error.

    I want to know Simple OBJ can prevent from this error or not
     
  49. Orbcreation

    Orbcreation

    Joined:
    May 4, 2010
    Posts:
    231
    Hey world_naoki, I can't really base any sensible response on some non-descriptive error message given by another importer. But if you mail me your model, I will test it for you.
     
  50. world_naoki

    world_naoki

    Joined:
    Mar 24, 2016
    Posts:
    11
    Thank you for replying and your help.


    I will mail you with my model soon. my mail address contains the word 'naoki'.