Well. For me it’s not so much ‘remembering’. More ‘discovering’
But I indeed found out that when you create a BMesh from a Mesh all associated CustomData/attributes is copied as well. It’s probably done that way for a good reason, but still it seems slow?
Anyway just to clarify my mental image:
If you have a float attribute on vertex corners, in a Mesh that is stored as a contiguous array of floats, in the same order as the MLoops in the mesh.
In BM_mesh_bm_from_me( ) I can see that not all customdata layers are converted, but a mask is used to determine which layers to add/skip. The default mask is CD_MASK_BMESH , but extra layers can be passed in via params.
However, I don’t get how to make it pass a specific general purpose attribute layer. I think the fact that CD_PROP_ALL is added to CD_MASK_BMESH means none of the attribute layers are copied to the BMesh? But the masking works on types of layers, not specific indices…
I’ll go on trying to figure it out, but if someone could steer me in the right direction…
Hm. I don’t really understand. I go into the uv editor with a breakpoint on BM_mesh_bm_from_me( ), and the result is a BMesh with only a single CustomData layer (just the UVs) and not other stuff. Even though I created an attribute layer as well.
Oh well, I’ll step through it again, to see why I end up with only that layer…
edit: found it. I was looking at ldata instead of vdata, while I cretaed my test-attribute on vertices.
There’s CustomData_get_named_layer_index(…) to get the index of the layer (in all layers)
There’s CustomData_get_n_offset(…) to get the offset. Which uses an offset relative to the first layer of that type
I could also use data->layers[index].offset direcly , but I guess that’s a bad idea? Or should I just do it that way? I’d expect there to be a CustomData_get_index_offset(…) as well…
Edit: Or a CustomData_get_named_offset(…) for that matter.
While CustomData_get_named_offset is nice to have, I think we’d need a CustomData_get_index_offset as well (or CustomData_get_offset_index, depending on the naming of the existing functions).
It turns out that this function if quite often going to be called inside a loop where the name stays the same for each call. Seems a pity to waste time looking up the name for each iteration…
After a marathon renaming and searching/replacing (and some sed trickery) session I now have a prototype version where the MLOOPUV_VERTSEL flag is stored in a generic attribute.
There’s all sorts of stuff wrong with it yet:
the python api accesses the old flag
you have to create the attribute manually before switching to the uv-editor (otherwise->crash)
the name of the attribute is hardcoded to be “UV-vertsel”. Creating multiple uv maps just isn’t handled yet.
But it does work.
My plan now is first to do the same for the other flag. And then maybe do some benchmarking?
The python api accesses the flag values from an MLoopUV pointer, without further context (as far as I can see). So in the getter/setter (in bmesh_py_types_meshdata.c) functions we need to find a way to lookup the original UV layer metadata (name, first element) to be able to get at the correct attribute layers.
I don’t really understand how all the python interfacing works (yet). Maybe we could store some extra metadata in the BPy_BMLoopUV struct?
edit: The same problem (and performancewise probably a bit harder to solve?) exists in
layerInterp_mloopuv() which is used to interpolate the UV layer in the CustomData layer handling. ( customdata.cc ) though this case maybe solves itself by just not interpolating the flag values here and relying on the fact that the independent bool attributes will get interpolated?
2022-02-09T23:00:00Z
edit ( wanted this to be a separate post for clarity, but apparently I’m not allowed to post more than 3 times in a row without someone else replying in between ):
Just a quick update of a problem I don’t yet know how to solve…
In blenkernel/customdata.cc there is a table describing various layertypes.
That table contains callbacks to interpolate various layers.
The callbacks are defined to take raw pointers to the data elements of the layers.
That means that the interpolate function for UV data gets an array of raw MLoopUV pointers.
This means that in the interpolation function I don’t have a way to get back to the layer data, so I don’t have a way to find the associated attribute layers.
The only way I can think of to solve this is to change the LayerTypeInfo callbackfunctions to take CustomDataLayer * instead of a void * directly to the data elements, and then rewrite all the callbacks to use those.
and another edit: I thought that maybe we could just rely on the boolean layers getting interpolated independently. This would work in the UV case, but it would fail if we’d ever want to split up some struct into multiple attributes and the interpolation needs several members of the struct.
I think it’s fine, good even, to rely on separate interpolation for boolean attributes.
In this case I don’t even think the boolean interpolation is critical, just nice to have, since the data is mostly for editing, i.e. only visibly changed when applying modifiers, in which case we wouldn’t usually expect that sort of thing to be interpolated.
That sounds quite reasonable to me. Though I don’t have any experience with BMesh Python API code.