Grim-es / material-combiner-addon

Blender addon for material combining, uv bounds fixing
MIT License
451 stars 36 forks source link

Remove pillow dependency and find material images by traversing node tree #51

Closed Mysteryem closed 1 year ago

Mysteryem commented 1 year ago

This is a big PR focussed mainly on removing the dependency on Pillow and rewriting how images are found from materials. A few fixes and other implementation changes are also included.

I've squashed as many commits as I could that were simply fixing bugs in my own code and wouldn't result in messy history rewrites, roughly halving the number of commits compared to my development branch.

There's a lot of changes here and the ctypes code in particular took me plenty of time to learn, if you've got any questions, please ask.

Removing the Pillow dependency

The Pillow dependency can cause headaches for some users, particularly Mac or Windows Store users who have troubles installing it. Additionally, its limitation of having to read images from disk has caused issues with .blend files that contain packed images, such as .vrm imports by default. Fairly recent changes to Cats' development branch can also result in all mmd base textures being replaced with new images that are not backed by a file when doing Cats' Fix Model.

The main work with removing the Pillow dependency was not having it be really slow on Blender 2.82 and older, because the fast access methods for image pixels were only added in 2.83. The naïve solutions of iterating through every pixel run 10s of times slower than the fast methods added in 2.83.

Generally I find that this new implementation runs about a second or two faster than the implementation with Pillow (even on Blender versions older than 2.83), though the difference will depend on the number and size of the images, as well as any images that have to be tiled to account for uvs that go outside of the [0,1] bounds and any images that need to be resized. Additionally, Blender doesn't load images from disk until it needs them, so the times can change depending on how many of the images have already been loaded from disk.

I have rewritten how images are found from Materials. In this new implementation, Material Combiner will find the active Material Output nodes of each Material in 2.80+ that uses nodes and traverse the node tree backwards from those Material Output nodes, attempting to find supported nodes by following the links between nodes.

For Blender 2.79, the implementation is effectively unchanged.

Mysteryem commented 1 year ago

I should add, that I've only been able to test on Windows. There is a possibility of some of the ctypes code not working on other operating systems, though I would hope that the vast majority of people are using Blender 2.83 or newer anyway where that code isn't used.

Kosyne commented 1 year ago

Does this fix or lay the framework for fixing #15 by any chance?

Mysteryem commented 1 year ago

Does this fix or lay the framework for fixing #15 by any chance?

It's only laid a framework. Currently when it finds a Principled BSDF node, for example, it will only attempt to find an image/color from the Base Color input.

The extension I have in mind is to additionally attempt to find an image/color for each of the other inputs (or only specific, hardcoded inputs to start with for simplicity) and then let the user pick which of the found extra inputs they want to include as additional output atlases.


I already built in support for exporting atlases with a Linear colorspace instead of sRGB. It's currently hardcoded to always be sRGB, so this would need to be selectable per atlas output.

Some extra code would be needed to allow for traversing the Normal Map node and something would probably need to be done to support the Invert node in cases of smoothness textures being used since Blender tends to use roughness.

There are extra complications when you consider that different materials could be using different shaders/group nodes with differently named inputs. Some inputs with different names might be the same sort of texture and there could even be cases where inputs with the same names are actually different textures. It would probably require users to assign the inputs themselves or for the code to be hardcoded to only handle specific shader nodes and group nodes with known inputs. Uniqueness of input types is fairly easy since you can do something like <node type>_<input name> or GROUP_<group name>_<input name> for group nodes.

Some image size options would probably be useful too, to allow users to pick between the size of the Base Color image or the maximum of all found images for that material, in cases where different inputs have differently sized images or if there's only a color for the Base Color input, but full textures for other inputs.

Additionally, a default color would need to be able to be set by the user for when one material has certain inputs but another material doesn't.

Mysteryem commented 1 year ago

I've pushed a couple of additional commits. The first is a just small fix for objects with empty material slots.

The second commit replaces the use of a hardcoded node name MaterialCombinerOverride for use as overriding the start of node traversal with a StringProperty attached to the Material that contains the override node name. This way, if any other addon requires specifically named nodes for its functions, Material Combiner won't conflict with its functions.

As the override is now a custom StringProperty, it needs some UI to be able to set/clear it. I have added a "Search Start Override" panel to the Shader Editor with this function, with additional buttons for selecting and refocusing the view on the override node. image

In addition to the UI for the override, there is a second panel that shows the material sources that are found from the current material. The magnifying glass button functions the same as the View button for the override node, focusing the view on the node in question. image

When editing a Group node, all the buttons except the Clear override are disabled.

If a material isn't using nodes, the Material Sources panel will show the Material name instead of a Node and the diffuse_color property that is used in such cases. The Search Start Override panel will contain a message and button to use nodes image

As shader nodes are not used by Material Combiner in Blender 2.79, neither of these panels, nor the operators they use get registered there.