DumpMesh: clean, complete, sexy

The previous bugfix release of DumpMesh was already able to dump quite a number attributes and attribute layers but in the latest version I went the whole way and dumped every attribute layer that happens to be defined. And I really mean every layer: if you have added a skin modifier the BMSkinVert layer will be dumped for example and even if you assign values to the generic float, string, etc. attribute layers programmatically the will be dumped as well.

Note that vertex groups will not be dumped: vertex groups are not part of a mesh but of an object. (yes, if you didn't know that already, you can have more than one object pointing to the same mesh data, each with its own vertex groups)

This is done by code that is a lot more Pythonic (whatever that means, for me pragmatism is more important than style, as long as it is readable and documented). It uses a lot of introspection to keep the code short and sweet as well. Of course it helps that Blender attribute layers (aka CustomData) is very flexible and well designed (well,... mostly, see Bugs below)

Functionally the add-on hasn't changed much: the interface is cleaner (no more separate selection of what will be dumped, you either choose just geometry or everything), and now all objects that are selected are dumped. This might give a slightly faster workflow.


The updated code for DumpMesh and CreateMesh can be found on my GitHub repository. DumpMesh can be downloaded directly from this link, as can CreateMesh if your are interested to look at the code.


Blenders Python API is generally well designed and adequately documented but there are still some bugs and strange design issues:
not documented at all but it is used by the skin modifier. And the bm.verts.layers.skin layer the skin modifier creates has a name that is an empty string
has a documentation entry but is marked as todo. Fair enough, because this might be for Ptex stuff that is sort of shelved for now. In the add-on it is mostly ignored.
If you add vertices, edges or faces to a bmesh you must ensure that the sequences they are members of can be indexed. You can do this with bm.verts.ensure_lookup_table() or equivalent. If you not only need to be able to do bm.verts[i] but need the actual index as well, like bm.verts[i].index you need to call bm.verts.index_update() otherwise all indices are -1. So far so good, however for loops this appears to be either unfinished or I don't understand it: there is no ensure_lookup_table() for loops, apparently this is taken care of by the faces, but any index attribute of a BMLoop is -1. now bm.faces[i].loops does have an index_update() but it will generate only indices for the loops of that particular face and will start at 0. However when transfering a bmesh to a regular mesh the indices of all loops in the whole mesh are properly initialized, so there is apparently hidden functionality to take care of this. Of course most of the time you can do without but in the addon I dump loop layers as dictionaries of dictionaries that can be indexed as d[faceindex][loopindex] where loopindex is initialy derived from the complete mesh and therefore numbered as one unbroken sequence of all the loops.
factories instead of instantiation from a class
BMesh, BMVert, BMSinVert, etc. are not fully fledged classes. You cannot subclass them and you cannot instantiate them with BMesh(). also most have no __repr__() function and also cannot be pickled. This means that especially for layer attributes like BMSkinVert with more than one attribute you have to know what to assign to which attribute, which is cumbersome. introspection is no help here because you cannot know which attribute is to be saved and which one is just for temporary use.
These aren't deal breakers, just things to keep in mind when you are designing an add-on.

No comments:

Post a Comment