Hello, I’m having an issue and I’m not sure if its a python problem or a blender API problem that I’m missing.
I have function that accepts an object struct and a string,
function parameters:
def changeAttributeToUV(obj, att_name):
and inside that function I’m doing:
uvmap = obj.data.uv_layers.new(name=att_name)
And I’m using that function like this:
# transform splineUvs to UVMaps
changeAttributeToUV(ob, "UVMap")
changeAttributeToUV(ob, "splineUvs")
When the above runs, there is no new UVMap layer at all, printing the following to the console for the UVMap created MeshUVLoopLayer("NGon Face-Vertex"). But if I do the following code:
It generates the new uv layer just fine, and shows up in the attribute tab in UVmaps. That code can be inside or outside the function (in the operator run method) that it does the same thing if written that way.
So, Am I missing something?
Thank you for the help!
Here is the code and the function that is calling it, it’s not a hard thing, but this interaction seems buggy? That or it’s just my stupidity showing
import bpy
def changeAttributeToUV(obj, att_name):
# Create UVMap
uvmap = obj.data.uv_layers.new(name=att_name)
# UV attribute to store
uv_attrib = None
# Try to find valid face corner attribute
for attribute in obj.data.attributes:
if attribute.name == att_name:
uv_attrib = attribute
break
# Check if face corner attribute was found
if uv_attrib is None:
if context.active_object is obj:
bpy.ops.object.delete()
self.report({'ERROR'}, 'No Face Corner attribute found!')
return {'CANCELLED'}
for loop in obj.data.loops:
uvmap.data[loop.index].uv[0] = uv_attrib.data[loop.index].vector[0]
uvmap.data[loop.index].uv[1] = uv_attrib.data[loop.index].vector[1]
print(uv_attrib)
obj.data.attributes.remove(uv_attrib)
print(uvmap)
def generateRailSelection(context):
selected = []
# get all selected
selected.extend(context.selected_objects)
# deselect all
bpy.ops.object.select_all(action='DESELECT')
# run through selection
for ob in selected:
if (ob.type != 'CURVE'):
continue
# select
ob.select_set(True)
context.view_layer.objects.active = ob
print(ob)
source_name = ob.name
# duplicate selection
bpy.ops.object.convert(target='MESH', keep_original=True)
cloneObj = context.active_object
cloneObj.name = source_name + "GeneratedRail"
# transform splineUvs to UVMaps
changeAttributeToUV(cloneObj, "UVMap")
changeAttributeToUV(cloneObj, "splineUvs")
# seperate mesh by material
# delete extra set that doesnt make sense with section
# join all
cloneObj.select_set(False)
What exactly is the goal, here? As far as I can tell, you are…
Adding a UV Map layer to the mesh
Locating the attribute interpretation of that UV Map layer
…?
Removing the attribute, which also removes the UV Map which is represented by that attribute?
If you comment out the obj.data.attributes.remove(uv_attrib) call, look at what’s printed on my machine on one particular run…
<bpy_struct, Float2Attribute("UVMap") at 0x000002A29E171488>
<bpy_struct, MeshUVLoopLayer("UVMap") at 0x000002A29E171488>
That is: two interpretations of an array of data, and that data is located at the same address in memory. They are different views of the same data, because UV coordinates are Float2 face corner attributes. When you remove the one, you also remove the other, because they are the same thing.
If the attributes have different names, they are different attributes. And if they have compatible data types (Float2, in this case), you can copy their values from one attribute channel to the other.
Where is the “splineUV” attribute coming from, though, which you want to convert to a UV Map? And why do you try to convert the attribute “UVMap” into to a UV Map called “UVMap” first? I don’t understand the code, so I don’t understand your goal.