0
\$\begingroup\$

A bit of context: I'm developing a 3D rendering engine and can't really make much more progress until I get some more interesting and complex meshes loaded in to the scene. So far I have been using built-in simple meshes like cubes and planes. I have written a Mesh class to take a MeshData struct which contains Position, Normal, Tangent, Bitangent, Colour, Texture Coordinate, and optional Face data. The Mesh class takes this data and depending on a few things it will generate a VBO with all of the available data interleaved, an EBO, and a VAO which has both the VBO and EBO (if one exists) bound to it. I've been pretty happy with this so far and it works fine with a simple .OBJ which contains a relatively straight-forward mesh.

Currently I have an asset management system which allows me to load in assets like this:

Mesh * teapot = AssetManager::loadGlobalAsset<Mesh>("res/meshes/teapot.obj");

If the returned pointer == nullptr then the assets doesn't exist. If it isn't nullptr then one of three things just happened: (1) the asset was just newly created and successfully loaded in to the asset manager's pool of assets, (2) the asset was found to already exist in the pool of assets and its pointer returned, (3) the asset was found to already exist in the pool of assets, but was unloaded, so it was loaded and its pointer returned.

As I said this works great for simple meshes but I'm a bit stuck on what to do and what changes I now need to make to load meshes which have multiple sub-meshes which might have individual materials.

For example the Sponza mesh has many sub-meshes which make use of a set of materials.

I could just load the mesh right in to my scene and have the mesh spread across multiple scene nodes all with a common ancestor node, but then this would defeat the purpose of an asset manager and I would have to worry about cleaning up and unloading the mesh outside of the asset manager. I could also just load the mesh as one big combined mesh, but of course then I can't assign individual materials to the sub-meshes without a lot of trouble.

I currently can't load the mesh using my asset manager as assets are identified by the hash of their filepaths, and here we have a situation where many individual meshes technically have the same filepath. If I just create new assets and give them to the asset manager with an ID to later fetch the asset (which isn't necessarily a bad idea for built in assets (I think)), then I feel I have the following issues:

  • Easy to add multiple assets with same ID
  • Breaks the connection between the meshes contained in a single mesh file
  • No way of actually knowing the ID of a mesh which was loaded in via a mesh file
  • Would have to manually recreate the whole mesh from its loaded sub meshes if I wanted to simply display the mesh as-is.

There is also the issue of where to store the materials that are included in the material library that a mesh file might reference. Do I create new material assets from this library, add them to the manager, and then have the mesh somehow reference these materials? But then how would I reference these materials manually? It's a similar issue to last point from the above list. Also, meshes don't currently have any knowledge of its material, that's the scene node's job.

Thanks for any thoughts or comments on this issue. I'd be very interested to hear what you guys think.

\$\endgroup\$
2
  • \$\begingroup\$ When you say "sub-meshes" do you mean something like a hierarchy? Or like an obj file that can contain multiple objects? \$\endgroup\$ Commented Mar 1, 2019 at 15:00
  • \$\begingroup\$ Mainly referring to how OBJ files (and perhaps others?) contain multiple meshes. If Every mesh file contained exactly a single mesh, then I don't thing I would have a problem. \$\endgroup\$
    – georgeous
    Commented Mar 1, 2019 at 15:07

1 Answer 1

1
\$\begingroup\$

One common way to handle this is to introduce a new category of asset that we might call a "prefab."

A prefab is a self-contained branch of a scene graph, with its own root node, and optionally additional child nodes.

When you instantiate a prefab inside your scene, you spawn a copy of the prefab's root node as a child of the scene root or an existing scene node, and recursively spawn copies of each of its children as children of this new prefab instance.

Now, when you're importing a model file that may contain multiple meshes, count the meshes. If there's exactly one mesh, you can import it as a mesh asset using your existing logic.

If there's more than one mesh, import it as a prefab asset. Give it an empty root node, then create a mesh node as a child of the prefab root for each mesh in the source file.

This lets you preserve the internal structure and spatial/hierarchy relationships between the various meshes (or other node types) in the file. The root level asset can still refer back to the file it was imported from, so any functions that need to access the file from which an asset was loaded just need to remember to navigate to the root node of the asset first (which is just a no-op on plain mesh assets that are their own root).

For placing the meshes in your scene, you'll typically want to place the whole coordinated prefab block as a single piece, so this should still be compatible with your strategy of using a hash of the file path to look up / load the asset. The root node of the prefab still has a unique path and thus (barring collisions) a unique hash to associate with it.

If you ever need a specific mesh from within the prefab, you'll need a second layer of addressing to select sub-assets. You could for instance assign them a sub-asset ID within the prefab at import time, based on their IDs or order inside the source file.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks DMG, this is a genuinely helpful answer. I don't think my problem is straight forward enough to be solved in a single written answer but I think this will help in starting me on the path to a solution. Model asset management sucks! \$\endgroup\$
    – georgeous
    Commented Mar 2, 2019 at 1:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .