Search Unity

ObjReader - load .obj files at runtime

Discussion in 'Assets and Asset Store' started by Eric5h5, May 7, 2013.

  1. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You need to use the gameObjects property of the ObjData class; see the docs for more details. Also you don't use Instantiate with objects created with ObjReader, since they're already instantiated (unless you're making more copies).

    --Eric
     
  2. Carpet_Head

    Carpet_Head

    Joined:
    Nov 27, 2014
    Posts:
    258
    Just curious: unity 2017.3 adds support for meshes bigger than 65k verts - has anyone tested if objreader pretty much supports this change immediately?
     
  3. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It doesn't, since it requires some minor code changes to support 32-bit mesh indices. However I did that some time ago and I've been waiting for 2017.3 to be done before releasing the changes. A high-poly sphere .obj file for example, check the number of verts:

    Screen Shot 2017-12-13 at 10.10.24 PM.png

    (The 2 batches is just because of that thing Unity does since 2017 or so where there's always a mystery quad somewhere using a batch; it's really just one object.) So, now you know why I wasn't planning on implementing mesh splitting...it didn't make a lot of sense spending time on that when 32-bit mesh indices are a much better solution: faster, easier to work with one object instead of many, and less hacky. I wanted to mention it earlier, but I believe people with access to alpha builds are not supposed to talk about those features. Since it's beta now, it's fine.

    --Eric
     
  4. Carpet_Head

    Carpet_Head

    Joined:
    Nov 27, 2014
    Posts:
    258
    I agree that 32-bit mesh indices is a great solution, but it has been a hell of along wait! Grateful that we will finally receive it though.

    We actually switched to a different plugin that supports mesh splitting (because we had some users importing some crazy big meshes) but it was a lot slower, even after some heavy modification. Hoping to be able to return to OBJReader in the near future for those sweet load times
     
  5. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Yep, it's ready to go as soon as 2017.3 is released (since they don't allow assets on the store that use beta functionality last I heard).

    --Eric
     
  6. Kubic75

    Kubic75

    Joined:
    Jan 2, 2017
    Posts:
    83
    I see your objreader also support normalmaps:

    Code (CSharp):
    1. if (lines[i].StartsWith ("map_bump")) || lines[i].StartsWith ("bump")) {
    2.         ConvertToNormalmap (diffuseTexture);
    3. }
    It seems the function simply converts to geyscale, but how can I convert this to a normalmap (in runtime) afterwards?
     
  7. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It doesn't convert to grayscale; you need to load an actual normalmap. See the "using normal maps" section in the docs.

    --Eric
     
  8. Kubic75

    Kubic75

    Joined:
    Jan 2, 2017
    Posts:
    83
    I see, but the (original colored) normalmap appears as greyscale in the editor, right?
     
  9. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    No, normalmaps look like this:

    images.jpeg

    You can use grayscale for bumpmaps, but bumpmaps are inferior to normalmaps and nobody has used them in many years. Unity doesn't have any bumpmap shaders.

    --Eric
     
  10. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Oh, and since Unity 2017.3 is officially released now:

    ObjReader 2.7

    Changes:
    • With Unity 2017.3, models with groups containing >65K vertices can be used, if the new use32BitIndices setting is on.
    • The maxPoints setting has been removed. Instead it's automatically internally set to ~65K if use32BitIndices is false, and ~4 billion if use32BitIndices is true.
    • Demo script files modified to remove warnings in later Unity 2017 versions.

    --Eric
     
  11. Kubic75

    Kubic75

    Joined:
    Jan 2, 2017
    Posts:
    83
    Hi Eric,

    sorry, I have to talk again about my shading-issue that I already mentioned above.
    Here´s a screenshot that clearly illustrates my problem:



    It´s the same box-primitive exported from 3dsmax and imported by your reader.
    The left ones faces are rendered wrong.

    I slightly changed the texture coordinates decimals (pink boxes) in texteditor and voilà, the faces render correct.
    I assume that the problem appears when texture coordinates are too close to others so that they are treated as one.

    In my opinion primitives exported from 3rd party packages like 3dsmax should render correct by default without the need to manually apply any uv-mapping. (So do other free packages on the store - please don´t mind about them - yours is 3 times faster.)

    Could you have a look at this - please?
     
  12. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    A cube needs 24 vertices for proper lighting; 8 can't work. Vertices will be split on UV seams, but that's the only splitting it does. Keep in mind that the more auto-stuff that ObjReader does, the slower it will go. It's fairly trivial to get models exported from 3D apps correctly (at least it is with Blender), so the tradeoff for ObjReader's speed is sometimes you might need to ensure that models are built appropriately.

    --Eric
     
  13. Kubic75

    Kubic75

    Joined:
    Jan 2, 2017
    Posts:
    83
    But the cube on the right has only 8 vertices and does work o_O
     
  14. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It does not. I guarantee 100% that in Unity it has 24 vertices. It's not possible for 8 to work (well, maybe with some kind of specialized shader, possibly, but not normally). It's required that the normals for each vertex to be unique to each face, meaning 6x4 vertices.

    --Eric
     
  15. tomas-dostal

    tomas-dostal

    Joined:
    Jul 13, 2015
    Posts:
    3
    Dear Eric,
    I have a problem with loading colors from mtl files. Could you please help me?
    Screen Shot 2018-01-12 at 18.11.18.png Screen Shot 2018-01-12 at 18.16.22.png

    The picture on the right shows how the model was generated. The other one shows how it looks, when imported using your code.
    Same problem here: on the right side is a model imported by unity, on the left side is one imported by your code.
    In both cases there is used ObjReader.use.ConvertFile (objFileName, false, standardMaterial, transparentMaterial);, no special settings. Screen Shot 2018-01-12 at 18.43.27.png Screen Shot 2018-01-12 at 18.39.20.png


    If ObjReader.use.ConvertFile (objFileName, true, standardMaterial, transparentMaterial);
    is used, the model is setted to 0% visibility.
    Screen Shot 2018-01-12 at 18.41.21.png


    What is wrong with it? What special options should I check? Could you please take a look at it? I really do not know what should I fix.
    OBJ file and MTL file are here:
    https://drive.google.com/file/d/0B-FBdI38RREQQlBwZW80cElKV1U/view?usp=sharing

    Thank you,
    Have a nice day,
    Tomas
     
  16. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Unfortunately MTL files don't seem to be used in a standard way. Yours is using "tr" for transparency, but apparently using tr=1 to mean opaque when it should be the other way around (that is, tr=0).

    --Eric
     
  17. KeithT

    KeithT

    Joined:
    Nov 23, 2011
    Posts:
    83
    Hi,

    I am trying load an obj into Unity 5.6.5 using ObjReader, but am getting different numbers of vertices compared to Maya and Meshlab. They both consistently report 27578, whereas ObjReader consistently creates a mesh with 31645. When Unity treats it like a mesh it has about 32055. (There are different versions of the file and Unity changes the number of vertices it creates between them).

    As Maya and Meshlab are from very different organisations I guess they using some "standard" way of interpreting the objs, which is different than ObjReader.

    Given the processing I need to do to the meshes I would like to get the vertex and index count to be the same everywhere. Do you know if this is possible and what ObjReader is doing differently?

    Thanks in advance for any insights.
     
  18. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Vertices are split on UV seams when importing with ObjReader (this is required). The Unity importer can also split based on angle, which is what I'd assume accounts for the difference compared to ObjReader. I think it would be quite difficult to get it to be the same everywhere.

    --Eric
     
  19. Carpet_Head

    Carpet_Head

    Joined:
    Nov 27, 2014
    Posts:
    258
  20. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Use the CombineMultipleGroups option.

    --Eric
     
  21. Carpet_Head

    Carpet_Head

    Joined:
    Nov 27, 2014
    Posts:
    258
    The problem is that this gives us just one single mesh right now, which goes too far in the other direction. Being able to break apart the mesh is really important, and works great for a decent subset of OBJ files
     
  22. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    In that case, Unity would do exactly the same thing if you use 32-bit vertex indices. If you're using 16-bit, then Unity is just breaking the mesh into arbitrary pieces, which ObjReader doesn't support. You could modify the .obj file so that the groups do what you want.

    --Eric
     
  23. Carpet_Head

    Carpet_Head

    Joined:
    Nov 27, 2014
    Posts:
    258
    I don't think that is the case. In the OBJ file, there are groups where the material flips back and forth between two materials. In Unity, objects that are the same group and material are part of the same mesh. In OBJReader, it creates a huge number of mesh that are in the same group and have the same material. It is certainly not arbitrary
     
  24. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    With ObjReader, any group is a separate mesh (unless CombineMultipleGroups is used). If there are a huge number of meshes, that means there are a huge number of groups in the .obj file. ObjReader has no ability to create separate meshes that are part of the same group. If I had to guess, perhaps Unity is combining groups based on some criteria, though I don't know what it would be.

    --Eric
     
  25. Carpet_Head

    Carpet_Head

    Joined:
    Nov 27, 2014
    Posts:
    258
    Did you check out the file? There are 168 groups defined in the file, with 129 of those having a unique name. The unity importer creates precisely 129 meshes, so it is indeed combining groups that have the same name, but that is not really arbitrary. This does not account for the thousands of meshes that ObjReader creates
     
  26. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I didn't check the file since I don't have access to it. However, groups are not just made from the group command, but also necessarily from material commands, so if there are lots of those, that could also result in lots of groups.

    --Eric
     
  27. Tenebris_Lab

    Tenebris_Lab

    Joined:
    May 23, 2017
    Posts:
    35
    Hello @Eric5h5 i have to load massive OBJ files. I'm talking 500 - 700 mb files. Do you have a build of this somewhere so I can test the loading speed of a file like this?
     
  28. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I don't have a demo version, sorry.

    --Eric
     
  29. bdominguezvw

    bdominguezvw

    Joined:
    Dec 4, 2013
    Posts:
    96
    Does it work on UWP with IL2CPP with .NET 4.6 scripting backend? Because you claim that it works on all platforms.

    I get the following error (Unity 2017.4.1f1):

    It seems that it doesn't like that the code is precompiled in a dll.

     
    Last edited: Apr 26, 2018
  30. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Did you try using the source instead of the dll?

    --Eric
     
  31. bdominguezvw

    bdominguezvw

    Joined:
    Dec 4, 2013
    Posts:
    96
    Thank you, that was it. I didn't know that you provide source code.
     
  32. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    First of all: Thanks for creating this assets and supporting it this long, it's amazing how fast it can load even bigger files!

    Unfortunately I've come across a problem using mtl files: The meshes are pink.
    I know that that usually means that the texture wasn't found but not only was there no error message but everything's also working fine when I open the .obj file in MeshLab.
    I already tested importing the "Spot" sample (the cow) using the same code and the generated mesh was textured properly, so is there maybe anything in my .mtl files that isn't supported by your ObjReader?

    My .mtl files all look like this:
    Code (CSharp):
    1. # Wavefront material file
    2. newmtl material0
    3. Kd 0.900000 0.900000 0.900000
    4. illum 2
    5. map_Kd object001.jpg
    The code for loading the .obj file:
    Code (CSharp):
    1. GameObject[] oo = ObjReader.use.ConvertFile(path,true);
    All the files are in the same folder and they all use the same name, e.g:
    object001.obj
    object001.jpg
    object001.obj.mtl

    If I load the texture separately (with "File.ReadAllBytes(path)") and add it to the object as a standard material (Shader: "Transparent/Diffuse"), it's there but as soon as I change the shader to "Legacy Shaders/Transparent/VertexLit" (I'm guessing that's the one you're using?), the mesh turns pink again.
     
  33. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It sounds like VertexLit isn't working with your system for some reason. What happens if you use ConvertFile(path, true, material), and supply a material, which doesn't use the VertexLit shader?

    --Eric
     
  34. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    Sorry, I forgot to mention that I'm using Unity 2017.3.1f1.
    With your suggestion the mesh is just white, it won't load the texture if I do:
    Code (CSharp):
    1. Material mat = new Material(Shader.Find("Transparent/Diffuse"));
    2. GameObject[] oo = ObjReader.use.ConvertFile(objpath,true,mat);
    The only way to get a texture that works for me is loading it through "File.ReadAllBytes(imgpath)" and then setting it with "mat.mainTexture" before I use "ObjReader.use.ConvertFile(objpath,false,mat);" - or use your cow sample, not sure why that mtl is working while mine aren't.
    I've already tried a couple of shaders but I'm only using the standard single spotline in the scene, nothing else, so I have to use an unlit shader (that also supports textures and transparency), which doesn't leave much as far as I've seen.
     
  35. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Sounds like it's not loading the mtl file; what does the mtllib line in the .obj file say?

    --Eric
     
  36. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    Code (CSharp):
    1. mtllib ./object001.obj.mtl
    Could the "./" be the problem?

    I also have another question:
    Is it possible to use your asset to read the .obj file but not create the GameObject yet but instead return the mesh data (vertices,...) in arrays and then only later use your asset with these arrays to create the GameObject?

    The reason behind this is that I have 300-400 .obj files that are displayed depending on where the camera's looking at and with about 10 being displayed at the same time, my app is just frozen while it's calling "ObjReader.use.ConvertFile(...) for them because I can't call that method from a second thread because only the main thread has access to the Unity API and can display GameObjects.
    I already opened a thread (click) and that's what was recommended.
     
  37. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Probably, since "./" means "root directory". It would take some re-writing to only return mesh data, but unfortunately I doubt that would help since 99.99% of the time spent is converting text files to mesh data in the first place; actually making GameObjects is trivial once that's done.

    --Eric
     
  38. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    Okay, I removed the "./" but it's still not working.
    The files all have pretty long names, so I shortened everything to "MyObj.xxx" but no luck either.
    Not giving it a material makes it pink.
    With one of the six shaders I've been testing it with the texture's now just white:
    • Legacy Shaders/Transparent/VertexLit
    • Standard
    • Transparent/Diffuse
    • Transparent/Specular
    • Unlit/Transparent
    • Unlit/Texture

    I know, that's why I need it to be separate with the amount of objects I have to load. Once everything's loaded, I can simply enable and disable the GameObjects I need/don't need, which is probably pretty fast anyway. But for the "read file and calculate stuff" part I really need an extra thread that can then pass everything to the main thread, which is actually able to draw the objects and hopefully not freeze the app anymore.
    I already split the "FastObjImporter" from the wiki into 2 parts but I'm still trying to get it to work.
    I already found the cut in your code and I'm going to try and do it there too, so no worries about that for now. ;)

    Edit: I uploaded files you can test it with. The forum won't let me use the actual file extensions, so you have to remove the ".txt" for two of them.
    Don't forget to do this, otherwise the object is just stuck to the "wall":
    Code (CSharp):
    1. myobj.transform.Rotate(new Vector3(270,0,0));
    2. myobj.transform.Rotate(new Vector3(0,0,180));
     

    Attached Files:

    Last edited: May 24, 2018
  39. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    The .obj file doesn't have any "usemtl" line anywhere, which is necessary to tell which groups use which material. It does have a line that says "material0", but that's not valid syntax; it needs to be "usemtl material0".

    --Eric
     
    SimRuJ likes this.
  40. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    Okay, MeshLab isn't an indicator that everything's fine with the files then - sorry. *facepalm*
    Thanks, now it's working of course - even with the "VertexLit" shader you're using.
     
  41. StarCoop

    StarCoop

    Joined:
    Nov 26, 2016
    Posts:
    44
    Hi there,

    I have two things:

    First, the filepaths should start with "file:///" with three "/" (instead of 2). Otherwise there's a non-catched error when loading .OBJs from another partition (e.g. C and D). In the current version the OBJReader checks for two "//". I don't know if that's the same for ftp:// and https://, but at least for file:/// this is crucial!

    Second, I too ran into a memory issue, but on a 64 bit Windows 10 machine. My OBJ is 1 GB and has 4991 objects. After import (each obj gets its own GameObject, however that is -not- the issue), Unity takes 12 GB out of 16 GB RAM. The profiler says, that 10 of these GB are for "Mono". After 1 minute, Unity crashes with a fatal error "System out of memory".
    I changed combining of the objects vs. non-combining, sub-meshes and no sub-meshes. 64 bit indices and no-64 bit-indices. No change.

    I don't see where this comes from. When I delete the GameObjects in the hierarchy, same high memory consumption. When I delete the OBJReader GameObject (with the script on it), also no change.
    What is causing this high memory consumption and how to get rid of?

    Thanks and best regards
     
  42. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    The correct prefix for file:, http:, etc. is //. (See URL information.)
    https:///
    would result in an error, since no web address starts with /. ObjReader isn't going to insist on file:///, since that won't be correct in some cases. If the file name should start with /, you should include that. If I try to use file://blah/whatever when it should be file:///blah/whatever, I get an "error loading" message, so incorrect file names are being caught as far as I can see. However, normally you wouldn't use file:// at all; that would only be used in ConvertFileAsync, but if you're loading from disk, you might as well just use ConvertFile.

    As for the memory issue, I don't see where that's coming from either. At a guess, Mono can't properly handle that much data for some reason. Can you split the obj file into smaller parts?

    --Eric
     
  43. StarCoop

    StarCoop

    Joined:
    Nov 26, 2016
    Posts:
    44
    Hi,

    thanks for the answers.
    I want to use async conversion in order not to block my entire programm completely. Unfortunately, the async is only for the reading of data, not the conversion (feature request!), but still better than blocking everything from the click of a button. Additionally, I just tried using only ConvertFile(), and I get the "OutOfMemoryExeption" for the StringBuilder class. So, apparently a 1 GB OBJ file is too large to read all at once.

    Could you maybe invest some time in the RAM bug? We're using your tool for a customer's software solution, and the massive memory usage is a killer at the moment. We can not split the obj into smaller parts, as it will be for a software solution that can take "any" OBJs.
    I sincerely hope you can help me out. I could double check if my test data is not classified and send it to you (details via PM?) if you would mind helping.

    Edit:
    I didn't quite get what you were saying about the "file:///" topic. So for https:// and stuff, I understand. But for "file:///", this is a common "mistake" to use only "file://:, because for some reason you need the three "/" when you want to access data from a different partition. This has nothing to do with filenames that might start with "/" (is that allowed anywhere?).
    Try reading a file from partition D, while running your tool from partition C, and you will see. The reason someone (me) -needs- to convert async is mentioned above.

    Best regards,
    Emanuel
     
  44. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You're free to use file:/// where appropriate, but ObjReader isn't going to force it, since file:// is correct. See examples in the link I posted. It's common to start file names with /, since that means root. I'd still suggest ConvertFile; you can just wait a frame after clicking before calling it.

    As far as memory, since I need to rely on Unity to handle that, there's not a lot I can do. You can try using the very latest version of Unity with the upgraded Mono enabled, since otherwise it's using a quite old and outdated version.

    --Eric
     
  45. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    Unfortuntely getting the code from the wiki ("FastObjImporter") to work completely failed and changing your code to only return the mesh data in arrays is more complicated than I had anticipated. It's weird that this hasn't come up here before.

    Could you please have a look at it?
     
  46. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It wouldn't solve your problem, though, for reasons already explained.

    --Eric
     
  47. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    Isn't reading the .obj file and doing the calculations what takes up the most time? Sorry if I misunderstood your other post (#638) but that's what I gathered from it:

    So if that heavy work is done in a separate thread, which then gives my main/UI thread the mesh data in arrays, wouldn't that solve my problem since creating the actual GameObjects from that mesh data is easy enough to not freeze everything for seconds at a time?
     
  48. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    The problem with multi-threading is that, according to my support requests, ObjReader seems to be used frequently with WebGL, which doesn't support multi-threading at this time.

    --Eric
     
  49. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    Oh, have there not been any requests for just normal applications for PC (/Android) yet? I don't need it for WebGL:

    In my game the player can fly around. Depending on the direction he's looking different tiles (1 tile = 1 .obj file) are displayed on the "floor" and the closer he gets (only height-wise at the moment) the more detailed these tiles become (= different .obj files with more vertices and higher resolution textures).

    If you only have a couple of models, displaying a loading screen while using your asset probably wouldn't be a problem. In my case there can be hundreds (or even thousands) of .obj files (5kb to 5mb each), so I can't just load all of them into memory (especially not on Android). This is where multithreading would come into play: Load the first 100-200 objects that are located in/around the starting area into memory while displaying a loading screen and then, while the player is actually flying around, load the other models, when needed, in a background thread.

    I already programmed the same thing for Android in Java using a special framework and it's working pretty well there. Unfortunately, with Unity's "no UI access in a different thread" restriction, this model loading is blocking the main thread and currently you get a 5-30 second freeze every time it's loading new objects, which makes the whole thing unplayable.
     
    Last edited: Jul 6, 2018
  50. Deleted User

    Deleted User

    Guest