UuuNyaa / blender_mmd_tools

MMD Tools is a blender addon for importing/exporting Models and Motions of MikuMikuDance.
GNU General Public License v3.0
1.94k stars 92 forks source link

Sequence of materials #74

Closed AliceSynthesisThirty closed 1 year ago

AliceSynthesisThirty commented 1 year ago

Why does the sequence of materials of my model get disrupted after I export the mmd model? I am exporting a model with a wrong material sequence after using a separate material.

This makes the model not display correct in the MMD. I had to return to a version of the plugin below 2.40 to ensure that my model was correct. Hundreds of materials that I now have to fix one by one in sequence.

I am shocked that several versions of your plugin have not fixed this problem.

Please fix it~~~~ Plugin Versions:2.50+

nagadomi commented 1 year ago

@UuuNyaa Caused by e52086cb04e731bd17465c254f9b99ef88f0932e Model.materials() should keep the order of self.meshes().

UuuNyaa commented 1 year ago

@AliceSynthesisThirty Thanks for the report 😃

@nagadomi Thanks for investigating the cause. Using dict instead of set would seem to solve the problem. https://stackoverflow.com/questions/1653970/does-python-have-an-ordered-set

nagadomi commented 1 year ago

@UuuNyaa Without LibraryOverrides, list(map(lambda x: x.material, obj.material_slots)) == list(obj.data.materials) is always True. (I tried changing order, adding empty material slots) So when an empty material slot is added, mesh.data.materials will also contain None.

UuuNyaa commented 1 year ago

@nagadomi Thank you for your effort 😃

Presumably the following code will solve the problem.

         materials = {} # Use dict instead of set to guarantee preserve order
         for mesh in self.meshes():
-            materials.update((slot.material,0) for slot in mesh.material_slots if slot.material is not None)
-            materials.update((material,0) for material in mesh.data.materials)
+            materials.update((material,0) for material in mesh.data.materials if material is not None)
         return list(materials.keys())

However, I am not familiar with the behavior of LibraryOverrides. Maybe @One-sixth knows something about it.

nagadomi commented 1 year ago

Maybe only obj.material_slots can be overridden with LibraryOverrides. (But this feature is under construction, I think) So I think it is more flexible to use obj.material_slots instead of obj.data.materials. However, I do not fully understand the difference.

UuuNyaa commented 1 year ago

I think it is more flexible to use obj.material_slots instead of obj.data.materials. However, I do not fully understand the difference.

Perhaps there are LibraryOverridden meshes. So I would adopt the following code.

         materials = {} # Use dict instead of set to guarantee preserve order
         for mesh in self.meshes():
             materials.update((slot.material,0) for slot in mesh.material_slots if slot.material is not None)
-            materials.update((material,0) for material in mesh.data.materials)
+            materials.update((material,0) for material in mesh.data.materials if material is not None)
         return list(materials.keys())
One-sixth commented 1 year ago

@UuuNyaa In my opinion. When exporting pmx models (or most of the time), maybe we only need to export (or return) the materials of the material_slot.

Between obj_material and data_material, I think they are alternative relations.


And the number of obj_material_slots is always equal to the length of the data_materials.


Currently, obj_materials are used in library overrides, and only replacement functions are available. Add and remove the material slots are not supported. The data_materials also cannot be add, remove or modified (it seems that the library_overwrite can be modified, but the modifications will be drop when save).


I have a new ideas, but it is not complete yet.

When build the material morph.

Locate the material_slot index by the data_materials, and then check the corresponding link setting of material_slot. If the corresponding material_slot is set to 'Object', the material_slot.material will be used.

This change does not modify material_morph_data. It only affects the build_morph. The same method can use when export the material morph of the PMX model.

I think this idea will make obj_material more easier to use.

AliceSynthesisThirty commented 1 year ago

And more question:Is it possible to make the sequence of the model's morphs undisturbed when exporting?

UuuNyaa commented 1 year ago

@AliceSynthesisThirty I created another issue #77 Could you explain what the problem is?

UuuNyaa commented 1 year ago

@One-sixth Thank you for your comment 😃 I will release it for now, referring only to material_slots.

         materials = {} # Use dict instead of set to guarantee preserve order
         for mesh in self.meshes():
             materials.update((slot.material,0) for slot in mesh.material_slots if slot.material is not None)
-            materials.update((material,0) for material in mesh.data.materials)
         return list(materials.keys())

Let us continue to discuss your new idea.

AliceSynthesisThirty commented 1 year ago

@AliceSynthesisThirty I created another issue #77 Could you explain what the problem is?

The expression of the model. Smile, cry, angry, bone morph, material morph.…etc If you open the model with the PmxEditor,you can find morph also has a sequence as does material.

Although this question is not important. It would be excellent if you could fix this problem~~

UuuNyaa commented 1 year ago

It was released as v2.8.0 🎉 Thanks everyone for your cooperation.

One-sixth commented 1 year ago

@One-sixth Thank you for your comment 😃 I will release it for now, referring only to material_slots.

         materials = {} # Use dict instead of set to guarantee preserve order
         for mesh in self.meshes():
             materials.update((slot.material,0) for slot in mesh.material_slots if slot.material is not None)
-            materials.update((material,0) for material in mesh.data.materials)
         return list(materials.keys())

Let us continue to discuss your new idea.

This is an idea about blender's MMD advanced material library. It also combines some of my experience in using library_override materials.

I will open a new issue to discuss with you in the next few days when this idea are more complete.