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

Skip to content

MTL with multiple materials may use incorrect Kd value #391

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
SeanCurtis-TRI opened this issue Jan 27, 2025 · 4 comments · Fixed by #392
Closed

MTL with multiple materials may use incorrect Kd value #391

SeanCurtis-TRI opened this issue Jan 27, 2025 · 4 comments · Fixed by #392
Labels

Comments

@SeanCurtis-TRI
Copy link
Contributor

SeanCurtis-TRI commented Jan 27, 2025

The issue

tl;dr not all per-material state is being reset each time.

Specifically, by rule, if a material specifies map_Kd but doesn't specify kd, it should use a default white. However, if a previous material in the file has specified a kd value, than the subsequent material that only specifies the map picks a black color. This is because the diffuse color gets reset, but the parser's understanding of whether the material has defined the diffuse color is not reset. Therefore, it mistakenly believes the last material has defined the diffuse color and the default-initialized black is used instead of what should be white.

To Reproduce
Obj:

  mtllib mem.mtl
  v 0 0 0
  v 1 0 0
  v 0 1 0
  vn 0 0 1
  usemtl has_map
  f 1//1 2//1 3//1
  usemtl has_kd
  f 1//1 2//1 3//1

Material library bad_diffuse.mtl

  newmtl has_kd
  Kd 1 0 0
  newmtl has_map
  map_Kd test.png

(Use arbitrary file for test.png -- it must exist.)

The material associated with has_map will have an all-black diffuse.

-- EDITED block --

I realized the initial problem statement was incomplete, so I've added the following:

On the other hand, if the declaration of the two materials is reversed, so that the has_map material comes first, then the resulting material will have a white-ish diffuse color.

So, the defect has two symptoms:

  1. Parsed materials change based on declaration order.
  2. Materials which use map_Kd but not kd may end up black because the diffuse color defaults to black.

-- End of EDITED block --

Expected behavior
The material should have the default diffuse color (0.6, 0.6, 0.6).

Environment

  • TinyObjLoader version: sha fe9e713
  • OS: linux
  • Compiler: gcc 11.4.0
  • Other environment n/a
@syoyo
Copy link
Collaborator

syoyo commented Jan 28, 2025

You should first investigate MTL spec

https://paulbourke.net/dataformats/mtl/

for the expected behavior.

If there is no info in the spec, then you should investigate how other obj importers(at least meshlab and Blender) interprets it.

@SeanCurtis-TRI
Copy link
Contributor Author

SeanCurtis-TRI commented Jan 28, 2025

I'd point you to the code itself.

https://github.com/tinyobjloader/tinyobjloader/blob/release/tiny_obj_loader.h#L2082-L2084

The has_kd variable is documented, specifically, for the purpose:

"has_kd is used to set a default diffuse value when map_Kd is present and Kd is not."

There are two other local variables has_d and has_tr that serve a similar role. has_d and has_tr get reset whenever a newmtl is encountered but has_kd is not.

In this case, regardless of what the spec is, the implementation of this library does not do what it intends to. For example, if you reverse the order of the material declarations, the has_map texture does get a white-ish diffuse color. Surely, no spec in the world would change the materials based on the order they're parsed.

@syoyo syoyo added the bug label Jan 28, 2025
@syoyo
Copy link
Collaborator

syoyo commented Jan 28, 2025

Thank you for the updated description.

So the issue itself is simply has_kd flag is not reset per newmtl, and proposed PR resets had_kd per newmtl call. PR will be merged soon after the review.

Background & expected behavior of Kd value

Just for the record, has_kd flag is added by this PR #249 to assign the default grayish value(this is not defined in obj's MTL spec) when Kd is not provided, but map_Kd is provided.

The logic of Kd value in tinyobj is:

mtl.Kd = black
mtl.map_Kd = none

if input.map_Kd:
  if not input.Kd:
    mtl.Kd = 0.6  # tinyobj & Blender specific 
  else:
    mtl.Kd = input.Kd

  mtl.map_Kd = input.map_Kd

@SeanCurtis-TRI
Copy link
Contributor Author

Thanks! I realized by your question that my original problem statement was incomplete. So, it all looks like it'll be squared away nicely.

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

Successfully merging a pull request may close this issue.

2 participants