Search Unity

Thread vs. Unity API (loading meshes from the HDD)

Discussion in 'Scripting' started by SimRuJ, May 18, 2018.

  1. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    I'm porting an Android/Java/VR app to Unity (PC & Android) and I've come across a big problem: Threading and how much the Unity API is in "love" with it...

    What my old app does:
    • Read .obj files from the internal storage at runtime and create meshes
    • Display these objects depending on where you look at, so if you look directly at the floor you'll see other objects than if you look straight ahead
    • There can be up to 400 or 500 object files (with up to 5mb each), so I only read what I need and then store an instance of the mesh to quickly load it again later
    • The whole "read .obj files and generate meshes" part is running in a separate thread

    To do the same thing in Unity I bought the "ObjReader" asset and already set it up to display pre-chosen objects. This loading of the files, of course, takes its time, which means that I can't simply run it on the main thread either and here's where my problem lies:
    As soon as one of these meshes is created, Unity wants to display it and trying this for the maybe 10 meshes than can be loaded/displayed at the same time simply freezes Unity.

    I already read that you're supposed to do whatever wants access to the Unity API on the main thread but I can't split the non-API and API stuff up because, like I said, Unity instantly displays objects instead of giving you something you can load whenever you feel like it.

    I thought about generating all the meshes at the very start and then quickly disabling them ("mygameobject.SetActive(false)") but that would probably take 5-10 minutes (probably even longer on Android) and I wouldn't even be able to show some kind of loading/progress screen because, well, the main thread is blocked while it's creating the meshes.

    How do you do something like this? Is it even possible without blocking the main thread?

    Unity: 2017.3.1f1
     
  2. unitywlp

    unitywlp

    Joined:
    Jan 3, 2014
    Posts:
    146
    you can try to disable the mesh render component or you can generate your mesh some where camera cannot render.
     
  3. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,052
    You could just read and store the mesh data (verts, tris, etc) into arrays and then push that data into a Mesh when needed.
     
    Ryiah likes this.
  4. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    Sorry for the late reply!

    @unitywlp
    The problem is that it'll still try to do that with the second thread, which hasn't got access to the render API. Like I said, I'd need some type of object that Unity only builds but doesn't display instantly - not even for a split second like it would be if I created the GameObject, the set it to disabled.

    @zombiegorilla
    I'm not reading the data myself, the ObjReader asset is, which then returns a GameObject that I'm using.
    Is there maybe any built in function that generates a GameObject but doesn't try to display it and also doesn't access the API because of that?
     
    Last edited: May 23, 2018
  5. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,203
    At a glance the ObjReader asset includes full source code. You just need to modify it to stop processing once it's loaded the necessary data into arrays. From there you can take the data and store it elsewhere until it's needed.
     
  6. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    @Ryiah
    They do but I'm not sure if it's even okay to sell an app that uses modified code of an imported asset.

    I was looking for something already finished and fast and tested two other free assets too before finding ObjReader but one was incredibly slow and didn't even display the texture and the other didn't work at all.

    At what point does the API kick in? When you create an instance of a Mesh? So looking at the link you posted, is "LoadMeshData(...)" fine but everything after calling that method should be done on the main thread? Or does the actually "dangerous" stuff only happen when you assign the created mesh to a GameObject?
     
  7. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,203
    It's completely fine. It's only a problem when you sell the asset itself or try to sell it as part of a package on the Asset Store.

    When you use anything that is part of the UnityEditor or UnityEngine namespaces.
     
  8. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    Good to know, thanks!

    Okay, thanks.
     
  9. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    I've been trying to get the code you linked (@Ryiah ) to work for an hour (on the main thread for now) but I can't get it to display anything (edit: this link).
    My .obj files don't specify any normals, so I'm using "mesh.RecalculateNormals()" instead and I also got rid of "mesh.Optimize()" because it's deprecated.

    With one of the .obj files I've tested, "else if(sb[0] == 'f' && sb[1] == ' ')" is entered 58429 times, which is also the number of faces (according to MeshLab) but my app never enters the "while(j + 2 < info)" loop and because of that also doesn't store any information about triangles, which is probably why the mesh isn't displayed.
    Appr. half of the .obj file consists of rows starting with an "f", e.g. the first one is "f 5/5 4/4 1/1".

    Does anyone know how to fix this?

    Edit:
    If I change the "j=1;" right before the loop to "j=0;" (no idea if that was simply a typo or actually intended), it actually starts collecting triangle data but even with that, my object isn't displayed in the scene. I also tried it with an .obj that's included in the ObjReader asset but got the same result with it.
    I'm doing the exact same things with the mesh I'm also doing with meshes of other GameObjects (e.g. planes that I create at runtime too) that get displayed just fine.
     
    Last edited: May 30, 2018