Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

li-plus
Copy link
Contributor

@li-plus li-plus commented Dec 23, 2021

Hi, thanks for this awesome tool to load obj files. I am using tinyobjloader for my tiny renderer, but I have met some problems on the "Living Room" scene from McGuire Computer Graphics Archive. Its obj file defines the same mtllib 181 times, and tinyobjloader will reload the file the same number of times! This mtllib file has 42 newmtl statements, so finally reader.GetMaterials() returns 7602 materials, causing my renderer OOM since it needs to load all texture maps of all materials.

This PR attempts to solve this issue by loading one mtl file only once. I record the filenames following "mtllib" in an std::set<std::string> so that the previously loaded mtl files will be skipped to avoid reloading. It should cover most scenarios in obj files. Limitations are that there might be different representations for the same file, e.g., ./mtl/scene.mtl and ./mtl/../mtl/scene.mtl, but it is rare in obj files.

@li-plus li-plus changed the title Fix mtllib reloading: load an mtl file only once WIP: Fix mtllib reloading: load an mtl file only once Dec 24, 2021
@syoyo
Copy link
Collaborator

syoyo commented Dec 24, 2021

@li-plus Awesome!

Its obj file defines the same mtllib 181 times, and tinyobjloader will reload the file the same number of times! This mtllib file has 42 newmtl statements, so finally reader.GetMaterials() returns 7602 materials

I see. Let us give some time to figure out the solution. It may require adding extra data structure and may break current API design to support multiple newmtl statements

@li-plus
Copy link
Contributor Author

li-plus commented Dec 25, 2021

Thanks for your attention! Just to be clear, multiple newmtl has no problem. What really matters is multiple mtllib statements. The obj file of "Living Room" scene is like:

mtllib living_room.mtl
usemtl MiddleLight
g Default
f 1/1/1 2/2/2 3/3/3 4/4/4
usemtl LeftLight
f 8/2/5 7/1/6 6/5/7 5/6/8
usemtl RightLight
f 11/7/9 12/8/10 10/4/11 9/3/11
......
mtllib living_room.mtl
usemtl Books
g Default
f 2106/2263/1506 2108/2264/1506 2107/2265/1506
......
mtllib living_room.mtl
usemtl DullSteel
g Default
f 2154/2291/1516 2156/2292/1516 2155/2293/1516
......

I have finally worked out a solution: memorize all the material_maps in an std::map indexed by mtllib filenames. Every time before I need to load an mtllib, I will check if it is already loaded. If already loaded, the material_map stored in memory will be returned. It works perfectly for me. You may review and merge this PR, or you might have your own implementation though.

@li-plus li-plus changed the title WIP: Fix mtllib reloading: load an mtl file only once Fix mtllib reloading: load an mtl file only once Dec 25, 2021
@li-plus
Copy link
Contributor Author

li-plus commented Dec 25, 2021

I just figured out a simpler way. When multiple mtllib statements are defined, only load the first one, and send warnings on the rest.

@syoyo
Copy link
Collaborator

syoyo commented Dec 25, 2021

@li-plus

When multiple mtllib statements are defined, only load the first one, and send warnings on the rest.

Awesome! Let us give some time to review the PR

@syoyo
Copy link
Collaborator

syoyo commented Dec 25, 2021

@li-plus After reading the .obj spec

https://en.wikipedia.org/wiki/Wavefront_.obj_file
http://paulbourke.net/dataformats/obj/

The spec says

mtllib filename1 filename2 . . .

    Polygonal and free-form geometry statement.

    Specifies the material library file for the material definitions
    set with the usemtl statement. You can specify multiple filenames
    with mtllib. If multiple filenames are specified, the first file
    listed is searched first for the material definition, the second
    file is searched next, and so on.

    When you assign a material library using the Model program, only
    one map library per .obj file is allowed. You can assign multiple
    libraries using a text editor.

one map library is a typo(this should be corrected as one material library). the Model program refers the modeling program(i.e., Wavefront 3D program)

So the spec itself allows multiple definition of mtllib in .obj. Thus,

If already loaded, the material_map stored in memory will be returned

You need to revert PR to the version of this: Cache mtllib command.

@li-plus
Copy link
Contributor Author

li-plus commented Dec 26, 2021

@syoyo You are correct. I reverted this PR to cache mtllib filenames, which supports multiple mtllib files in multiple statements. The behavior does not change except for no reloading the same file.

@syoyo syoyo merged commit 8322e00 into tinyobjloader:master Dec 27, 2021
@syoyo
Copy link
Collaborator

syoyo commented Dec 27, 2021

@li-plus Thanks! Merged!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants